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