aclparse.c revision 1.1.1.4
1/* $NetBSD: aclparse.c,v 1.1.1.4 2014/05/28 09:58:45 tron Exp $ */ 2 3/* aclparse.c - routines to parse and check acl's */ 4/* $OpenLDAP$ */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2014 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18/* Portions Copyright (c) 1995 Regents of the University of Michigan. 19 * All rights reserved. 20 * 21 * Redistribution and use in source and binary forms are permitted 22 * provided that this notice is preserved and that due credit is given 23 * to the University of Michigan at Ann Arbor. The name of the University 24 * may not be used to endorse or promote products derived from this 25 * software without specific prior written permission. This software 26 * is provided ``as is'' without express or implied warranty. 27 */ 28 29#include "portable.h" 30 31#include <stdio.h> 32 33#include <ac/ctype.h> 34#include <ac/regex.h> 35#include <ac/socket.h> 36#include <ac/string.h> 37#include <ac/unistd.h> 38 39#include "slap.h" 40#include "lber_pvt.h" 41#include "lutil.h" 42 43static const char style_base[] = "base"; 44const char *style_strings[] = { 45 "regex", 46 "expand", 47 "exact", 48 "one", 49 "subtree", 50 "children", 51 "level", 52 "attrof", 53 "anonymous", 54 "users", 55 "self", 56 "ip", 57 "ipv6", 58 "path", 59 NULL 60}; 61 62#define ACLBUF_CHUNKSIZE 8192 63static struct berval aclbuf; 64 65static void split(char *line, int splitchar, char **left, char **right); 66static void access_append(Access **l, Access *a); 67static void access_free( Access *a ); 68static int acl_usage(void); 69 70static void acl_regex_normalized_dn(const char *src, struct berval *pat); 71 72#ifdef LDAP_DEBUG 73static void print_acl(Backend *be, AccessControl *a); 74#endif 75 76static int check_scope( BackendDB *be, AccessControl *a ); 77 78#ifdef SLAP_DYNACL 79static int 80slap_dynacl_config( 81 const char *fname, 82 int lineno, 83 Access *b, 84 const char *name, 85 const char *opts, 86 slap_style_t sty, 87 const char *right ) 88{ 89 slap_dynacl_t *da, *tmp; 90 int rc = 0; 91 92 for ( da = b->a_dynacl; da; da = da->da_next ) { 93 if ( strcasecmp( da->da_name, name ) == 0 ) { 94 Debug( LDAP_DEBUG_ANY, 95 "%s: line %d: dynacl \"%s\" already specified.\n", 96 fname, lineno, name ); 97 return acl_usage(); 98 } 99 } 100 101 da = slap_dynacl_get( name ); 102 if ( da == NULL ) { 103 return -1; 104 } 105 106 tmp = ch_malloc( sizeof( slap_dynacl_t ) ); 107 *tmp = *da; 108 109 if ( tmp->da_parse ) { 110 rc = ( *tmp->da_parse )( fname, lineno, opts, sty, right, &tmp->da_private ); 111 if ( rc ) { 112 ch_free( tmp ); 113 return rc; 114 } 115 } 116 117 tmp->da_next = b->a_dynacl; 118 b->a_dynacl = tmp; 119 120 return 0; 121} 122#endif /* SLAP_DYNACL */ 123 124static void 125regtest(const char *fname, int lineno, char *pat) { 126 int e; 127 regex_t re; 128 129 char buf[ SLAP_TEXT_BUFLEN ]; 130 unsigned size; 131 132 char *sp; 133 char *dp; 134 int flag; 135 136 sp = pat; 137 dp = buf; 138 size = 0; 139 buf[0] = '\0'; 140 141 for (size = 0, flag = 0; (size < sizeof(buf)) && *sp; sp++) { 142 if (flag) { 143 if (*sp == '$'|| (*sp >= '0' && *sp <= '9')) { 144 *dp++ = *sp; 145 size++; 146 } 147 flag = 0; 148 149 } else { 150 if (*sp == '$') { 151 flag = 1; 152 } else { 153 *dp++ = *sp; 154 size++; 155 } 156 } 157 } 158 159 *dp = '\0'; 160 if ( size >= (sizeof(buf) - 1) ) { 161 Debug( LDAP_DEBUG_ANY, 162 "%s: line %d: regular expression \"%s\" too large\n", 163 fname, lineno, pat ); 164 (void)acl_usage(); 165 exit( EXIT_FAILURE ); 166 } 167 168 if ((e = regcomp(&re, buf, REG_EXTENDED|REG_ICASE))) { 169 char error[ SLAP_TEXT_BUFLEN ]; 170 171 regerror(e, &re, error, sizeof(error)); 172 173 snprintf( buf, sizeof( buf ), 174 "regular expression \"%s\" bad because of %s", 175 pat, error ); 176 Debug( LDAP_DEBUG_ANY, 177 "%s: line %d: %s\n", 178 fname, lineno, buf ); 179 acl_usage(); 180 exit( EXIT_FAILURE ); 181 } 182 regfree(&re); 183} 184 185/* 186 * Experimental 187 * 188 * Check if the pattern of an ACL, if any, matches the scope 189 * of the backend it is defined within. 190 */ 191#define ACL_SCOPE_UNKNOWN (-2) 192#define ACL_SCOPE_ERR (-1) 193#define ACL_SCOPE_OK (0) 194#define ACL_SCOPE_PARTIAL (1) 195#define ACL_SCOPE_WARN (2) 196 197static int 198check_scope( BackendDB *be, AccessControl *a ) 199{ 200 ber_len_t patlen; 201 struct berval dn; 202 203 dn = be->be_nsuffix[0]; 204 205 if ( BER_BVISEMPTY( &dn ) ) { 206 return ACL_SCOPE_OK; 207 } 208 209 if ( !BER_BVISEMPTY( &a->acl_dn_pat ) || 210 a->acl_dn_style != ACL_STYLE_REGEX ) 211 { 212 slap_style_t style = a->acl_dn_style; 213 214 if ( style == ACL_STYLE_REGEX ) { 215 char dnbuf[SLAP_LDAPDN_MAXLEN + 2]; 216 char rebuf[SLAP_LDAPDN_MAXLEN + 1]; 217 ber_len_t rebuflen; 218 regex_t re; 219 int rc; 220 221 /* add trailing '$' to database suffix to form 222 * a simple trial regex pattern "<suffix>$" */ 223 AC_MEMCPY( dnbuf, be->be_nsuffix[0].bv_val, 224 be->be_nsuffix[0].bv_len ); 225 dnbuf[be->be_nsuffix[0].bv_len] = '$'; 226 dnbuf[be->be_nsuffix[0].bv_len + 1] = '\0'; 227 228 if ( regcomp( &re, dnbuf, REG_EXTENDED|REG_ICASE ) ) { 229 return ACL_SCOPE_WARN; 230 } 231 232 /* remove trailing ')$', if any, from original 233 * regex pattern */ 234 rebuflen = a->acl_dn_pat.bv_len; 235 AC_MEMCPY( rebuf, a->acl_dn_pat.bv_val, rebuflen + 1 ); 236 if ( rebuf[rebuflen - 1] == '$' ) { 237 rebuf[--rebuflen] = '\0'; 238 } 239 while ( rebuflen > be->be_nsuffix[0].bv_len && rebuf[rebuflen - 1] == ')' ) { 240 rebuf[--rebuflen] = '\0'; 241 } 242 if ( rebuflen == be->be_nsuffix[0].bv_len ) { 243 rc = ACL_SCOPE_WARN; 244 goto regex_done; 245 } 246 247 /* not a clear indication of scoping error, though */ 248 rc = regexec( &re, rebuf, 0, NULL, 0 ) 249 ? ACL_SCOPE_WARN : ACL_SCOPE_OK; 250 251regex_done:; 252 regfree( &re ); 253 return rc; 254 } 255 256 patlen = a->acl_dn_pat.bv_len; 257 /* If backend suffix is longer than pattern, 258 * it is a potential mismatch (in the sense 259 * that a superior naming context could 260 * match */ 261 if ( dn.bv_len > patlen ) { 262 /* base is blatantly wrong */ 263 if ( style == ACL_STYLE_BASE ) return ACL_SCOPE_ERR; 264 265 /* a style of one can be wrong if there is 266 * more than one level between the suffix 267 * and the pattern */ 268 if ( style == ACL_STYLE_ONE ) { 269 ber_len_t rdnlen = 0; 270 int sep = 0; 271 272 if ( patlen > 0 ) { 273 if ( !DN_SEPARATOR( dn.bv_val[dn.bv_len - patlen - 1] )) { 274 return ACL_SCOPE_ERR; 275 } 276 sep = 1; 277 } 278 279 rdnlen = dn_rdnlen( NULL, &dn ); 280 if ( rdnlen != dn.bv_len - patlen - sep ) 281 return ACL_SCOPE_ERR; 282 } 283 284 /* if the trailing part doesn't match, 285 * then it's an error */ 286 if ( strcmp( a->acl_dn_pat.bv_val, 287 &dn.bv_val[dn.bv_len - patlen] ) != 0 ) 288 { 289 return ACL_SCOPE_ERR; 290 } 291 292 return ACL_SCOPE_PARTIAL; 293 } 294 295 switch ( style ) { 296 case ACL_STYLE_BASE: 297 case ACL_STYLE_ONE: 298 case ACL_STYLE_CHILDREN: 299 case ACL_STYLE_SUBTREE: 300 break; 301 302 default: 303 assert( 0 ); 304 break; 305 } 306 307 if ( dn.bv_len < patlen && 308 !DN_SEPARATOR( a->acl_dn_pat.bv_val[patlen - dn.bv_len - 1] )) 309 { 310 return ACL_SCOPE_ERR; 311 } 312 313 if ( strcmp( &a->acl_dn_pat.bv_val[patlen - dn.bv_len], dn.bv_val ) 314 != 0 ) 315 { 316 return ACL_SCOPE_ERR; 317 } 318 319 return ACL_SCOPE_OK; 320 } 321 322 return ACL_SCOPE_UNKNOWN; 323} 324 325int 326parse_acl( 327 Backend *be, 328 const char *fname, 329 int lineno, 330 int argc, 331 char **argv, 332 int pos ) 333{ 334 int i; 335 char *left, *right, *style; 336 struct berval bv; 337 AccessControl *a = NULL; 338 Access *b = NULL; 339 int rc; 340 const char *text; 341 342 for ( i = 1; i < argc; i++ ) { 343 /* to clause - select which entries are protected */ 344 if ( strcasecmp( argv[i], "to" ) == 0 ) { 345 if ( a != NULL ) { 346 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 347 "only one to clause allowed in access line\n", 348 fname, lineno, 0 ); 349 goto fail; 350 } 351 a = (AccessControl *) ch_calloc( 1, sizeof(AccessControl) ); 352 a->acl_attrval_style = ACL_STYLE_NONE; 353 for ( ++i; i < argc; i++ ) { 354 if ( strcasecmp( argv[i], "by" ) == 0 ) { 355 i--; 356 break; 357 } 358 359 if ( strcasecmp( argv[i], "*" ) == 0 ) { 360 if ( !BER_BVISEMPTY( &a->acl_dn_pat ) || 361 a->acl_dn_style != ACL_STYLE_REGEX ) 362 { 363 Debug( LDAP_DEBUG_ANY, 364 "%s: line %d: dn pattern" 365 " already specified in to clause.\n", 366 fname, lineno, 0 ); 367 goto fail; 368 } 369 370 ber_str2bv( "*", STRLENOF( "*" ), 1, &a->acl_dn_pat ); 371 continue; 372 } 373 374 split( argv[i], '=', &left, &right ); 375 split( left, '.', &left, &style ); 376 377 if ( right == NULL ) { 378 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 379 "missing \"=\" in \"%s\" in to clause\n", 380 fname, lineno, left ); 381 goto fail; 382 } 383 384 if ( strcasecmp( left, "dn" ) == 0 ) { 385 if ( !BER_BVISEMPTY( &a->acl_dn_pat ) || 386 a->acl_dn_style != ACL_STYLE_REGEX ) 387 { 388 Debug( LDAP_DEBUG_ANY, 389 "%s: line %d: dn pattern" 390 " already specified in to clause.\n", 391 fname, lineno, 0 ); 392 goto fail; 393 } 394 395 if ( style == NULL || *style == '\0' || 396 strcasecmp( style, "baseObject" ) == 0 || 397 strcasecmp( style, "base" ) == 0 || 398 strcasecmp( style, "exact" ) == 0 ) 399 { 400 a->acl_dn_style = ACL_STYLE_BASE; 401 ber_str2bv( right, 0, 1, &a->acl_dn_pat ); 402 403 } else if ( strcasecmp( style, "oneLevel" ) == 0 || 404 strcasecmp( style, "one" ) == 0 ) 405 { 406 a->acl_dn_style = ACL_STYLE_ONE; 407 ber_str2bv( right, 0, 1, &a->acl_dn_pat ); 408 409 } else if ( strcasecmp( style, "subtree" ) == 0 || 410 strcasecmp( style, "sub" ) == 0 ) 411 { 412 if( *right == '\0' ) { 413 ber_str2bv( "*", STRLENOF( "*" ), 1, &a->acl_dn_pat ); 414 415 } else { 416 a->acl_dn_style = ACL_STYLE_SUBTREE; 417 ber_str2bv( right, 0, 1, &a->acl_dn_pat ); 418 } 419 420 } else if ( strcasecmp( style, "children" ) == 0 ) { 421 a->acl_dn_style = ACL_STYLE_CHILDREN; 422 ber_str2bv( right, 0, 1, &a->acl_dn_pat ); 423 424 } else if ( strcasecmp( style, "regex" ) == 0 ) { 425 a->acl_dn_style = ACL_STYLE_REGEX; 426 427 if ( *right == '\0' ) { 428 /* empty regex should match empty DN */ 429 a->acl_dn_style = ACL_STYLE_BASE; 430 ber_str2bv( right, 0, 1, &a->acl_dn_pat ); 431 432 } else if ( strcmp(right, "*") == 0 433 || strcmp(right, ".*") == 0 434 || strcmp(right, ".*$") == 0 435 || strcmp(right, "^.*") == 0 436 || strcmp(right, "^.*$") == 0 437 || strcmp(right, ".*$$") == 0 438 || strcmp(right, "^.*$$") == 0 ) 439 { 440 ber_str2bv( "*", STRLENOF("*"), 1, &a->acl_dn_pat ); 441 442 } else { 443 acl_regex_normalized_dn( right, &a->acl_dn_pat ); 444 } 445 446 } else { 447 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 448 "unknown dn style \"%s\" in to clause\n", 449 fname, lineno, style ); 450 goto fail; 451 } 452 453 continue; 454 } 455 456 if ( strcasecmp( left, "filter" ) == 0 ) { 457 if ( (a->acl_filter = str2filter( right )) == NULL ) { 458 Debug( LDAP_DEBUG_ANY, 459 "%s: line %d: bad filter \"%s\" in to clause\n", 460 fname, lineno, right ); 461 goto fail; 462 } 463 464 } else if ( strcasecmp( left, "attr" ) == 0 /* TOLERATED */ 465 || strcasecmp( left, "attrs" ) == 0 ) /* DOCUMENTED */ 466 { 467 if ( strcasecmp( left, "attr" ) == 0 ) { 468 Debug( LDAP_DEBUG_ANY, 469 "%s: line %d: \"attr\" " 470 "is deprecated (and undocumented); " 471 "use \"attrs\" instead.\n", 472 fname, lineno, 0 ); 473 } 474 475 a->acl_attrs = str2anlist( a->acl_attrs, 476 right, "," ); 477 if ( a->acl_attrs == NULL ) { 478 Debug( LDAP_DEBUG_ANY, 479 "%s: line %d: unknown attr \"%s\" in to clause\n", 480 fname, lineno, right ); 481 goto fail; 482 } 483 484 } else if ( strncasecmp( left, "val", 3 ) == 0 ) { 485 struct berval bv; 486 char *mr; 487 488 if ( !BER_BVISEMPTY( &a->acl_attrval ) ) { 489 Debug( LDAP_DEBUG_ANY, 490 "%s: line %d: attr val already specified in to clause.\n", 491 fname, lineno, 0 ); 492 goto fail; 493 } 494 if ( a->acl_attrs == NULL || !BER_BVISEMPTY( &a->acl_attrs[1].an_name ) ) 495 { 496 Debug( LDAP_DEBUG_ANY, 497 "%s: line %d: attr val requires a single attribute.\n", 498 fname, lineno, 0 ); 499 goto fail; 500 } 501 502 ber_str2bv( right, 0, 0, &bv ); 503 a->acl_attrval_style = ACL_STYLE_BASE; 504 505 mr = strchr( left, '/' ); 506 if ( mr != NULL ) { 507 mr[ 0 ] = '\0'; 508 mr++; 509 510 a->acl_attrval_mr = mr_find( mr ); 511 if ( a->acl_attrval_mr == NULL ) { 512 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 513 "invalid matching rule \"%s\".\n", 514 fname, lineno, mr ); 515 goto fail; 516 } 517 518 if( !mr_usable_with_at( a->acl_attrval_mr, a->acl_attrs[ 0 ].an_desc->ad_type ) ) 519 { 520 char buf[ SLAP_TEXT_BUFLEN ]; 521 522 snprintf( buf, sizeof( buf ), 523 "matching rule \"%s\" use " 524 "with attr \"%s\" not appropriate.", 525 mr, a->acl_attrs[ 0 ].an_name.bv_val ); 526 527 528 Debug( LDAP_DEBUG_ANY, "%s: line %d: %s\n", 529 fname, lineno, buf ); 530 goto fail; 531 } 532 } 533 534 if ( style != NULL ) { 535 if ( strcasecmp( style, "regex" ) == 0 ) { 536 int e = regcomp( &a->acl_attrval_re, bv.bv_val, 537 REG_EXTENDED | REG_ICASE ); 538 if ( e ) { 539 char err[SLAP_TEXT_BUFLEN], 540 buf[ SLAP_TEXT_BUFLEN ]; 541 542 regerror( e, &a->acl_attrval_re, err, sizeof( err ) ); 543 544 snprintf( buf, sizeof( buf ), 545 "regular expression \"%s\" bad because of %s", 546 right, err ); 547 548 Debug( LDAP_DEBUG_ANY, "%s: line %d: %s\n", 549 fname, lineno, buf ); 550 goto fail; 551 } 552 a->acl_attrval_style = ACL_STYLE_REGEX; 553 554 } else { 555 /* FIXME: if the attribute has DN syntax, we might 556 * allow one, subtree and children styles as well */ 557 if ( !strcasecmp( style, "base" ) || 558 !strcasecmp( style, "exact" ) ) { 559 a->acl_attrval_style = ACL_STYLE_BASE; 560 561 } else if ( a->acl_attrs[0].an_desc->ad_type-> 562 sat_syntax == slap_schema.si_syn_distinguishedName ) 563 { 564 if ( !strcasecmp( style, "baseObject" ) || 565 !strcasecmp( style, "base" ) ) 566 { 567 a->acl_attrval_style = ACL_STYLE_BASE; 568 } else if ( !strcasecmp( style, "onelevel" ) || 569 !strcasecmp( style, "one" ) ) 570 { 571 a->acl_attrval_style = ACL_STYLE_ONE; 572 } else if ( !strcasecmp( style, "subtree" ) || 573 !strcasecmp( style, "sub" ) ) 574 { 575 a->acl_attrval_style = ACL_STYLE_SUBTREE; 576 } else if ( !strcasecmp( style, "children" ) ) { 577 a->acl_attrval_style = ACL_STYLE_CHILDREN; 578 } else { 579 char buf[ SLAP_TEXT_BUFLEN ]; 580 581 snprintf( buf, sizeof( buf ), 582 "unknown val.<style> \"%s\" for attributeType \"%s\" " 583 "with DN syntax.", 584 style, 585 a->acl_attrs[0].an_desc->ad_cname.bv_val ); 586 587 Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, 588 "%s: line %d: %s\n", 589 fname, lineno, buf ); 590 goto fail; 591 } 592 593 rc = dnNormalize( 0, NULL, NULL, &bv, &a->acl_attrval, NULL ); 594 if ( rc != LDAP_SUCCESS ) { 595 char buf[ SLAP_TEXT_BUFLEN ]; 596 597 snprintf( buf, sizeof( buf ), 598 "unable to normalize DN \"%s\" " 599 "for attributeType \"%s\" (%d).", 600 bv.bv_val, 601 a->acl_attrs[0].an_desc->ad_cname.bv_val, 602 rc ); 603 Debug( LDAP_DEBUG_ANY, 604 "%s: line %d: %s\n", 605 fname, lineno, buf ); 606 goto fail; 607 } 608 609 } else { 610 char buf[ SLAP_TEXT_BUFLEN ]; 611 612 snprintf( buf, sizeof( buf ), 613 "unknown val.<style> \"%s\" for attributeType \"%s\".", 614 style, a->acl_attrs[0].an_desc->ad_cname.bv_val ); 615 Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, 616 "%s: line %d: %s\n", 617 fname, lineno, buf ); 618 goto fail; 619 } 620 } 621 } 622 623 /* Check for appropriate matching rule */ 624 if ( a->acl_attrval_style == ACL_STYLE_REGEX ) { 625 ber_dupbv( &a->acl_attrval, &bv ); 626 627 } else if ( BER_BVISNULL( &a->acl_attrval ) ) { 628 int rc; 629 const char *text; 630 631 if ( a->acl_attrval_mr == NULL ) { 632 a->acl_attrval_mr = a->acl_attrs[ 0 ].an_desc->ad_type->sat_equality; 633 } 634 635 if ( a->acl_attrval_mr == NULL ) { 636 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 637 "attr \"%s\" does not have an EQUALITY matching rule.\n", 638 fname, lineno, a->acl_attrs[ 0 ].an_name.bv_val ); 639 goto fail; 640 } 641 642 rc = asserted_value_validate_normalize( 643 a->acl_attrs[ 0 ].an_desc, 644 a->acl_attrval_mr, 645 SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, 646 &bv, 647 &a->acl_attrval, 648 &text, 649 NULL ); 650 if ( rc != LDAP_SUCCESS ) { 651 char buf[ SLAP_TEXT_BUFLEN ]; 652 653 snprintf( buf, sizeof( buf ), "%s: line %d: " 654 " attr \"%s\" normalization failed (%d: %s)", 655 fname, lineno, 656 a->acl_attrs[ 0 ].an_name.bv_val, rc, text ); 657 Debug( LDAP_DEBUG_ANY, "%s: line %d: %s.\n", 658 fname, lineno, buf ); 659 goto fail; 660 } 661 } 662 663 } else { 664 Debug( LDAP_DEBUG_ANY, 665 "%s: line %d: expecting <what> got \"%s\"\n", 666 fname, lineno, left ); 667 goto fail; 668 } 669 } 670 671 if ( !BER_BVISNULL( &a->acl_dn_pat ) && 672 ber_bvccmp( &a->acl_dn_pat, '*' ) ) 673 { 674 free( a->acl_dn_pat.bv_val ); 675 BER_BVZERO( &a->acl_dn_pat ); 676 a->acl_dn_style = ACL_STYLE_REGEX; 677 } 678 679 if ( !BER_BVISEMPTY( &a->acl_dn_pat ) || 680 a->acl_dn_style != ACL_STYLE_REGEX ) 681 { 682 if ( a->acl_dn_style != ACL_STYLE_REGEX ) { 683 struct berval bv; 684 rc = dnNormalize( 0, NULL, NULL, &a->acl_dn_pat, &bv, NULL); 685 if ( rc != LDAP_SUCCESS ) { 686 Debug( LDAP_DEBUG_ANY, 687 "%s: line %d: bad DN \"%s\" in to DN clause\n", 688 fname, lineno, a->acl_dn_pat.bv_val ); 689 goto fail; 690 } 691 free( a->acl_dn_pat.bv_val ); 692 a->acl_dn_pat = bv; 693 694 } else { 695 int e = regcomp( &a->acl_dn_re, a->acl_dn_pat.bv_val, 696 REG_EXTENDED | REG_ICASE ); 697 if ( e ) { 698 char err[ SLAP_TEXT_BUFLEN ], 699 buf[ SLAP_TEXT_BUFLEN ]; 700 701 regerror( e, &a->acl_dn_re, err, sizeof( err ) ); 702 snprintf( buf, sizeof( buf ), 703 "regular expression \"%s\" bad because of %s", 704 right, err ); 705 Debug( LDAP_DEBUG_ANY, "%s: line %d: %s\n", 706 fname, lineno, buf ); 707 goto fail; 708 } 709 } 710 } 711 712 /* by clause - select who has what access to entries */ 713 } else if ( strcasecmp( argv[i], "by" ) == 0 ) { 714 if ( a == NULL ) { 715 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 716 "to clause required before by clause in access line\n", 717 fname, lineno, 0 ); 718 goto fail; 719 } 720 721 /* 722 * by clause consists of <who> and <access> 723 */ 724 725 if ( ++i == argc ) { 726 Debug( LDAP_DEBUG_ANY, 727 "%s: line %d: premature EOL: expecting <who>\n", 728 fname, lineno, 0 ); 729 goto fail; 730 } 731 732 b = (Access *) ch_calloc( 1, sizeof(Access) ); 733 734 ACL_INVALIDATE( b->a_access_mask ); 735 736 /* get <who> */ 737 for ( ; i < argc; i++ ) { 738 slap_style_t sty = ACL_STYLE_REGEX; 739 char *style_modifier = NULL; 740 char *style_level = NULL; 741 int level = 0; 742 int expand = 0; 743 slap_dn_access *bdn = &b->a_dn; 744 int is_realdn = 0; 745 746 split( argv[i], '=', &left, &right ); 747 split( left, '.', &left, &style ); 748 if ( style ) { 749 split( style, ',', &style, &style_modifier ); 750 751 if ( strncasecmp( style, "level", STRLENOF( "level" ) ) == 0 ) { 752 split( style, '{', &style, &style_level ); 753 if ( style_level != NULL ) { 754 char *p = strchr( style_level, '}' ); 755 if ( p == NULL ) { 756 Debug( LDAP_DEBUG_ANY, 757 "%s: line %d: premature eol: " 758 "expecting closing '}' in \"level{n}\"\n", 759 fname, lineno, 0 ); 760 goto fail; 761 } else if ( p == style_level ) { 762 Debug( LDAP_DEBUG_ANY, 763 "%s: line %d: empty level " 764 "in \"level{n}\"\n", 765 fname, lineno, 0 ); 766 goto fail; 767 } 768 p[0] = '\0'; 769 } 770 } 771 } 772 773 if ( style == NULL || *style == '\0' || 774 strcasecmp( style, "exact" ) == 0 || 775 strcasecmp( style, "baseObject" ) == 0 || 776 strcasecmp( style, "base" ) == 0 ) 777 { 778 sty = ACL_STYLE_BASE; 779 780 } else if ( strcasecmp( style, "onelevel" ) == 0 || 781 strcasecmp( style, "one" ) == 0 ) 782 { 783 sty = ACL_STYLE_ONE; 784 785 } else if ( strcasecmp( style, "subtree" ) == 0 || 786 strcasecmp( style, "sub" ) == 0 ) 787 { 788 sty = ACL_STYLE_SUBTREE; 789 790 } else if ( strcasecmp( style, "children" ) == 0 ) { 791 sty = ACL_STYLE_CHILDREN; 792 793 } else if ( strcasecmp( style, "level" ) == 0 ) 794 { 795 if ( lutil_atoi( &level, style_level ) != 0 ) { 796 Debug( LDAP_DEBUG_ANY, 797 "%s: line %d: unable to parse level " 798 "in \"level{n}\"\n", 799 fname, lineno, 0 ); 800 goto fail; 801 } 802 803 sty = ACL_STYLE_LEVEL; 804 805 } else if ( strcasecmp( style, "regex" ) == 0 ) { 806 sty = ACL_STYLE_REGEX; 807 808 } else if ( strcasecmp( style, "expand" ) == 0 ) { 809 sty = ACL_STYLE_EXPAND; 810 811 } else if ( strcasecmp( style, "ip" ) == 0 ) { 812 sty = ACL_STYLE_IP; 813 814 } else if ( strcasecmp( style, "ipv6" ) == 0 ) { 815#ifndef LDAP_PF_INET6 816 Debug( LDAP_DEBUG_ANY, 817 "%s: line %d: IPv6 not supported\n", 818 fname, lineno, 0 ); 819#endif /* ! LDAP_PF_INET6 */ 820 sty = ACL_STYLE_IPV6; 821 822 } else if ( strcasecmp( style, "path" ) == 0 ) { 823 sty = ACL_STYLE_PATH; 824#ifndef LDAP_PF_LOCAL 825 Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, 826 "%s: line %d: " 827 "\"path\" style modifier is useless without local.\n", 828 fname, lineno, 0 ); 829 goto fail; 830#endif /* LDAP_PF_LOCAL */ 831 832 } else { 833 Debug( LDAP_DEBUG_ANY, 834 "%s: line %d: unknown style \"%s\" in by clause\n", 835 fname, lineno, style ); 836 goto fail; 837 } 838 839 if ( style_modifier && 840 strcasecmp( style_modifier, "expand" ) == 0 ) 841 { 842 switch ( sty ) { 843 case ACL_STYLE_REGEX: 844 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 845 "\"regex\" style implies \"expand\" modifier.\n", 846 fname, lineno, 0 ); 847 goto fail; 848 break; 849 850 case ACL_STYLE_EXPAND: 851 break; 852 853 default: 854 /* we'll see later if it's pertinent */ 855 expand = 1; 856 break; 857 } 858 } 859 860 if ( strncasecmp( left, "real", STRLENOF( "real" ) ) == 0 ) { 861 is_realdn = 1; 862 bdn = &b->a_realdn; 863 left += STRLENOF( "real" ); 864 } 865 866 if ( strcasecmp( left, "*" ) == 0 ) { 867 if ( is_realdn ) { 868 goto fail; 869 } 870 871 ber_str2bv( "*", STRLENOF( "*" ), 1, &bv ); 872 sty = ACL_STYLE_REGEX; 873 874 } else if ( strcasecmp( left, "anonymous" ) == 0 ) { 875 ber_str2bv("anonymous", STRLENOF( "anonymous" ), 1, &bv); 876 sty = ACL_STYLE_ANONYMOUS; 877 878 } else if ( strcasecmp( left, "users" ) == 0 ) { 879 ber_str2bv("users", STRLENOF( "users" ), 1, &bv); 880 sty = ACL_STYLE_USERS; 881 882 } else if ( strcasecmp( left, "self" ) == 0 ) { 883 ber_str2bv("self", STRLENOF( "self" ), 1, &bv); 884 sty = ACL_STYLE_SELF; 885 886 } else if ( strcasecmp( left, "dn" ) == 0 ) { 887 if ( sty == ACL_STYLE_REGEX ) { 888 bdn->a_style = ACL_STYLE_REGEX; 889 if ( right == NULL ) { 890 /* no '=' */ 891 ber_str2bv("users", 892 STRLENOF( "users" ), 893 1, &bv); 894 bdn->a_style = ACL_STYLE_USERS; 895 896 } else if (*right == '\0' ) { 897 /* dn="" */ 898 ber_str2bv("anonymous", 899 STRLENOF( "anonymous" ), 900 1, &bv); 901 bdn->a_style = ACL_STYLE_ANONYMOUS; 902 903 } else if ( strcmp( right, "*" ) == 0 ) { 904 /* dn=* */ 905 /* any or users? users for now */ 906 ber_str2bv("users", 907 STRLENOF( "users" ), 908 1, &bv); 909 bdn->a_style = ACL_STYLE_USERS; 910 911 } else if ( strcmp( right, ".+" ) == 0 912 || strcmp( right, "^.+" ) == 0 913 || strcmp( right, ".+$" ) == 0 914 || strcmp( right, "^.+$" ) == 0 915 || strcmp( right, ".+$$" ) == 0 916 || strcmp( right, "^.+$$" ) == 0 ) 917 { 918 ber_str2bv("users", 919 STRLENOF( "users" ), 920 1, &bv); 921 bdn->a_style = ACL_STYLE_USERS; 922 923 } else if ( strcmp( right, ".*" ) == 0 924 || strcmp( right, "^.*" ) == 0 925 || strcmp( right, ".*$" ) == 0 926 || strcmp( right, "^.*$" ) == 0 927 || strcmp( right, ".*$$" ) == 0 928 || strcmp( right, "^.*$$" ) == 0 ) 929 { 930 ber_str2bv("*", 931 STRLENOF( "*" ), 932 1, &bv); 933 934 } else { 935 acl_regex_normalized_dn( right, &bv ); 936 if ( !ber_bvccmp( &bv, '*' ) ) { 937 regtest( fname, lineno, bv.bv_val ); 938 } 939 } 940 941 } else if ( right == NULL || *right == '\0' ) { 942 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 943 "missing \"=\" in (or value after) \"%s\" " 944 "in by clause\n", 945 fname, lineno, left ); 946 goto fail; 947 948 } else { 949 ber_str2bv( right, 0, 1, &bv ); 950 } 951 952 } else { 953 BER_BVZERO( &bv ); 954 } 955 956 if ( !BER_BVISNULL( &bv ) ) { 957 if ( !BER_BVISEMPTY( &bdn->a_pat ) ) { 958 Debug( LDAP_DEBUG_ANY, 959 "%s: line %d: dn pattern already specified.\n", 960 fname, lineno, 0 ); 961 goto fail; 962 } 963 964 if ( sty != ACL_STYLE_REGEX && 965 sty != ACL_STYLE_ANONYMOUS && 966 sty != ACL_STYLE_USERS && 967 sty != ACL_STYLE_SELF && 968 expand == 0 ) 969 { 970 rc = dnNormalize(0, NULL, NULL, 971 &bv, &bdn->a_pat, NULL); 972 if ( rc != LDAP_SUCCESS ) { 973 Debug( LDAP_DEBUG_ANY, 974 "%s: line %d: bad DN \"%s\" in by DN clause\n", 975 fname, lineno, bv.bv_val ); 976 goto fail; 977 } 978 free( bv.bv_val ); 979 if ( sty == ACL_STYLE_BASE 980 && be != NULL 981 && !BER_BVISNULL( &be->be_rootndn ) 982 && dn_match( &bdn->a_pat, &be->be_rootndn ) ) 983 { 984 Debug( LDAP_DEBUG_ANY, 985 "%s: line %d: rootdn is always granted " 986 "unlimited privileges.\n", 987 fname, lineno, 0 ); 988 } 989 990 } else { 991 bdn->a_pat = bv; 992 } 993 bdn->a_style = sty; 994 if ( expand ) { 995 char *exp; 996 int gotit = 0; 997 998 for ( exp = strchr( bdn->a_pat.bv_val, '$' ); 999 exp && (ber_len_t)(exp - bdn->a_pat.bv_val) 1000 < bdn->a_pat.bv_len; 1001 exp = strchr( exp, '$' ) ) 1002 { 1003 if ( ( isdigit( (unsigned char) exp[ 1 ] ) || 1004 exp[ 1 ] == '{' ) ) { 1005 gotit = 1; 1006 break; 1007 } 1008 } 1009 1010 if ( gotit == 1 ) { 1011 bdn->a_expand = expand; 1012 1013 } else { 1014 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1015 "\"expand\" used with no expansions in \"pattern\".\n", 1016 fname, lineno, 0 ); 1017 goto fail; 1018 } 1019 } 1020 if ( sty == ACL_STYLE_SELF ) { 1021 bdn->a_self_level = level; 1022 1023 } else { 1024 if ( level < 0 ) { 1025 Debug( LDAP_DEBUG_ANY, 1026 "%s: line %d: bad negative level \"%d\" " 1027 "in by DN clause\n", 1028 fname, lineno, level ); 1029 goto fail; 1030 } else if ( level == 1 ) { 1031 Debug( LDAP_DEBUG_ANY, 1032 "%s: line %d: \"onelevel\" should be used " 1033 "instead of \"level{1}\" in by DN clause\n", 1034 fname, lineno, 0 ); 1035 } else if ( level == 0 && sty == ACL_STYLE_LEVEL ) { 1036 Debug( LDAP_DEBUG_ANY, 1037 "%s: line %d: \"base\" should be used " 1038 "instead of \"level{0}\" in by DN clause\n", 1039 fname, lineno, 0 ); 1040 } 1041 1042 bdn->a_level = level; 1043 } 1044 continue; 1045 } 1046 1047 if ( strcasecmp( left, "dnattr" ) == 0 ) { 1048 if ( right == NULL || right[0] == '\0' ) { 1049 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1050 "missing \"=\" in (or value after) \"%s\" " 1051 "in by clause\n", 1052 fname, lineno, left ); 1053 goto fail; 1054 } 1055 1056 if( bdn->a_at != NULL ) { 1057 Debug( LDAP_DEBUG_ANY, 1058 "%s: line %d: dnattr already specified.\n", 1059 fname, lineno, 0 ); 1060 goto fail; 1061 } 1062 1063 rc = slap_str2ad( right, &bdn->a_at, &text ); 1064 1065 if( rc != LDAP_SUCCESS ) { 1066 char buf[ SLAP_TEXT_BUFLEN ]; 1067 1068 snprintf( buf, sizeof( buf ), 1069 "dnattr \"%s\": %s", 1070 right, text ); 1071 Debug( LDAP_DEBUG_ANY, 1072 "%s: line %d: %s\n", 1073 fname, lineno, buf ); 1074 goto fail; 1075 } 1076 1077 1078 if( !is_at_syntax( bdn->a_at->ad_type, 1079 SLAPD_DN_SYNTAX ) && 1080 !is_at_syntax( bdn->a_at->ad_type, 1081 SLAPD_NAMEUID_SYNTAX )) 1082 { 1083 char buf[ SLAP_TEXT_BUFLEN ]; 1084 1085 snprintf( buf, sizeof( buf ), 1086 "dnattr \"%s\": " 1087 "inappropriate syntax: %s\n", 1088 right, 1089 bdn->a_at->ad_type->sat_syntax_oid ); 1090 Debug( LDAP_DEBUG_ANY, 1091 "%s: line %d: %s\n", 1092 fname, lineno, buf ); 1093 goto fail; 1094 } 1095 1096 if( bdn->a_at->ad_type->sat_equality == NULL ) { 1097 Debug( LDAP_DEBUG_ANY, 1098 "%s: line %d: dnattr \"%s\": " 1099 "inappropriate matching (no EQUALITY)\n", 1100 fname, lineno, right ); 1101 goto fail; 1102 } 1103 1104 continue; 1105 } 1106 1107 if ( strncasecmp( left, "group", STRLENOF( "group" ) ) == 0 ) { 1108 char *name = NULL; 1109 char *value = NULL; 1110 char *attr_name = SLAPD_GROUP_ATTR; 1111 1112 switch ( sty ) { 1113 case ACL_STYLE_REGEX: 1114 /* legacy, tolerated */ 1115 Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, 1116 "%s: line %d: " 1117 "deprecated group style \"regex\"; " 1118 "use \"expand\" instead.\n", 1119 fname, lineno, 0 ); 1120 sty = ACL_STYLE_EXPAND; 1121 break; 1122 1123 case ACL_STYLE_BASE: 1124 /* legal, traditional */ 1125 case ACL_STYLE_EXPAND: 1126 /* legal, substring expansion; supersedes regex */ 1127 break; 1128 1129 default: 1130 /* unknown */ 1131 Debug( LDAP_DEBUG_ANY, 1132 "%s: line %d: " 1133 "inappropriate style \"%s\" in by clause.\n", 1134 fname, lineno, style ); 1135 goto fail; 1136 } 1137 1138 if ( right == NULL || right[0] == '\0' ) { 1139 Debug( LDAP_DEBUG_ANY, 1140 "%s: line %d: " 1141 "missing \"=\" in (or value after) \"%s\" " 1142 "in by clause.\n", 1143 fname, lineno, left ); 1144 goto fail; 1145 } 1146 1147 if ( !BER_BVISEMPTY( &b->a_group_pat ) ) { 1148 Debug( LDAP_DEBUG_ANY, 1149 "%s: line %d: group pattern already specified.\n", 1150 fname, lineno, 0 ); 1151 goto fail; 1152 } 1153 1154 /* format of string is 1155 "group/objectClassValue/groupAttrName" */ 1156 if ( ( value = strchr(left, '/') ) != NULL ) { 1157 *value++ = '\0'; 1158 if ( *value && ( name = strchr( value, '/' ) ) != NULL ) { 1159 *name++ = '\0'; 1160 } 1161 } 1162 1163 b->a_group_style = sty; 1164 if ( sty == ACL_STYLE_EXPAND ) { 1165 acl_regex_normalized_dn( right, &bv ); 1166 if ( !ber_bvccmp( &bv, '*' ) ) { 1167 regtest( fname, lineno, bv.bv_val ); 1168 } 1169 b->a_group_pat = bv; 1170 1171 } else { 1172 ber_str2bv( right, 0, 0, &bv ); 1173 rc = dnNormalize( 0, NULL, NULL, &bv, 1174 &b->a_group_pat, NULL ); 1175 if ( rc != LDAP_SUCCESS ) { 1176 Debug( LDAP_DEBUG_ANY, 1177 "%s: line %d: bad DN \"%s\".\n", 1178 fname, lineno, right ); 1179 goto fail; 1180 } 1181 } 1182 1183 if ( value && *value ) { 1184 b->a_group_oc = oc_find( value ); 1185 *--value = '/'; 1186 1187 if ( b->a_group_oc == NULL ) { 1188 Debug( LDAP_DEBUG_ANY, 1189 "%s: line %d: group objectclass " 1190 "\"%s\" unknown.\n", 1191 fname, lineno, value ); 1192 goto fail; 1193 } 1194 1195 } else { 1196 b->a_group_oc = oc_find( SLAPD_GROUP_CLASS ); 1197 1198 if( b->a_group_oc == NULL ) { 1199 Debug( LDAP_DEBUG_ANY, 1200 "%s: line %d: group default objectclass " 1201 "\"%s\" unknown.\n", 1202 fname, lineno, SLAPD_GROUP_CLASS ); 1203 goto fail; 1204 } 1205 } 1206 1207 if ( is_object_subclass( slap_schema.si_oc_referral, 1208 b->a_group_oc ) ) 1209 { 1210 Debug( LDAP_DEBUG_ANY, 1211 "%s: line %d: group objectclass \"%s\" " 1212 "is subclass of referral.\n", 1213 fname, lineno, value ); 1214 goto fail; 1215 } 1216 1217 if ( is_object_subclass( slap_schema.si_oc_alias, 1218 b->a_group_oc ) ) 1219 { 1220 Debug( LDAP_DEBUG_ANY, 1221 "%s: line %d: group objectclass \"%s\" " 1222 "is subclass of alias.\n", 1223 fname, lineno, value ); 1224 goto fail; 1225 } 1226 1227 if ( name && *name ) { 1228 attr_name = name; 1229 *--name = '/'; 1230 1231 } 1232 1233 rc = slap_str2ad( attr_name, &b->a_group_at, &text ); 1234 if ( rc != LDAP_SUCCESS ) { 1235 char buf[ SLAP_TEXT_BUFLEN ]; 1236 1237 snprintf( buf, sizeof( buf ), 1238 "group \"%s\": %s.", 1239 right, text ); 1240 Debug( LDAP_DEBUG_ANY, 1241 "%s: line %d: %s\n", 1242 fname, lineno, buf ); 1243 goto fail; 1244 } 1245 1246 if ( !is_at_syntax( b->a_group_at->ad_type, 1247 SLAPD_DN_SYNTAX ) /* e.g. "member" */ 1248 && !is_at_syntax( b->a_group_at->ad_type, 1249 SLAPD_NAMEUID_SYNTAX ) /* e.g. memberUID */ 1250 && !is_at_subtype( b->a_group_at->ad_type, 1251 slap_schema.si_ad_labeledURI->ad_type ) /* e.g. memberURL */ ) 1252 { 1253 char buf[ SLAP_TEXT_BUFLEN ]; 1254 1255 snprintf( buf, sizeof( buf ), 1256 "group \"%s\" attr \"%s\": inappropriate syntax: %s; " 1257 "must be " SLAPD_DN_SYNTAX " (DN), " 1258 SLAPD_NAMEUID_SYNTAX " (NameUID) " 1259 "or a subtype of labeledURI.", 1260 right, 1261 attr_name, 1262 at_syntax( b->a_group_at->ad_type ) ); 1263 Debug( LDAP_DEBUG_ANY, 1264 "%s: line %d: %s\n", 1265 fname, lineno, buf ); 1266 goto fail; 1267 } 1268 1269 1270 { 1271 int rc; 1272 ObjectClass *ocs[2]; 1273 1274 ocs[0] = b->a_group_oc; 1275 ocs[1] = NULL; 1276 1277 rc = oc_check_allowed( b->a_group_at->ad_type, 1278 ocs, NULL ); 1279 1280 if( rc != 0 ) { 1281 char buf[ SLAP_TEXT_BUFLEN ]; 1282 1283 snprintf( buf, sizeof( buf ), 1284 "group: \"%s\" not allowed by \"%s\".", 1285 b->a_group_at->ad_cname.bv_val, 1286 b->a_group_oc->soc_oid ); 1287 Debug( LDAP_DEBUG_ANY, "%s: line %d: %s\n", 1288 fname, lineno, buf ); 1289 goto fail; 1290 } 1291 } 1292 continue; 1293 } 1294 1295 if ( strcasecmp( left, "peername" ) == 0 ) { 1296 switch ( sty ) { 1297 case ACL_STYLE_REGEX: 1298 case ACL_STYLE_BASE: 1299 /* legal, traditional */ 1300 case ACL_STYLE_EXPAND: 1301 /* cheap replacement to regex for simple expansion */ 1302 case ACL_STYLE_IP: 1303 case ACL_STYLE_IPV6: 1304 case ACL_STYLE_PATH: 1305 /* legal, peername specific */ 1306 break; 1307 1308 default: 1309 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1310 "inappropriate style \"%s\" in by clause.\n", 1311 fname, lineno, style ); 1312 goto fail; 1313 } 1314 1315 if ( right == NULL || right[0] == '\0' ) { 1316 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1317 "missing \"=\" in (or value after) \"%s\" " 1318 "in by clause.\n", 1319 fname, lineno, left ); 1320 goto fail; 1321 } 1322 1323 if ( !BER_BVISEMPTY( &b->a_peername_pat ) ) { 1324 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1325 "peername pattern already specified.\n", 1326 fname, lineno, 0 ); 1327 goto fail; 1328 } 1329 1330 b->a_peername_style = sty; 1331 if ( sty == ACL_STYLE_REGEX ) { 1332 acl_regex_normalized_dn( right, &bv ); 1333 if ( !ber_bvccmp( &bv, '*' ) ) { 1334 regtest( fname, lineno, bv.bv_val ); 1335 } 1336 b->a_peername_pat = bv; 1337 1338 } else { 1339 ber_str2bv( right, 0, 1, &b->a_peername_pat ); 1340 1341 if ( sty == ACL_STYLE_IP ) { 1342 char *addr = NULL, 1343 *mask = NULL, 1344 *port = NULL; 1345 1346 split( right, '{', &addr, &port ); 1347 split( addr, '%', &addr, &mask ); 1348 1349 b->a_peername_addr = inet_addr( addr ); 1350 if ( b->a_peername_addr == (unsigned long)(-1) ) { 1351 /* illegal address */ 1352 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1353 "illegal peername address \"%s\".\n", 1354 fname, lineno, addr ); 1355 goto fail; 1356 } 1357 1358 b->a_peername_mask = (unsigned long)(-1); 1359 if ( mask != NULL ) { 1360 b->a_peername_mask = inet_addr( mask ); 1361 if ( b->a_peername_mask == 1362 (unsigned long)(-1) ) 1363 { 1364 /* illegal mask */ 1365 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1366 "illegal peername address mask " 1367 "\"%s\".\n", 1368 fname, lineno, mask ); 1369 goto fail; 1370 } 1371 } 1372 1373 b->a_peername_port = -1; 1374 if ( port ) { 1375 char *end = NULL; 1376 1377 b->a_peername_port = strtol( port, &end, 10 ); 1378 if ( end == port || end[0] != '}' ) { 1379 /* illegal port */ 1380 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1381 "illegal peername port specification " 1382 "\"{%s}\".\n", 1383 fname, lineno, port ); 1384 goto fail; 1385 } 1386 } 1387 1388#ifdef LDAP_PF_INET6 1389 } else if ( sty == ACL_STYLE_IPV6 ) { 1390 char *addr = NULL, 1391 *mask = NULL, 1392 *port = NULL; 1393 1394 split( right, '{', &addr, &port ); 1395 split( addr, '%', &addr, &mask ); 1396 1397 if ( inet_pton( AF_INET6, addr, &b->a_peername_addr6 ) != 1 ) { 1398 /* illegal address */ 1399 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1400 "illegal peername address \"%s\".\n", 1401 fname, lineno, addr ); 1402 goto fail; 1403 } 1404 1405 if ( mask == NULL ) { 1406 mask = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"; 1407 } 1408 1409 if ( inet_pton( AF_INET6, mask, &b->a_peername_mask6 ) != 1 ) { 1410 /* illegal mask */ 1411 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1412 "illegal peername address mask " 1413 "\"%s\".\n", 1414 fname, lineno, mask ); 1415 goto fail; 1416 } 1417 1418 b->a_peername_port = -1; 1419 if ( port ) { 1420 char *end = NULL; 1421 1422 b->a_peername_port = strtol( port, &end, 10 ); 1423 if ( end == port || end[0] != '}' ) { 1424 /* illegal port */ 1425 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1426 "illegal peername port specification " 1427 "\"{%s}\".\n", 1428 fname, lineno, port ); 1429 goto fail; 1430 } 1431 } 1432#endif /* LDAP_PF_INET6 */ 1433 } 1434 } 1435 continue; 1436 } 1437 1438 if ( strcasecmp( left, "sockname" ) == 0 ) { 1439 switch ( sty ) { 1440 case ACL_STYLE_REGEX: 1441 case ACL_STYLE_BASE: 1442 /* legal, traditional */ 1443 case ACL_STYLE_EXPAND: 1444 /* cheap replacement to regex for simple expansion */ 1445 break; 1446 1447 default: 1448 /* unknown */ 1449 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1450 "inappropriate style \"%s\" in by clause\n", 1451 fname, lineno, style ); 1452 goto fail; 1453 } 1454 1455 if ( right == NULL || right[0] == '\0' ) { 1456 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1457 "missing \"=\" in (or value after) \"%s\" " 1458 "in by clause\n", 1459 fname, lineno, left ); 1460 goto fail; 1461 } 1462 1463 if ( !BER_BVISNULL( &b->a_sockname_pat ) ) { 1464 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1465 "sockname pattern already specified.\n", 1466 fname, lineno, 0 ); 1467 goto fail; 1468 } 1469 1470 b->a_sockname_style = sty; 1471 if ( sty == ACL_STYLE_REGEX ) { 1472 acl_regex_normalized_dn( right, &bv ); 1473 if ( !ber_bvccmp( &bv, '*' ) ) { 1474 regtest( fname, lineno, bv.bv_val ); 1475 } 1476 b->a_sockname_pat = bv; 1477 1478 } else { 1479 ber_str2bv( right, 0, 1, &b->a_sockname_pat ); 1480 } 1481 continue; 1482 } 1483 1484 if ( strcasecmp( left, "domain" ) == 0 ) { 1485 switch ( sty ) { 1486 case ACL_STYLE_REGEX: 1487 case ACL_STYLE_BASE: 1488 case ACL_STYLE_SUBTREE: 1489 /* legal, traditional */ 1490 break; 1491 1492 case ACL_STYLE_EXPAND: 1493 /* tolerated: means exact,expand */ 1494 if ( expand ) { 1495 Debug( LDAP_DEBUG_ANY, 1496 "%s: line %d: " 1497 "\"expand\" modifier " 1498 "with \"expand\" style.\n", 1499 fname, lineno, 0 ); 1500 } 1501 sty = ACL_STYLE_BASE; 1502 expand = 1; 1503 break; 1504 1505 default: 1506 /* unknown */ 1507 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1508 "inappropriate style \"%s\" in by clause.\n", 1509 fname, lineno, style ); 1510 goto fail; 1511 } 1512 1513 if ( right == NULL || right[0] == '\0' ) { 1514 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1515 "missing \"=\" in (or value after) \"%s\" " 1516 "in by clause.\n", 1517 fname, lineno, left ); 1518 goto fail; 1519 } 1520 1521 if ( !BER_BVISEMPTY( &b->a_domain_pat ) ) { 1522 Debug( LDAP_DEBUG_ANY, 1523 "%s: line %d: domain pattern already specified.\n", 1524 fname, lineno, 0 ); 1525 goto fail; 1526 } 1527 1528 b->a_domain_style = sty; 1529 b->a_domain_expand = expand; 1530 if ( sty == ACL_STYLE_REGEX ) { 1531 acl_regex_normalized_dn( right, &bv ); 1532 if ( !ber_bvccmp( &bv, '*' ) ) { 1533 regtest( fname, lineno, bv.bv_val ); 1534 } 1535 b->a_domain_pat = bv; 1536 1537 } else { 1538 ber_str2bv( right, 0, 1, &b->a_domain_pat ); 1539 } 1540 continue; 1541 } 1542 1543 if ( strcasecmp( left, "sockurl" ) == 0 ) { 1544 switch ( sty ) { 1545 case ACL_STYLE_REGEX: 1546 case ACL_STYLE_BASE: 1547 /* legal, traditional */ 1548 case ACL_STYLE_EXPAND: 1549 /* cheap replacement to regex for simple expansion */ 1550 break; 1551 1552 default: 1553 /* unknown */ 1554 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1555 "inappropriate style \"%s\" in by clause.\n", 1556 fname, lineno, style ); 1557 goto fail; 1558 } 1559 1560 if ( right == NULL || right[0] == '\0' ) { 1561 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1562 "missing \"=\" in (or value after) \"%s\" " 1563 "in by clause.\n", 1564 fname, lineno, left ); 1565 goto fail; 1566 } 1567 1568 if ( !BER_BVISEMPTY( &b->a_sockurl_pat ) ) { 1569 Debug( LDAP_DEBUG_ANY, 1570 "%s: line %d: sockurl pattern already specified.\n", 1571 fname, lineno, 0 ); 1572 goto fail; 1573 } 1574 1575 b->a_sockurl_style = sty; 1576 if ( sty == ACL_STYLE_REGEX ) { 1577 acl_regex_normalized_dn( right, &bv ); 1578 if ( !ber_bvccmp( &bv, '*' ) ) { 1579 regtest( fname, lineno, bv.bv_val ); 1580 } 1581 b->a_sockurl_pat = bv; 1582 1583 } else { 1584 ber_str2bv( right, 0, 1, &b->a_sockurl_pat ); 1585 } 1586 continue; 1587 } 1588 1589 if ( strcasecmp( left, "set" ) == 0 ) { 1590 switch ( sty ) { 1591 /* deprecated */ 1592 case ACL_STYLE_REGEX: 1593 Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, 1594 "%s: line %d: " 1595 "deprecated set style " 1596 "\"regex\" in <by> clause; " 1597 "use \"expand\" instead.\n", 1598 fname, lineno, 0 ); 1599 sty = ACL_STYLE_EXPAND; 1600 /* FALLTHRU */ 1601 1602 case ACL_STYLE_BASE: 1603 case ACL_STYLE_EXPAND: 1604 break; 1605 1606 default: 1607 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1608 "inappropriate style \"%s\" in by clause.\n", 1609 fname, lineno, style ); 1610 goto fail; 1611 } 1612 1613 if ( !BER_BVISEMPTY( &b->a_set_pat ) ) { 1614 Debug( LDAP_DEBUG_ANY, 1615 "%s: line %d: set attribute already specified.\n", 1616 fname, lineno, 0 ); 1617 goto fail; 1618 } 1619 1620 if ( right == NULL || *right == '\0' ) { 1621 Debug( LDAP_DEBUG_ANY, 1622 "%s: line %d: no set is defined.\n", 1623 fname, lineno, 0 ); 1624 goto fail; 1625 } 1626 1627 b->a_set_style = sty; 1628 ber_str2bv( right, 0, 1, &b->a_set_pat ); 1629 1630 continue; 1631 } 1632 1633#ifdef SLAP_DYNACL 1634 { 1635 char *name = NULL, 1636 *opts = NULL; 1637 1638#if 1 /* tolerate legacy "aci" <who> */ 1639 if ( strcasecmp( left, "aci" ) == 0 ) { 1640 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1641 "undocumented deprecated \"aci\" directive " 1642 "is superseded by \"dynacl/aci\".\n", 1643 fname, lineno, 0 ); 1644 name = "aci"; 1645 1646 } else 1647#endif /* tolerate legacy "aci" <who> */ 1648 if ( strncasecmp( left, "dynacl/", STRLENOF( "dynacl/" ) ) == 0 ) { 1649 name = &left[ STRLENOF( "dynacl/" ) ]; 1650 opts = strchr( name, '/' ); 1651 if ( opts ) { 1652 opts[ 0 ] = '\0'; 1653 opts++; 1654 } 1655 } 1656 1657 if ( name ) { 1658 if ( slap_dynacl_config( fname, lineno, b, name, opts, sty, right ) ) { 1659 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1660 "unable to configure dynacl \"%s\".\n", 1661 fname, lineno, name ); 1662 goto fail; 1663 } 1664 1665 continue; 1666 } 1667 } 1668#endif /* SLAP_DYNACL */ 1669 1670 if ( strcasecmp( left, "ssf" ) == 0 ) { 1671 if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) { 1672 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1673 "inappropriate style \"%s\" in by clause.\n", 1674 fname, lineno, style ); 1675 goto fail; 1676 } 1677 1678 if ( b->a_authz.sai_ssf ) { 1679 Debug( LDAP_DEBUG_ANY, 1680 "%s: line %d: ssf attribute already specified.\n", 1681 fname, lineno, 0 ); 1682 goto fail; 1683 } 1684 1685 if ( right == NULL || *right == '\0' ) { 1686 Debug( LDAP_DEBUG_ANY, 1687 "%s: line %d: no ssf is defined.\n", 1688 fname, lineno, 0 ); 1689 goto fail; 1690 } 1691 1692 if ( lutil_atou( &b->a_authz.sai_ssf, right ) != 0 ) { 1693 Debug( LDAP_DEBUG_ANY, 1694 "%s: line %d: unable to parse ssf value (%s).\n", 1695 fname, lineno, right ); 1696 goto fail; 1697 } 1698 1699 if ( !b->a_authz.sai_ssf ) { 1700 Debug( LDAP_DEBUG_ANY, 1701 "%s: line %d: invalid ssf value (%s).\n", 1702 fname, lineno, right ); 1703 goto fail; 1704 } 1705 continue; 1706 } 1707 1708 if ( strcasecmp( left, "transport_ssf" ) == 0 ) { 1709 if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) { 1710 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1711 "inappropriate style \"%s\" in by clause.\n", 1712 fname, lineno, style ); 1713 goto fail; 1714 } 1715 1716 if ( b->a_authz.sai_transport_ssf ) { 1717 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1718 "transport_ssf attribute already specified.\n", 1719 fname, lineno, 0 ); 1720 goto fail; 1721 } 1722 1723 if ( right == NULL || *right == '\0' ) { 1724 Debug( LDAP_DEBUG_ANY, 1725 "%s: line %d: no transport_ssf is defined.\n", 1726 fname, lineno, 0 ); 1727 goto fail; 1728 } 1729 1730 if ( lutil_atou( &b->a_authz.sai_transport_ssf, right ) != 0 ) { 1731 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1732 "unable to parse transport_ssf value (%s).\n", 1733 fname, lineno, right ); 1734 goto fail; 1735 } 1736 1737 if ( !b->a_authz.sai_transport_ssf ) { 1738 Debug( LDAP_DEBUG_ANY, 1739 "%s: line %d: invalid transport_ssf value (%s).\n", 1740 fname, lineno, right ); 1741 goto fail; 1742 } 1743 continue; 1744 } 1745 1746 if ( strcasecmp( left, "tls_ssf" ) == 0 ) { 1747 if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) { 1748 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1749 "inappropriate style \"%s\" in by clause.\n", 1750 fname, lineno, style ); 1751 goto fail; 1752 } 1753 1754 if ( b->a_authz.sai_tls_ssf ) { 1755 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1756 "tls_ssf attribute already specified.\n", 1757 fname, lineno, 0 ); 1758 goto fail; 1759 } 1760 1761 if ( right == NULL || *right == '\0' ) { 1762 Debug( LDAP_DEBUG_ANY, 1763 "%s: line %d: no tls_ssf is defined\n", 1764 fname, lineno, 0 ); 1765 goto fail; 1766 } 1767 1768 if ( lutil_atou( &b->a_authz.sai_tls_ssf, right ) != 0 ) { 1769 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1770 "unable to parse tls_ssf value (%s).\n", 1771 fname, lineno, right ); 1772 goto fail; 1773 } 1774 1775 if ( !b->a_authz.sai_tls_ssf ) { 1776 Debug( LDAP_DEBUG_ANY, 1777 "%s: line %d: invalid tls_ssf value (%s).\n", 1778 fname, lineno, right ); 1779 goto fail; 1780 } 1781 continue; 1782 } 1783 1784 if ( strcasecmp( left, "sasl_ssf" ) == 0 ) { 1785 if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) { 1786 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1787 "inappropriate style \"%s\" in by clause.\n", 1788 fname, lineno, style ); 1789 goto fail; 1790 } 1791 1792 if ( b->a_authz.sai_sasl_ssf ) { 1793 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1794 "sasl_ssf attribute already specified.\n", 1795 fname, lineno, 0 ); 1796 goto fail; 1797 } 1798 1799 if ( right == NULL || *right == '\0' ) { 1800 Debug( LDAP_DEBUG_ANY, 1801 "%s: line %d: no sasl_ssf is defined.\n", 1802 fname, lineno, 0 ); 1803 goto fail; 1804 } 1805 1806 if ( lutil_atou( &b->a_authz.sai_sasl_ssf, right ) != 0 ) { 1807 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1808 "unable to parse sasl_ssf value (%s).\n", 1809 fname, lineno, right ); 1810 goto fail; 1811 } 1812 1813 if ( !b->a_authz.sai_sasl_ssf ) { 1814 Debug( LDAP_DEBUG_ANY, 1815 "%s: line %d: invalid sasl_ssf value (%s).\n", 1816 fname, lineno, right ); 1817 goto fail; 1818 } 1819 continue; 1820 } 1821 1822 if ( right != NULL ) { 1823 /* unsplit */ 1824 right[-1] = '='; 1825 } 1826 break; 1827 } 1828 1829 if ( i == argc || ( strcasecmp( left, "stop" ) == 0 ) ) { 1830 /* out of arguments or plain stop */ 1831 1832 ACL_PRIV_ASSIGN( b->a_access_mask, ACL_PRIV_ADDITIVE ); 1833 ACL_PRIV_SET( b->a_access_mask, ACL_PRIV_NONE); 1834 b->a_type = ACL_STOP; 1835 1836 access_append( &a->acl_access, b ); 1837 continue; 1838 } 1839 1840 if ( strcasecmp( left, "continue" ) == 0 ) { 1841 /* plain continue */ 1842 1843 ACL_PRIV_ASSIGN( b->a_access_mask, ACL_PRIV_ADDITIVE ); 1844 ACL_PRIV_SET( b->a_access_mask, ACL_PRIV_NONE); 1845 b->a_type = ACL_CONTINUE; 1846 1847 access_append( &a->acl_access, b ); 1848 continue; 1849 } 1850 1851 if ( strcasecmp( left, "break" ) == 0 ) { 1852 /* plain continue */ 1853 1854 ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE); 1855 ACL_PRIV_SET( b->a_access_mask, ACL_PRIV_NONE); 1856 b->a_type = ACL_BREAK; 1857 1858 access_append( &a->acl_access, b ); 1859 continue; 1860 } 1861 1862 if ( strcasecmp( left, "by" ) == 0 ) { 1863 /* we've gone too far */ 1864 --i; 1865 ACL_PRIV_ASSIGN( b->a_access_mask, ACL_PRIV_ADDITIVE ); 1866 ACL_PRIV_SET( b->a_access_mask, ACL_PRIV_NONE); 1867 b->a_type = ACL_STOP; 1868 1869 access_append( &a->acl_access, b ); 1870 continue; 1871 } 1872 1873 /* get <access> */ 1874 { 1875 char *lleft = left; 1876 1877 if ( strncasecmp( left, "self", STRLENOF( "self" ) ) == 0 ) { 1878 b->a_dn_self = 1; 1879 lleft = &left[ STRLENOF( "self" ) ]; 1880 1881 } else if ( strncasecmp( left, "realself", STRLENOF( "realself" ) ) == 0 ) { 1882 b->a_realdn_self = 1; 1883 lleft = &left[ STRLENOF( "realself" ) ]; 1884 } 1885 1886 ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( lleft ) ); 1887 } 1888 1889 if ( ACL_IS_INVALID( b->a_access_mask ) ) { 1890 Debug( LDAP_DEBUG_ANY, 1891 "%s: line %d: expecting <access> got \"%s\".\n", 1892 fname, lineno, left ); 1893 goto fail; 1894 } 1895 1896 b->a_type = ACL_STOP; 1897 1898 if ( ++i == argc ) { 1899 /* out of arguments or plain stop */ 1900 access_append( &a->acl_access, b ); 1901 continue; 1902 } 1903 1904 if ( strcasecmp( argv[i], "continue" ) == 0 ) { 1905 /* plain continue */ 1906 b->a_type = ACL_CONTINUE; 1907 1908 } else if ( strcasecmp( argv[i], "break" ) == 0 ) { 1909 /* plain continue */ 1910 b->a_type = ACL_BREAK; 1911 1912 } else if ( strcasecmp( argv[i], "stop" ) != 0 ) { 1913 /* gone to far */ 1914 i--; 1915 } 1916 1917 access_append( &a->acl_access, b ); 1918 b = NULL; 1919 1920 } else { 1921 Debug( LDAP_DEBUG_ANY, 1922 "%s: line %d: expecting \"to\" " 1923 "or \"by\" got \"%s\"\n", 1924 fname, lineno, argv[i] ); 1925 goto fail; 1926 } 1927 } 1928 1929 /* if we have no real access clause, complain and do nothing */ 1930 if ( a == NULL ) { 1931 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1932 "warning: no access clause(s) specified in access line.\n", 1933 fname, lineno, 0 ); 1934 goto fail; 1935 1936 } else { 1937#ifdef LDAP_DEBUG 1938 if ( slap_debug & LDAP_DEBUG_ACL ) { 1939 print_acl( be, a ); 1940 } 1941#endif 1942 1943 if ( a->acl_access == NULL ) { 1944 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1945 "warning: no by clause(s) specified in access line.\n", 1946 fname, lineno, 0 ); 1947 goto fail; 1948 } 1949 1950 if ( be != NULL ) { 1951 if ( be->be_nsuffix == NULL ) { 1952 Debug( LDAP_DEBUG_ACL, "%s: line %d: warning: " 1953 "scope checking needs suffix before ACLs.\n", 1954 fname, lineno, 0 ); 1955 /* go ahead, since checking is not authoritative */ 1956 } else if ( !BER_BVISNULL( &be->be_nsuffix[ 1 ] ) ) { 1957 Debug( LDAP_DEBUG_ACL, "%s: line %d: warning: " 1958 "scope checking only applies to single-valued " 1959 "suffix databases\n", 1960 fname, lineno, 0 ); 1961 /* go ahead, since checking is not authoritative */ 1962 } else { 1963 switch ( check_scope( be, a ) ) { 1964 case ACL_SCOPE_UNKNOWN: 1965 Debug( LDAP_DEBUG_ACL, "%s: line %d: warning: " 1966 "cannot assess the validity of the ACL scope within " 1967 "backend naming context\n", 1968 fname, lineno, 0 ); 1969 break; 1970 1971 case ACL_SCOPE_WARN: 1972 Debug( LDAP_DEBUG_ACL, "%s: line %d: warning: " 1973 "ACL could be out of scope within backend naming context\n", 1974 fname, lineno, 0 ); 1975 break; 1976 1977 case ACL_SCOPE_PARTIAL: 1978 Debug( LDAP_DEBUG_ACL, "%s: line %d: warning: " 1979 "ACL appears to be partially out of scope within " 1980 "backend naming context\n", 1981 fname, lineno, 0 ); 1982 break; 1983 1984 case ACL_SCOPE_ERR: 1985 Debug( LDAP_DEBUG_ACL, "%s: line %d: warning: " 1986 "ACL appears to be out of scope within " 1987 "backend naming context\n", 1988 fname, lineno, 0 ); 1989 break; 1990 1991 default: 1992 break; 1993 } 1994 } 1995 acl_append( &be->be_acl, a, pos ); 1996 1997 } else { 1998 acl_append( &frontendDB->be_acl, a, pos ); 1999 } 2000 } 2001 2002 return 0; 2003 2004fail: 2005 if ( b ) access_free( b ); 2006 if ( a ) acl_free( a ); 2007 return acl_usage(); 2008} 2009 2010char * 2011accessmask2str( slap_mask_t mask, char *buf, int debug ) 2012{ 2013 int none = 1; 2014 char *ptr = buf; 2015 2016 assert( buf != NULL ); 2017 2018 if ( ACL_IS_INVALID( mask ) ) { 2019 return "invalid"; 2020 } 2021 2022 buf[0] = '\0'; 2023 2024 if ( ACL_IS_LEVEL( mask ) ) { 2025 if ( ACL_LVL_IS_NONE(mask) ) { 2026 ptr = lutil_strcopy( ptr, "none" ); 2027 2028 } else if ( ACL_LVL_IS_DISCLOSE(mask) ) { 2029 ptr = lutil_strcopy( ptr, "disclose" ); 2030 2031 } else if ( ACL_LVL_IS_AUTH(mask) ) { 2032 ptr = lutil_strcopy( ptr, "auth" ); 2033 2034 } else if ( ACL_LVL_IS_COMPARE(mask) ) { 2035 ptr = lutil_strcopy( ptr, "compare" ); 2036 2037 } else if ( ACL_LVL_IS_SEARCH(mask) ) { 2038 ptr = lutil_strcopy( ptr, "search" ); 2039 2040 } else if ( ACL_LVL_IS_READ(mask) ) { 2041 ptr = lutil_strcopy( ptr, "read" ); 2042 2043 } else if ( ACL_LVL_IS_WRITE(mask) ) { 2044 ptr = lutil_strcopy( ptr, "write" ); 2045 2046 } else if ( ACL_LVL_IS_WADD(mask) ) { 2047 ptr = lutil_strcopy( ptr, "add" ); 2048 2049 } else if ( ACL_LVL_IS_WDEL(mask) ) { 2050 ptr = lutil_strcopy( ptr, "delete" ); 2051 2052 } else if ( ACL_LVL_IS_MANAGE(mask) ) { 2053 ptr = lutil_strcopy( ptr, "manage" ); 2054 2055 } else { 2056 ptr = lutil_strcopy( ptr, "unknown" ); 2057 } 2058 2059 if ( !debug ) { 2060 *ptr = '\0'; 2061 return buf; 2062 } 2063 *ptr++ = '('; 2064 } 2065 2066 if( ACL_IS_ADDITIVE( mask ) ) { 2067 *ptr++ = '+'; 2068 2069 } else if( ACL_IS_SUBTRACTIVE( mask ) ) { 2070 *ptr++ = '-'; 2071 2072 } else { 2073 *ptr++ = '='; 2074 } 2075 2076 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_MANAGE) ) { 2077 none = 0; 2078 *ptr++ = 'm'; 2079 } 2080 2081 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WRITE) ) { 2082 none = 0; 2083 *ptr++ = 'w'; 2084 2085 } else if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WADD) ) { 2086 none = 0; 2087 *ptr++ = 'a'; 2088 2089 } else if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WDEL) ) { 2090 none = 0; 2091 *ptr++ = 'z'; 2092 } 2093 2094 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_READ) ) { 2095 none = 0; 2096 *ptr++ = 'r'; 2097 } 2098 2099 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_SEARCH) ) { 2100 none = 0; 2101 *ptr++ = 's'; 2102 } 2103 2104 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_COMPARE) ) { 2105 none = 0; 2106 *ptr++ = 'c'; 2107 } 2108 2109 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_AUTH) ) { 2110 none = 0; 2111 *ptr++ = 'x'; 2112 } 2113 2114 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_DISCLOSE) ) { 2115 none = 0; 2116 *ptr++ = 'd'; 2117 } 2118 2119 if ( none && ACL_PRIV_ISSET(mask, ACL_PRIV_NONE) ) { 2120 none = 0; 2121 *ptr++ = '0'; 2122 } 2123 2124 if ( none ) { 2125 ptr = buf; 2126 } 2127 2128 if ( ACL_IS_LEVEL( mask ) ) { 2129 *ptr++ = ')'; 2130 } 2131 2132 *ptr = '\0'; 2133 2134 return buf; 2135} 2136 2137slap_mask_t 2138str2accessmask( const char *str ) 2139{ 2140 slap_mask_t mask; 2141 2142 if( !ASCII_ALPHA(str[0]) ) { 2143 int i; 2144 2145 if ( str[0] == '=' ) { 2146 ACL_INIT(mask); 2147 2148 } else if( str[0] == '+' ) { 2149 ACL_PRIV_ASSIGN(mask, ACL_PRIV_ADDITIVE); 2150 2151 } else if( str[0] == '-' ) { 2152 ACL_PRIV_ASSIGN(mask, ACL_PRIV_SUBSTRACTIVE); 2153 2154 } else { 2155 ACL_INVALIDATE(mask); 2156 return mask; 2157 } 2158 2159 for( i=1; str[i] != '\0'; i++ ) { 2160 if( TOLOWER((unsigned char) str[i]) == 'm' ) { 2161 ACL_PRIV_SET(mask, ACL_PRIV_MANAGE); 2162 2163 } else if( TOLOWER((unsigned char) str[i]) == 'w' ) { 2164 ACL_PRIV_SET(mask, ACL_PRIV_WRITE); 2165 2166 } else if( TOLOWER((unsigned char) str[i]) == 'a' ) { 2167 ACL_PRIV_SET(mask, ACL_PRIV_WADD); 2168 2169 } else if( TOLOWER((unsigned char) str[i]) == 'z' ) { 2170 ACL_PRIV_SET(mask, ACL_PRIV_WDEL); 2171 2172 } else if( TOLOWER((unsigned char) str[i]) == 'r' ) { 2173 ACL_PRIV_SET(mask, ACL_PRIV_READ); 2174 2175 } else if( TOLOWER((unsigned char) str[i]) == 's' ) { 2176 ACL_PRIV_SET(mask, ACL_PRIV_SEARCH); 2177 2178 } else if( TOLOWER((unsigned char) str[i]) == 'c' ) { 2179 ACL_PRIV_SET(mask, ACL_PRIV_COMPARE); 2180 2181 } else if( TOLOWER((unsigned char) str[i]) == 'x' ) { 2182 ACL_PRIV_SET(mask, ACL_PRIV_AUTH); 2183 2184 } else if( TOLOWER((unsigned char) str[i]) == 'd' ) { 2185 ACL_PRIV_SET(mask, ACL_PRIV_DISCLOSE); 2186 2187 } else if( str[i] == '0' ) { 2188 ACL_PRIV_SET(mask, ACL_PRIV_NONE); 2189 2190 } else { 2191 ACL_INVALIDATE(mask); 2192 return mask; 2193 } 2194 } 2195 2196 return mask; 2197 } 2198 2199 if ( strcasecmp( str, "none" ) == 0 ) { 2200 ACL_LVL_ASSIGN_NONE(mask); 2201 2202 } else if ( strcasecmp( str, "disclose" ) == 0 ) { 2203 ACL_LVL_ASSIGN_DISCLOSE(mask); 2204 2205 } else if ( strcasecmp( str, "auth" ) == 0 ) { 2206 ACL_LVL_ASSIGN_AUTH(mask); 2207 2208 } else if ( strcasecmp( str, "compare" ) == 0 ) { 2209 ACL_LVL_ASSIGN_COMPARE(mask); 2210 2211 } else if ( strcasecmp( str, "search" ) == 0 ) { 2212 ACL_LVL_ASSIGN_SEARCH(mask); 2213 2214 } else if ( strcasecmp( str, "read" ) == 0 ) { 2215 ACL_LVL_ASSIGN_READ(mask); 2216 2217 } else if ( strcasecmp( str, "add" ) == 0 ) { 2218 ACL_LVL_ASSIGN_WADD(mask); 2219 2220 } else if ( strcasecmp( str, "delete" ) == 0 ) { 2221 ACL_LVL_ASSIGN_WDEL(mask); 2222 2223 } else if ( strcasecmp( str, "write" ) == 0 ) { 2224 ACL_LVL_ASSIGN_WRITE(mask); 2225 2226 } else if ( strcasecmp( str, "manage" ) == 0 ) { 2227 ACL_LVL_ASSIGN_MANAGE(mask); 2228 2229 } else { 2230 ACL_INVALIDATE( mask ); 2231 } 2232 2233 return mask; 2234} 2235 2236static int 2237acl_usage( void ) 2238{ 2239 char *access = 2240 "<access clause> ::= access to <what> " 2241 "[ by <who> [ <access> ] [ <control> ] ]+ \n"; 2242 char *what = 2243 "<what> ::= * | dn[.<dnstyle>=<DN>] [filter=<filter>] [attrs=<attrspec>]\n" 2244 "<attrspec> ::= <attrname> [val[/<matchingRule>][.<attrstyle>]=<value>] | <attrlist>\n" 2245 "<attrlist> ::= <attr> [ , <attrlist> ]\n" 2246 "<attr> ::= <attrname> | @<objectClass> | !<objectClass> | entry | children\n"; 2247 2248 char *who = 2249 "<who> ::= [ * | anonymous | users | self | dn[.<dnstyle>]=<DN> ]\n" 2250 "\t[ realanonymous | realusers | realself | realdn[.<dnstyle>]=<DN> ]\n" 2251 "\t[dnattr=<attrname>]\n" 2252 "\t[realdnattr=<attrname>]\n" 2253 "\t[group[/<objectclass>[/<attrname>]][.<style>]=<group>]\n" 2254 "\t[peername[.<peernamestyle>]=<peer>] [sockname[.<style>]=<name>]\n" 2255 "\t[domain[.<domainstyle>]=<domain>] [sockurl[.<style>]=<url>]\n" 2256#ifdef SLAP_DYNACL 2257 "\t[dynacl/<name>[/<options>][.<dynstyle>][=<pattern>]]\n" 2258#endif /* SLAP_DYNACL */ 2259 "\t[ssf=<n>] [transport_ssf=<n>] [tls_ssf=<n>] [sasl_ssf=<n>]\n" 2260 "<style> ::= exact | regex | base(Object)\n" 2261 "<dnstyle> ::= base(Object) | one(level) | sub(tree) | children | " 2262 "exact | regex\n" 2263 "<attrstyle> ::= exact | regex | base(Object) | one(level) | " 2264 "sub(tree) | children\n" 2265 "<peernamestyle> ::= exact | regex | ip | ipv6 | path\n" 2266 "<domainstyle> ::= exact | regex | base(Object) | sub(tree)\n" 2267 "<access> ::= [[real]self]{<level>|<priv>}\n" 2268 "<level> ::= none|disclose|auth|compare|search|read|{write|add|delete}|manage\n" 2269 "<priv> ::= {=|+|-}{0|d|x|c|s|r|{w|a|z}|m}+\n" 2270 "<control> ::= [ stop | continue | break ]\n" 2271#ifdef SLAP_DYNACL 2272#ifdef SLAPD_ACI_ENABLED 2273 "dynacl:\n" 2274 "\t<name>=ACI\t<pattern>=<attrname>\n" 2275#endif /* SLAPD_ACI_ENABLED */ 2276#endif /* ! SLAP_DYNACL */ 2277 ""; 2278 2279 Debug( LDAP_DEBUG_ANY, "%s%s%s\n", access, what, who ); 2280 2281 return 1; 2282} 2283 2284/* 2285 * Set pattern to a "normalized" DN from src. 2286 * At present it simply eats the (optional) space after 2287 * a RDN separator (,) 2288 * Eventually will evolve in a more complete normalization 2289 */ 2290static void 2291acl_regex_normalized_dn( 2292 const char *src, 2293 struct berval *pattern ) 2294{ 2295 char *str, *p; 2296 ber_len_t len; 2297 2298 str = ch_strdup( src ); 2299 len = strlen( src ); 2300 2301 for ( p = str; p && p[0]; p++ ) { 2302 /* escape */ 2303 if ( p[0] == '\\' && p[1] ) { 2304 /* 2305 * if escaping a hex pair we should 2306 * increment p twice; however, in that 2307 * case the second hex number does 2308 * no harm 2309 */ 2310 p++; 2311 } 2312 2313 if ( p[0] == ',' && p[1] == ' ' ) { 2314 char *q; 2315 2316 /* 2317 * too much space should be an error if we are pedantic 2318 */ 2319 for ( q = &p[2]; q[0] == ' '; q++ ) { 2320 /* DO NOTHING */ ; 2321 } 2322 AC_MEMCPY( p+1, q, len-(q-str)+1); 2323 } 2324 } 2325 pattern->bv_val = str; 2326 pattern->bv_len = p - str; 2327 2328 return; 2329} 2330 2331static void 2332split( 2333 char *line, 2334 int splitchar, 2335 char **left, 2336 char **right ) 2337{ 2338 *left = line; 2339 if ( (*right = strchr( line, splitchar )) != NULL ) { 2340 *((*right)++) = '\0'; 2341 } 2342} 2343 2344static void 2345access_append( Access **l, Access *a ) 2346{ 2347 for ( ; *l != NULL; l = &(*l)->a_next ) { 2348 ; /* Empty */ 2349 } 2350 2351 *l = a; 2352} 2353 2354void 2355acl_append( AccessControl **l, AccessControl *a, int pos ) 2356{ 2357 int i; 2358 2359 for (i=0 ; i != pos && *l != NULL; l = &(*l)->acl_next, i++ ) { 2360 ; /* Empty */ 2361 } 2362 if ( *l && a ) 2363 a->acl_next = *l; 2364 *l = a; 2365} 2366 2367static void 2368access_free( Access *a ) 2369{ 2370 if ( !BER_BVISNULL( &a->a_dn_pat ) ) { 2371 free( a->a_dn_pat.bv_val ); 2372 } 2373 if ( !BER_BVISNULL( &a->a_realdn_pat ) ) { 2374 free( a->a_realdn_pat.bv_val ); 2375 } 2376 if ( !BER_BVISNULL( &a->a_peername_pat ) ) { 2377 free( a->a_peername_pat.bv_val ); 2378 } 2379 if ( !BER_BVISNULL( &a->a_sockname_pat ) ) { 2380 free( a->a_sockname_pat.bv_val ); 2381 } 2382 if ( !BER_BVISNULL( &a->a_domain_pat ) ) { 2383 free( a->a_domain_pat.bv_val ); 2384 } 2385 if ( !BER_BVISNULL( &a->a_sockurl_pat ) ) { 2386 free( a->a_sockurl_pat.bv_val ); 2387 } 2388 if ( !BER_BVISNULL( &a->a_set_pat ) ) { 2389 free( a->a_set_pat.bv_val ); 2390 } 2391 if ( !BER_BVISNULL( &a->a_group_pat ) ) { 2392 free( a->a_group_pat.bv_val ); 2393 } 2394#ifdef SLAP_DYNACL 2395 if ( a->a_dynacl != NULL ) { 2396 slap_dynacl_t *da; 2397 for ( da = a->a_dynacl; da; ) { 2398 slap_dynacl_t *tmp = da; 2399 2400 da = da->da_next; 2401 2402 if ( tmp->da_destroy ) { 2403 tmp->da_destroy( tmp->da_private ); 2404 } 2405 2406 ch_free( tmp ); 2407 } 2408 } 2409#endif /* SLAP_DYNACL */ 2410 free( a ); 2411} 2412 2413void 2414acl_free( AccessControl *a ) 2415{ 2416 Access *n; 2417 AttributeName *an; 2418 2419 if ( a->acl_filter ) { 2420 filter_free( a->acl_filter ); 2421 } 2422 if ( !BER_BVISNULL( &a->acl_dn_pat ) ) { 2423 if ( a->acl_dn_style == ACL_STYLE_REGEX ) { 2424 regfree( &a->acl_dn_re ); 2425 } 2426 free ( a->acl_dn_pat.bv_val ); 2427 } 2428 if ( a->acl_attrs ) { 2429 for ( an = a->acl_attrs; !BER_BVISNULL( &an->an_name ); an++ ) { 2430 free( an->an_name.bv_val ); 2431 } 2432 free( a->acl_attrs ); 2433 2434 if ( a->acl_attrval_style == ACL_STYLE_REGEX ) { 2435 regfree( &a->acl_attrval_re ); 2436 } 2437 2438 if ( !BER_BVISNULL( &a->acl_attrval ) ) { 2439 ber_memfree( a->acl_attrval.bv_val ); 2440 } 2441 } 2442 for ( ; a->acl_access; a->acl_access = n ) { 2443 n = a->acl_access->a_next; 2444 access_free( a->acl_access ); 2445 } 2446 free( a ); 2447} 2448 2449void 2450acl_destroy( AccessControl *a ) 2451{ 2452 AccessControl *n; 2453 2454 for ( ; a; a = n ) { 2455 n = a->acl_next; 2456 acl_free( a ); 2457 } 2458 2459 if ( !BER_BVISNULL( &aclbuf ) ) { 2460 ch_free( aclbuf.bv_val ); 2461 BER_BVZERO( &aclbuf ); 2462 } 2463} 2464 2465char * 2466access2str( slap_access_t access ) 2467{ 2468 if ( access == ACL_NONE ) { 2469 return "none"; 2470 2471 } else if ( access == ACL_DISCLOSE ) { 2472 return "disclose"; 2473 2474 } else if ( access == ACL_AUTH ) { 2475 return "auth"; 2476 2477 } else if ( access == ACL_COMPARE ) { 2478 return "compare"; 2479 2480 } else if ( access == ACL_SEARCH ) { 2481 return "search"; 2482 2483 } else if ( access == ACL_READ ) { 2484 return "read"; 2485 2486 } else if ( access == ACL_WRITE ) { 2487 return "write"; 2488 2489 } else if ( access == ACL_WADD ) { 2490 return "add"; 2491 2492 } else if ( access == ACL_WDEL ) { 2493 return "delete"; 2494 2495 } else if ( access == ACL_MANAGE ) { 2496 return "manage"; 2497 2498 } 2499 2500 return "unknown"; 2501} 2502 2503slap_access_t 2504str2access( const char *str ) 2505{ 2506 if ( strcasecmp( str, "none" ) == 0 ) { 2507 return ACL_NONE; 2508 2509 } else if ( strcasecmp( str, "disclose" ) == 0 ) { 2510 return ACL_DISCLOSE; 2511 2512 } else if ( strcasecmp( str, "auth" ) == 0 ) { 2513 return ACL_AUTH; 2514 2515 } else if ( strcasecmp( str, "compare" ) == 0 ) { 2516 return ACL_COMPARE; 2517 2518 } else if ( strcasecmp( str, "search" ) == 0 ) { 2519 return ACL_SEARCH; 2520 2521 } else if ( strcasecmp( str, "read" ) == 0 ) { 2522 return ACL_READ; 2523 2524 } else if ( strcasecmp( str, "write" ) == 0 ) { 2525 return ACL_WRITE; 2526 2527 } else if ( strcasecmp( str, "add" ) == 0 ) { 2528 return ACL_WADD; 2529 2530 } else if ( strcasecmp( str, "delete" ) == 0 ) { 2531 return ACL_WDEL; 2532 2533 } else if ( strcasecmp( str, "manage" ) == 0 ) { 2534 return ACL_MANAGE; 2535 } 2536 2537 return( ACL_INVALID_ACCESS ); 2538} 2539 2540static char * 2541safe_strncopy( char *ptr, const char *src, size_t n, struct berval *buf ) 2542{ 2543 while ( ptr + n >= buf->bv_val + buf->bv_len ) { 2544 char *tmp = ch_realloc( buf->bv_val, 2*buf->bv_len ); 2545 if ( tmp == NULL ) { 2546 return NULL; 2547 } 2548 ptr = tmp + (ptr - buf->bv_val); 2549 buf->bv_val = tmp; 2550 buf->bv_len *= 2; 2551 } 2552 2553 return lutil_strncopy( ptr, src, n ); 2554} 2555 2556static char * 2557safe_strcopy( char *ptr, const char *s, struct berval *buf ) 2558{ 2559 size_t n = strlen( s ); 2560 2561 return safe_strncopy( ptr, s, n, buf ); 2562} 2563 2564static char * 2565safe_strbvcopy( char *ptr, const struct berval *bv, struct berval *buf ) 2566{ 2567 return safe_strncopy( ptr, bv->bv_val, bv->bv_len, buf ); 2568} 2569 2570#define acl_safe_strcopy( ptr, s ) safe_strcopy( (ptr), (s), &aclbuf ) 2571#define acl_safe_strncopy( ptr, s, n ) safe_strncopy( (ptr), (s), (n), &aclbuf ) 2572#define acl_safe_strbvcopy( ptr, bv ) safe_strbvcopy( (ptr), (bv), &aclbuf ) 2573 2574static char * 2575dnaccess2text( slap_dn_access *bdn, char *ptr, int is_realdn ) 2576{ 2577 *ptr++ = ' '; 2578 2579 if ( is_realdn ) { 2580 ptr = acl_safe_strcopy( ptr, "real" ); 2581 } 2582 2583 if ( ber_bvccmp( &bdn->a_pat, '*' ) || 2584 bdn->a_style == ACL_STYLE_ANONYMOUS || 2585 bdn->a_style == ACL_STYLE_USERS || 2586 bdn->a_style == ACL_STYLE_SELF ) 2587 { 2588 if ( is_realdn ) { 2589 assert( ! ber_bvccmp( &bdn->a_pat, '*' ) ); 2590 } 2591 2592 ptr = acl_safe_strbvcopy( ptr, &bdn->a_pat ); 2593 if ( bdn->a_style == ACL_STYLE_SELF && bdn->a_self_level != 0 ) { 2594 char buf[SLAP_TEXT_BUFLEN]; 2595 int n = snprintf( buf, sizeof(buf), ".level{%d}", bdn->a_self_level ); 2596 if ( n > 0 ) { 2597 ptr = acl_safe_strncopy( ptr, buf, n ); 2598 } /* else ? */ 2599 } 2600 2601 } else { 2602 ptr = acl_safe_strcopy( ptr, "dn." ); 2603 if ( bdn->a_style == ACL_STYLE_BASE ) 2604 ptr = acl_safe_strcopy( ptr, style_base ); 2605 else 2606 ptr = acl_safe_strcopy( ptr, style_strings[bdn->a_style] ); 2607 if ( bdn->a_style == ACL_STYLE_LEVEL ) { 2608 char buf[SLAP_TEXT_BUFLEN]; 2609 int n = snprintf( buf, sizeof(buf), "{%d}", bdn->a_level ); 2610 if ( n > 0 ) { 2611 ptr = acl_safe_strncopy( ptr, buf, n ); 2612 } /* else ? */ 2613 } 2614 if ( bdn->a_expand ) { 2615 ptr = acl_safe_strcopy( ptr, ",expand" ); 2616 } 2617 ptr = acl_safe_strcopy( ptr, "=\"" ); 2618 ptr = acl_safe_strbvcopy( ptr, &bdn->a_pat ); 2619 ptr = acl_safe_strcopy( ptr, "\"" ); 2620 } 2621 return ptr; 2622} 2623 2624static char * 2625access2text( Access *b, char *ptr ) 2626{ 2627 char maskbuf[ACCESSMASK_MAXLEN]; 2628 2629 ptr = acl_safe_strcopy( ptr, "\tby" ); 2630 2631 if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) { 2632 ptr = dnaccess2text( &b->a_dn, ptr, 0 ); 2633 } 2634 if ( b->a_dn_at ) { 2635 ptr = acl_safe_strcopy( ptr, " dnattr=" ); 2636 ptr = acl_safe_strbvcopy( ptr, &b->a_dn_at->ad_cname ); 2637 } 2638 2639 if ( !BER_BVISEMPTY( &b->a_realdn_pat ) ) { 2640 ptr = dnaccess2text( &b->a_realdn, ptr, 1 ); 2641 } 2642 if ( b->a_realdn_at ) { 2643 ptr = acl_safe_strcopy( ptr, " realdnattr=" ); 2644 ptr = acl_safe_strbvcopy( ptr, &b->a_realdn_at->ad_cname ); 2645 } 2646 2647 if ( !BER_BVISEMPTY( &b->a_group_pat ) ) { 2648 ptr = acl_safe_strcopy( ptr, " group/" ); 2649 ptr = acl_safe_strcopy( ptr, b->a_group_oc ? 2650 b->a_group_oc->soc_cname.bv_val : SLAPD_GROUP_CLASS ); 2651 ptr = acl_safe_strcopy( ptr, "/" ); 2652 ptr = acl_safe_strcopy( ptr, b->a_group_at ? 2653 b->a_group_at->ad_cname.bv_val : SLAPD_GROUP_ATTR ); 2654 ptr = acl_safe_strcopy( ptr, "." ); 2655 ptr = acl_safe_strcopy( ptr, style_strings[b->a_group_style] ); 2656 ptr = acl_safe_strcopy( ptr, "=\"" ); 2657 ptr = acl_safe_strbvcopy( ptr, &b->a_group_pat ); 2658 ptr = acl_safe_strcopy( ptr, "\"" ); 2659 } 2660 2661 if ( !BER_BVISEMPTY( &b->a_peername_pat ) ) { 2662 ptr = acl_safe_strcopy( ptr, " peername" ); 2663 ptr = acl_safe_strcopy( ptr, "." ); 2664 ptr = acl_safe_strcopy( ptr, style_strings[b->a_peername_style] ); 2665 ptr = acl_safe_strcopy( ptr, "=\"" ); 2666 ptr = acl_safe_strbvcopy( ptr, &b->a_peername_pat ); 2667 ptr = acl_safe_strcopy( ptr, "\"" ); 2668 } 2669 2670 if ( !BER_BVISEMPTY( &b->a_sockname_pat ) ) { 2671 ptr = acl_safe_strcopy( ptr, " sockname" ); 2672 ptr = acl_safe_strcopy( ptr, "." ); 2673 ptr = acl_safe_strcopy( ptr, style_strings[b->a_sockname_style] ); 2674 ptr = acl_safe_strcopy( ptr, "=\"" ); 2675 ptr = acl_safe_strbvcopy( ptr, &b->a_sockname_pat ); 2676 ptr = acl_safe_strcopy( ptr, "\"" ); 2677 } 2678 2679 if ( !BER_BVISEMPTY( &b->a_domain_pat ) ) { 2680 ptr = acl_safe_strcopy( ptr, " domain" ); 2681 ptr = acl_safe_strcopy( ptr, "." ); 2682 ptr = acl_safe_strcopy( ptr, style_strings[b->a_domain_style] ); 2683 if ( b->a_domain_expand ) { 2684 ptr = acl_safe_strcopy( ptr, ",expand" ); 2685 } 2686 ptr = acl_safe_strcopy( ptr, "=" ); 2687 ptr = acl_safe_strbvcopy( ptr, &b->a_domain_pat ); 2688 } 2689 2690 if ( !BER_BVISEMPTY( &b->a_sockurl_pat ) ) { 2691 ptr = acl_safe_strcopy( ptr, " sockurl" ); 2692 ptr = acl_safe_strcopy( ptr, "." ); 2693 ptr = acl_safe_strcopy( ptr, style_strings[b->a_sockurl_style] ); 2694 ptr = acl_safe_strcopy( ptr, "=\"" ); 2695 ptr = acl_safe_strbvcopy( ptr, &b->a_sockurl_pat ); 2696 ptr = acl_safe_strcopy( ptr, "\"" ); 2697 } 2698 2699 if ( !BER_BVISEMPTY( &b->a_set_pat ) ) { 2700 ptr = acl_safe_strcopy( ptr, " set" ); 2701 ptr = acl_safe_strcopy( ptr, "." ); 2702 ptr = acl_safe_strcopy( ptr, style_strings[b->a_set_style] ); 2703 ptr = acl_safe_strcopy( ptr, "=\"" ); 2704 ptr = acl_safe_strbvcopy( ptr, &b->a_set_pat ); 2705 ptr = acl_safe_strcopy( ptr, "\"" ); 2706 } 2707 2708#ifdef SLAP_DYNACL 2709 if ( b->a_dynacl ) { 2710 slap_dynacl_t *da; 2711 2712 for ( da = b->a_dynacl; da; da = da->da_next ) { 2713 if ( da->da_unparse ) { 2714 struct berval bv = BER_BVNULL; 2715 (void)( *da->da_unparse )( da->da_private, &bv ); 2716 assert( !BER_BVISNULL( &bv ) ); 2717 ptr = acl_safe_strbvcopy( ptr, &bv ); 2718 ch_free( bv.bv_val ); 2719 } 2720 } 2721 } 2722#endif /* SLAP_DYNACL */ 2723 2724 /* Security Strength Factors */ 2725 if ( b->a_authz.sai_ssf ) { 2726 char buf[SLAP_TEXT_BUFLEN]; 2727 int n = snprintf( buf, sizeof(buf), " ssf=%u", 2728 b->a_authz.sai_ssf ); 2729 ptr = acl_safe_strncopy( ptr, buf, n ); 2730 } 2731 if ( b->a_authz.sai_transport_ssf ) { 2732 char buf[SLAP_TEXT_BUFLEN]; 2733 int n = snprintf( buf, sizeof(buf), " transport_ssf=%u", 2734 b->a_authz.sai_transport_ssf ); 2735 ptr = acl_safe_strncopy( ptr, buf, n ); 2736 } 2737 if ( b->a_authz.sai_tls_ssf ) { 2738 char buf[SLAP_TEXT_BUFLEN]; 2739 int n = snprintf( buf, sizeof(buf), " tls_ssf=%u", 2740 b->a_authz.sai_tls_ssf ); 2741 ptr = acl_safe_strncopy( ptr, buf, n ); 2742 } 2743 if ( b->a_authz.sai_sasl_ssf ) { 2744 char buf[SLAP_TEXT_BUFLEN]; 2745 int n = snprintf( buf, sizeof(buf), " sasl_ssf=%u", 2746 b->a_authz.sai_sasl_ssf ); 2747 ptr = acl_safe_strncopy( ptr, buf, n ); 2748 } 2749 2750 ptr = acl_safe_strcopy( ptr, " " ); 2751 if ( b->a_dn_self ) { 2752 ptr = acl_safe_strcopy( ptr, "self" ); 2753 } else if ( b->a_realdn_self ) { 2754 ptr = acl_safe_strcopy( ptr, "realself" ); 2755 } 2756 ptr = acl_safe_strcopy( ptr, accessmask2str( b->a_access_mask, maskbuf, 0 )); 2757 if ( !maskbuf[0] ) ptr--; 2758 2759 if( b->a_type == ACL_BREAK ) { 2760 ptr = acl_safe_strcopy( ptr, " break" ); 2761 2762 } else if( b->a_type == ACL_CONTINUE ) { 2763 ptr = acl_safe_strcopy( ptr, " continue" ); 2764 2765 } else if( b->a_type != ACL_STOP ) { 2766 ptr = acl_safe_strcopy( ptr, " unknown-control" ); 2767 } else { 2768 if ( !maskbuf[0] ) ptr = acl_safe_strcopy( ptr, " stop" ); 2769 } 2770 ptr = acl_safe_strcopy( ptr, "\n" ); 2771 2772 return ptr; 2773} 2774 2775void 2776acl_unparse( AccessControl *a, struct berval *bv ) 2777{ 2778 Access *b; 2779 char *ptr; 2780 int to = 0; 2781 2782 if ( BER_BVISNULL( &aclbuf ) ) { 2783 aclbuf.bv_val = ch_malloc( ACLBUF_CHUNKSIZE ); 2784 aclbuf.bv_len = ACLBUF_CHUNKSIZE; 2785 } 2786 2787 bv->bv_len = 0; 2788 2789 ptr = aclbuf.bv_val; 2790 2791 ptr = acl_safe_strcopy( ptr, "to" ); 2792 if ( !BER_BVISNULL( &a->acl_dn_pat ) ) { 2793 to++; 2794 ptr = acl_safe_strcopy( ptr, " dn." ); 2795 if ( a->acl_dn_style == ACL_STYLE_BASE ) 2796 ptr = acl_safe_strcopy( ptr, style_base ); 2797 else 2798 ptr = acl_safe_strcopy( ptr, style_strings[a->acl_dn_style] ); 2799 ptr = acl_safe_strcopy( ptr, "=\"" ); 2800 ptr = acl_safe_strbvcopy( ptr, &a->acl_dn_pat ); 2801 ptr = acl_safe_strcopy( ptr, "\"\n" ); 2802 } 2803 2804 if ( a->acl_filter != NULL ) { 2805 struct berval fbv = BER_BVNULL; 2806 2807 to++; 2808 filter2bv( a->acl_filter, &fbv ); 2809 ptr = acl_safe_strcopy( ptr, " filter=\"" ); 2810 ptr = acl_safe_strbvcopy( ptr, &fbv ); 2811 ptr = acl_safe_strcopy( ptr, "\"\n" ); 2812 ch_free( fbv.bv_val ); 2813 } 2814 2815 if ( a->acl_attrs != NULL ) { 2816 int first = 1; 2817 AttributeName *an; 2818 to++; 2819 2820 ptr = acl_safe_strcopy( ptr, " attrs=" ); 2821 for ( an = a->acl_attrs; an && !BER_BVISNULL( &an->an_name ); an++ ) { 2822 if ( ! first ) ptr = acl_safe_strcopy( ptr, ","); 2823 if (an->an_oc) { 2824 ptr = acl_safe_strcopy( ptr, ( an->an_flags & SLAP_AN_OCEXCLUDE ) ? "!" : "@" ); 2825 ptr = acl_safe_strbvcopy( ptr, &an->an_oc->soc_cname ); 2826 2827 } else { 2828 ptr = acl_safe_strbvcopy( ptr, &an->an_name ); 2829 } 2830 first = 0; 2831 } 2832 ptr = acl_safe_strcopy( ptr, "\n" ); 2833 } 2834 2835 if ( !BER_BVISNULL( &a->acl_attrval ) ) { 2836 to++; 2837 ptr = acl_safe_strcopy( ptr, " val." ); 2838 if ( a->acl_attrval_style == ACL_STYLE_BASE && 2839 a->acl_attrs[0].an_desc->ad_type->sat_syntax == 2840 slap_schema.si_syn_distinguishedName ) 2841 ptr = acl_safe_strcopy( ptr, style_base ); 2842 else 2843 ptr = acl_safe_strcopy( ptr, style_strings[a->acl_attrval_style] ); 2844 ptr = acl_safe_strcopy( ptr, "=\"" ); 2845 ptr = acl_safe_strbvcopy( ptr, &a->acl_attrval ); 2846 ptr = acl_safe_strcopy( ptr, "\"\n" ); 2847 } 2848 2849 if ( !to ) { 2850 ptr = acl_safe_strcopy( ptr, " *\n" ); 2851 } 2852 2853 for ( b = a->acl_access; b != NULL; b = b->a_next ) { 2854 ptr = access2text( b, ptr ); 2855 } 2856 *ptr = '\0'; 2857 bv->bv_val = aclbuf.bv_val; 2858 bv->bv_len = ptr - bv->bv_val; 2859} 2860 2861#ifdef LDAP_DEBUG 2862static void 2863print_acl( Backend *be, AccessControl *a ) 2864{ 2865 struct berval bv; 2866 2867 acl_unparse( a, &bv ); 2868 fprintf( stderr, "%s ACL: access %s\n", 2869 be == NULL ? "Global" : "Backend", bv.bv_val ); 2870} 2871#endif /* LDAP_DEBUG */ 2872