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