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