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