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