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