1 /* acl.c - routines to parse and check acl's */ 2 /* $OpenLDAP: pkg/ldap/servers/slapd/acl.c,v 1.303.2.16 2008/05/20 00:08:13 quanah Exp $ */ 3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2008 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16 /* Portions Copyright (c) 1995 Regents of the University of Michigan. 17 * All rights reserved. 18 * 19 * Redistribution and use in source and binary forms are permitted 20 * provided that this notice is preserved and that due credit is given 21 * to the University of Michigan at Ann Arbor. The name of the University 22 * may not be used to endorse or promote products derived from this 23 * software without specific prior written permission. This software 24 * is provided ``as is'' without express or implied warranty. 25 */ 26 27 #include "portable.h" 28 29 #include <stdio.h> 30 31 #include <ac/regex.h> 32 #include <ac/socket.h> 33 #include <ac/string.h> 34 35 #include "slap.h" 36 #include "sets.h" 37 #include "lber_pvt.h" 38 #include "lutil.h" 39 40 #define ACL_BUF_SIZE 1024 /* use most appropriate size */ 41 42 static const struct berval acl_bv_ip_eq = BER_BVC( "IP=" ); 43 #ifdef LDAP_PF_INET6 44 static const struct berval acl_bv_ipv6_eq = BER_BVC( "IP=[" ); 45 #endif /* LDAP_PF_INET6 */ 46 #ifdef LDAP_PF_LOCAL 47 static const struct berval acl_bv_path_eq = BER_BVC("PATH="); 48 #endif /* LDAP_PF_LOCAL */ 49 50 static AccessControl * slap_acl_get( 51 AccessControl *ac, int *count, 52 Operation *op, Entry *e, 53 AttributeDescription *desc, 54 struct berval *val, 55 int nmatch, regmatch_t *matches, 56 AccessControlState *state ); 57 58 static slap_control_t slap_acl_mask( 59 AccessControl *ac, slap_mask_t *mask, 60 Operation *op, Entry *e, 61 AttributeDescription *desc, 62 struct berval *val, 63 int nmatch, 64 regmatch_t *matches, 65 int count, 66 AccessControlState *state ); 67 68 static int regex_matches( 69 struct berval *pat, char *str, char *buf, 70 int nmatch, regmatch_t *matches); 71 72 typedef struct AclSetCookie { 73 SetCookie asc_cookie; 74 #define asc_op asc_cookie.set_op 75 Entry *asc_e; 76 } AclSetCookie; 77 78 SLAP_SET_GATHER acl_set_gather; 79 SLAP_SET_GATHER acl_set_gather2; 80 81 /* 82 * access_allowed - check whether op->o_ndn is allowed the requested access 83 * to entry e, attribute attr, value val. if val is null, access to 84 * the whole attribute is assumed (all values). 85 * 86 * This routine loops through all access controls and calls 87 * slap_acl_mask() on each applicable access control. 88 * The loop exits when a definitive answer is reached or 89 * or no more controls remain. 90 * 91 * returns: 92 * 0 access denied 93 * 1 access granted 94 * 95 * Notes: 96 * - can be legally called with op == NULL 97 * - can be legally called with op->o_bd == NULL 98 */ 99 100 int 101 slap_access_always_allowed( 102 Operation *op, 103 Entry *e, 104 AttributeDescription *desc, 105 struct berval *val, 106 slap_access_t access, 107 AccessControlState *state, 108 slap_mask_t *maskp ) 109 { 110 assert( maskp != NULL ); 111 112 /* assign all */ 113 ACL_LVL_ASSIGN_MANAGE( *maskp ); 114 115 return 1; 116 } 117 118 int 119 slap_access_allowed( 120 Operation *op, 121 Entry *e, 122 AttributeDescription *desc, 123 struct berval *val, 124 slap_access_t access, 125 AccessControlState *state, 126 slap_mask_t *maskp ) 127 { 128 int ret = 1; 129 int count; 130 AccessControl *a = NULL; 131 132 #ifdef LDAP_DEBUG 133 char accessmaskbuf[ACCESSMASK_MAXLEN]; 134 #endif 135 slap_mask_t mask; 136 slap_control_t control; 137 slap_access_t access_level; 138 const char *attr; 139 regmatch_t matches[MAXREMATCHES]; 140 141 assert( op != NULL ); 142 assert( e != NULL ); 143 assert( desc != NULL ); 144 assert( maskp != NULL ); 145 146 access_level = ACL_LEVEL( access ); 147 attr = desc->ad_cname.bv_val; 148 149 assert( attr != NULL ); 150 151 ACL_INIT( mask ); 152 153 /* grant database root access */ 154 if ( be_isroot( op ) ) { 155 Debug( LDAP_DEBUG_ACL, "<= root access granted\n", 0, 0, 0 ); 156 mask = ACL_LVL_MANAGE; 157 goto done; 158 } 159 160 /* 161 * no-user-modification operational attributes are ignored 162 * by ACL_WRITE checking as any found here are not provided 163 * by the user 164 * 165 * NOTE: but they are not ignored for ACL_MANAGE, because 166 * if we get here it means a non-root user is trying to 167 * manage data, so we need to check its privileges. 168 */ 169 if ( access_level == ACL_WRITE 170 && is_at_no_user_mod( desc->ad_type ) 171 && desc != slap_schema.si_ad_entry 172 && desc != slap_schema.si_ad_children ) 173 { 174 Debug( LDAP_DEBUG_ACL, "NoUserMod Operational attribute:" 175 " %s access granted\n", 176 attr, 0, 0 ); 177 goto done; 178 } 179 180 /* use backend default access if no backend acls */ 181 if ( op->o_bd->be_acl == NULL ) { 182 int i; 183 184 Debug( LDAP_DEBUG_ACL, 185 "=> slap_access_allowed: backend default %s " 186 "access %s to \"%s\"\n", 187 access2str( access ), 188 op->o_bd->be_dfltaccess >= access_level ? "granted" : "denied", 189 op->o_dn.bv_val ? op->o_dn.bv_val : "(anonymous)" ); 190 ret = op->o_bd->be_dfltaccess >= access_level; 191 192 mask = ACL_PRIV_LEVEL; 193 for ( i = ACL_NONE; i <= op->o_bd->be_dfltaccess; i++ ) { 194 ACL_PRIV_SET( mask, ACL_ACCESS2PRIV( i ) ); 195 } 196 197 goto done; 198 } 199 200 ret = 0; 201 control = ACL_BREAK; 202 203 if ( state && state->as_vd_ad == desc ) { 204 a = state->as_vd_acl; 205 count = state->as_vd_acl_count; 206 207 } else { 208 if ( state ) state->as_vi_acl = NULL; 209 a = NULL; 210 count = 0; 211 } 212 ACL_PRIV_ASSIGN( mask, *maskp ); 213 memset( matches, '\0', sizeof( matches ) ); 214 215 while ( ( a = slap_acl_get( a, &count, op, e, desc, val, 216 MAXREMATCHES, matches, state ) ) != NULL ) 217 { 218 int i; 219 220 for ( i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++ ) { 221 Debug( LDAP_DEBUG_ACL, "=> match[%d]: %d %d ", i, 222 (int)matches[i].rm_so, (int)matches[i].rm_eo ); 223 if ( matches[i].rm_so <= matches[0].rm_eo ) { 224 int n; 225 for ( n = matches[i].rm_so; n < matches[i].rm_eo; n++ ) { 226 Debug( LDAP_DEBUG_ACL, "%c", e->e_ndn[n], 0, 0 ); 227 } 228 } 229 Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 ); 230 } 231 232 if ( state ) { 233 if ( state->as_vi_acl == a && 234 ( state->as_recorded & ACL_STATE_RECORDED_NV ) ) 235 { 236 Debug( LDAP_DEBUG_ACL, 237 "=> slap_access_allowed: result was in cache (%s)\n", 238 attr, 0, 0 ); 239 ret = state->as_result; 240 goto done; 241 } else { 242 Debug( LDAP_DEBUG_ACL, 243 "=> slap_access_allowed: result not in cache (%s)\n", 244 attr, 0, 0 ); 245 } 246 } 247 248 control = slap_acl_mask( a, &mask, op, 249 e, desc, val, MAXREMATCHES, matches, count, state ); 250 251 if ( control != ACL_BREAK ) { 252 break; 253 } 254 255 memset( matches, '\0', sizeof( matches ) ); 256 } 257 258 if ( ACL_IS_INVALID( mask ) ) { 259 Debug( LDAP_DEBUG_ACL, 260 "=> slap_access_allowed: \"%s\" (%s) invalid!\n", 261 e->e_dn, attr, 0 ); 262 ACL_PRIV_ASSIGN( mask, *maskp ); 263 264 } else if ( control == ACL_BREAK ) { 265 Debug( LDAP_DEBUG_ACL, 266 "=> slap_access_allowed: no more rules\n", 0, 0, 0 ); 267 268 goto done; 269 } 270 271 ret = ACL_GRANT( mask, access ); 272 273 Debug( LDAP_DEBUG_ACL, 274 "=> slap_access_allowed: %s access %s by %s\n", 275 access2str( access ), ret ? "granted" : "denied", 276 accessmask2str( mask, accessmaskbuf, 1 ) ); 277 278 done: 279 ACL_PRIV_ASSIGN( *maskp, mask ); 280 return ret; 281 } 282 283 int 284 fe_access_allowed( 285 Operation *op, 286 Entry *e, 287 AttributeDescription *desc, 288 struct berval *val, 289 slap_access_t access, 290 AccessControlState *state, 291 slap_mask_t *maskp ) 292 { 293 BackendDB *be_orig; 294 int rc; 295 296 /* 297 * NOTE: control gets here if FIXME 298 * if an appropriate backend cannot be selected for the operation, 299 * we assume that the frontend should handle this 300 * FIXME: should select_backend() take care of this, 301 * and return frontendDB instead of NULL? maybe for some value 302 * of the flags? 303 */ 304 be_orig = op->o_bd; 305 306 if ( op->o_bd == NULL ) { 307 op->o_bd = select_backend( &op->o_req_ndn, 0 ); 308 if ( op->o_bd == NULL ) 309 op->o_bd = frontendDB; 310 } 311 rc = slap_access_allowed( op, e, desc, val, access, state, maskp ); 312 op->o_bd = be_orig; 313 314 return rc; 315 } 316 317 int 318 access_allowed_mask( 319 Operation *op, 320 Entry *e, 321 AttributeDescription *desc, 322 struct berval *val, 323 slap_access_t access, 324 AccessControlState *state, 325 slap_mask_t *maskp ) 326 { 327 int ret = 1; 328 AccessControl *a = NULL; 329 int be_null = 0; 330 331 #ifdef LDAP_DEBUG 332 char accessmaskbuf[ACCESSMASK_MAXLEN]; 333 #endif 334 slap_mask_t mask; 335 slap_access_t access_level; 336 const char *attr; 337 static AccessControlState state_init = ACL_STATE_INIT; 338 339 assert( e != NULL ); 340 assert( desc != NULL ); 341 342 access_level = ACL_LEVEL( access ); 343 344 assert( access_level > ACL_NONE ); 345 346 ACL_INIT( mask ); 347 if ( maskp ) ACL_INVALIDATE( *maskp ); 348 349 attr = desc->ad_cname.bv_val; 350 351 assert( attr != NULL ); 352 353 if ( op ) { 354 if ( op->o_acl_priv != ACL_NONE ) { 355 access = op->o_acl_priv; 356 357 } else if ( op->o_is_auth_check && 358 ( access_level == ACL_SEARCH || access_level == ACL_READ ) ) 359 { 360 access = ACL_AUTH; 361 362 } else if ( get_relax( op ) && access_level == ACL_WRITE && 363 desc == slap_schema.si_ad_entry ) 364 { 365 access = ACL_MANAGE; 366 } 367 } 368 369 if ( state ) { 370 if ( state->as_vd_ad == desc ) { 371 if ( ( state->as_recorded & ACL_STATE_RECORDED_NV ) && 372 val == NULL ) 373 { 374 return state->as_result; 375 376 } 377 } else { 378 *state = state_init; 379 } 380 } 381 382 Debug( LDAP_DEBUG_ACL, 383 "=> access_allowed: %s access to \"%s\" \"%s\" requested\n", 384 access2str( access ), e->e_dn, attr ); 385 386 if ( op == NULL ) { 387 /* no-op call */ 388 goto done; 389 } 390 391 if ( op->o_bd == NULL ) { 392 op->o_bd = LDAP_STAILQ_FIRST( &backendDB ); 393 be_null = 1; 394 395 /* FIXME: experimental; use first backend rules 396 * iff there is no global_acl (ITS#3100) 397 */ 398 if ( frontendDB->be_acl != NULL ) { 399 op->o_bd = frontendDB; 400 } 401 } 402 assert( op->o_bd != NULL ); 403 404 /* this is enforced in backend_add() */ 405 if ( op->o_bd->bd_info->bi_access_allowed ) { 406 /* delegate to backend */ 407 ret = op->o_bd->bd_info->bi_access_allowed( op, e, 408 desc, val, access, state, &mask ); 409 410 } else { 411 /* use default (but pass through frontend 412 * for global ACL overlays) */ 413 ret = frontendDB->bd_info->bi_access_allowed( op, e, 414 desc, val, access, state, &mask ); 415 } 416 417 if ( !ret ) { 418 if ( ACL_IS_INVALID( mask ) ) { 419 Debug( LDAP_DEBUG_ACL, 420 "=> access_allowed: \"%s\" (%s) invalid!\n", 421 e->e_dn, attr, 0 ); 422 ACL_INIT( mask ); 423 424 } else { 425 Debug( LDAP_DEBUG_ACL, 426 "=> access_allowed: no more rules\n", 0, 0, 0 ); 427 428 goto done; 429 } 430 } 431 432 Debug( LDAP_DEBUG_ACL, 433 "=> access_allowed: %s access %s by %s\n", 434 access2str( access ), ret ? "granted" : "denied", 435 accessmask2str( mask, accessmaskbuf, 1 ) ); 436 437 done: 438 if ( state != NULL ) { 439 /* If not value-dependent, save ACL in case of more attrs */ 440 if ( !( state->as_recorded & ACL_STATE_RECORDED_VD ) ) { 441 state->as_vi_acl = a; 442 state->as_result = ret; 443 } 444 state->as_recorded |= ACL_STATE_RECORDED; 445 state->as_vd_ad = desc; 446 } 447 if ( be_null ) op->o_bd = NULL; 448 if ( maskp ) ACL_PRIV_ASSIGN( *maskp, mask ); 449 return ret; 450 } 451 452 453 /* 454 * slap_acl_get - return the acl applicable to entry e, attribute 455 * attr. the acl returned is suitable for use in subsequent calls to 456 * acl_access_allowed(). 457 */ 458 459 static AccessControl * 460 slap_acl_get( 461 AccessControl *a, 462 int *count, 463 Operation *op, 464 Entry *e, 465 AttributeDescription *desc, 466 struct berval *val, 467 int nmatch, 468 regmatch_t *matches, 469 AccessControlState *state ) 470 { 471 const char *attr; 472 int dnlen, patlen; 473 AccessControl *prev; 474 475 assert( e != NULL ); 476 assert( count != NULL ); 477 assert( desc != NULL ); 478 479 attr = desc->ad_cname.bv_val; 480 481 assert( attr != NULL ); 482 483 if( a == NULL ) { 484 if( op->o_bd == NULL ) { 485 a = frontendDB->be_acl; 486 } else { 487 a = op->o_bd->be_acl; 488 } 489 prev = NULL; 490 491 assert( a != NULL ); 492 493 } else { 494 prev = a; 495 a = a->acl_next; 496 } 497 498 dnlen = e->e_nname.bv_len; 499 500 for ( ; a != NULL; prev = a, a = a->acl_next ) { 501 (*count) ++; 502 503 if ( a->acl_dn_pat.bv_len || ( a->acl_dn_style != ACL_STYLE_REGEX )) { 504 if ( a->acl_dn_style == ACL_STYLE_REGEX ) { 505 Debug( LDAP_DEBUG_ACL, "=> dnpat: [%d] %s nsub: %d\n", 506 *count, a->acl_dn_pat.bv_val, (int) a->acl_dn_re.re_nsub ); 507 if (regexec(&a->acl_dn_re, e->e_ndn, nmatch, matches, 0)) 508 continue; 509 510 } else { 511 Debug( LDAP_DEBUG_ACL, "=> dn: [%d] %s\n", 512 *count, a->acl_dn_pat.bv_val, 0 ); 513 patlen = a->acl_dn_pat.bv_len; 514 if ( dnlen < patlen ) 515 continue; 516 517 if ( a->acl_dn_style == ACL_STYLE_BASE ) { 518 /* base dn -- entire object DN must match */ 519 if ( dnlen != patlen ) 520 continue; 521 522 } else if ( a->acl_dn_style == ACL_STYLE_ONE ) { 523 ber_len_t rdnlen = 0; 524 int sep = 0; 525 526 if ( dnlen <= patlen ) 527 continue; 528 529 if ( patlen > 0 ) { 530 if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) ) 531 continue; 532 sep = 1; 533 } 534 535 rdnlen = dn_rdnlen( NULL, &e->e_nname ); 536 if ( rdnlen != dnlen - patlen - sep ) 537 continue; 538 539 } else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) { 540 if ( dnlen > patlen && !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) ) 541 continue; 542 543 } else if ( a->acl_dn_style == ACL_STYLE_CHILDREN ) { 544 if ( dnlen <= patlen ) 545 continue; 546 if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) ) 547 continue; 548 } 549 550 if ( strcmp( a->acl_dn_pat.bv_val, e->e_ndn + dnlen - patlen ) != 0 ) 551 continue; 552 } 553 554 Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] matched\n", 555 *count, 0, 0 ); 556 } 557 558 if ( a->acl_attrs && !ad_inlist( desc, a->acl_attrs ) ) { 559 matches[0].rm_so = matches[0].rm_eo = -1; 560 continue; 561 } 562 563 /* Is this ACL only for a specific value? */ 564 if ( a->acl_attrval.bv_len ) { 565 if ( val == NULL ) { 566 continue; 567 } 568 569 if( state && !( state->as_recorded & ACL_STATE_RECORDED_VD )) { 570 state->as_recorded |= ACL_STATE_RECORDED_VD; 571 state->as_vd_acl = prev; 572 state->as_vd_acl_count = *count - 1; 573 } 574 575 if ( a->acl_attrval_style == ACL_STYLE_REGEX ) { 576 Debug( LDAP_DEBUG_ACL, 577 "acl_get: valpat %s\n", 578 a->acl_attrval.bv_val, 0, 0 ); 579 if ( regexec( &a->acl_attrval_re, val->bv_val, 0, NULL, 0 ) ) 580 { 581 continue; 582 } 583 584 } else { 585 int match = 0; 586 const char *text; 587 Debug( LDAP_DEBUG_ACL, 588 "acl_get: val %s\n", 589 a->acl_attrval.bv_val, 0, 0 ); 590 591 if ( a->acl_attrs[0].an_desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) { 592 if (value_match( &match, desc, 593 a->acl_attrval_mr, 0, 594 val, &a->acl_attrval, &text ) != LDAP_SUCCESS || 595 match ) 596 continue; 597 598 } else { 599 int patlen, vdnlen; 600 601 patlen = a->acl_attrval.bv_len; 602 vdnlen = val->bv_len; 603 604 if ( vdnlen < patlen ) 605 continue; 606 607 if ( a->acl_attrval_style == ACL_STYLE_BASE ) { 608 if ( vdnlen > patlen ) 609 continue; 610 611 } else if ( a->acl_attrval_style == ACL_STYLE_ONE ) { 612 ber_len_t rdnlen = 0; 613 614 if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) ) 615 continue; 616 617 rdnlen = dn_rdnlen( NULL, val ); 618 if ( rdnlen != vdnlen - patlen - 1 ) 619 continue; 620 621 } else if ( a->acl_attrval_style == ACL_STYLE_SUBTREE ) { 622 if ( vdnlen > patlen && !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) ) 623 continue; 624 625 } else if ( a->acl_attrval_style == ACL_STYLE_CHILDREN ) { 626 if ( vdnlen <= patlen ) 627 continue; 628 629 if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) ) 630 continue; 631 } 632 633 if ( strcmp( a->acl_attrval.bv_val, val->bv_val + vdnlen - patlen ) ) 634 continue; 635 } 636 } 637 } 638 639 if ( a->acl_filter != NULL ) { 640 ber_int_t rc = test_filter( NULL, e, a->acl_filter ); 641 if ( rc != LDAP_COMPARE_TRUE ) { 642 continue; 643 } 644 } 645 646 Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] attr %s\n", 647 *count, attr, 0); 648 return a; 649 } 650 651 Debug( LDAP_DEBUG_ACL, "<= acl_get: done.\n", 0, 0, 0 ); 652 return( NULL ); 653 } 654 655 /* 656 * Record value-dependent access control state 657 */ 658 #define ACL_RECORD_VALUE_STATE do { \ 659 if( state && !( state->as_recorded & ACL_STATE_RECORDED_VD )) { \ 660 state->as_recorded |= ACL_STATE_RECORDED_VD; \ 661 state->as_vd_acl = a; \ 662 state->as_vd_acl_count = count; \ 663 } \ 664 } while( 0 ) 665 666 static int 667 acl_mask_dn( 668 Operation *op, 669 Entry *e, 670 AttributeDescription *desc, 671 struct berval *val, 672 AccessControl *a, 673 int nmatch, 674 regmatch_t *matches, 675 slap_dn_access *bdn, 676 struct berval *opndn ) 677 { 678 /* 679 * if access applies to the entry itself, and the 680 * user is bound as somebody in the same namespace as 681 * the entry, OR the given dn matches the dn pattern 682 */ 683 /* 684 * NOTE: styles "anonymous", "users" and "self" 685 * have been moved to enum slap_style_t, whose 686 * value is set in a_dn_style; however, the string 687 * is maintained in a_dn_pat. 688 */ 689 690 if ( bdn->a_style == ACL_STYLE_ANONYMOUS ) { 691 if ( !BER_BVISEMPTY( opndn ) ) { 692 return 1; 693 } 694 695 } else if ( bdn->a_style == ACL_STYLE_USERS ) { 696 if ( BER_BVISEMPTY( opndn ) ) { 697 return 1; 698 } 699 700 } else if ( bdn->a_style == ACL_STYLE_SELF ) { 701 struct berval ndn, selfndn; 702 int level; 703 704 if ( BER_BVISEMPTY( opndn ) || BER_BVISNULL( &e->e_nname ) ) { 705 return 1; 706 } 707 708 level = bdn->a_self_level; 709 if ( level < 0 ) { 710 selfndn = *opndn; 711 ndn = e->e_nname; 712 level = -level; 713 714 } else { 715 ndn = *opndn; 716 selfndn = e->e_nname; 717 } 718 719 for ( ; level > 0; level-- ) { 720 if ( BER_BVISEMPTY( &ndn ) ) { 721 break; 722 } 723 dnParent( &ndn, &ndn ); 724 } 725 726 if ( BER_BVISEMPTY( &ndn ) || !dn_match( &ndn, &selfndn ) ) 727 { 728 return 1; 729 } 730 731 } else if ( bdn->a_style == ACL_STYLE_REGEX ) { 732 if ( !ber_bvccmp( &bdn->a_pat, '*' ) ) { 733 int tmp_nmatch; 734 regmatch_t tmp_matches[2], 735 *tmp_matchesp = tmp_matches; 736 737 int rc = 0; 738 739 switch ( a->acl_dn_style ) { 740 case ACL_STYLE_REGEX: 741 if ( !BER_BVISNULL( &a->acl_dn_pat ) ) { 742 tmp_matchesp = matches; 743 tmp_nmatch = nmatch; 744 break; 745 } 746 /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */ 747 748 case ACL_STYLE_BASE: 749 tmp_matches[0].rm_so = 0; 750 tmp_matches[0].rm_eo = e->e_nname.bv_len; 751 tmp_nmatch = 1; 752 break; 753 754 case ACL_STYLE_ONE: 755 case ACL_STYLE_SUBTREE: 756 case ACL_STYLE_CHILDREN: 757 tmp_matches[0].rm_so = 0; 758 tmp_matches[0].rm_eo = e->e_nname.bv_len; 759 tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len; 760 tmp_matches[1].rm_eo = e->e_nname.bv_len; 761 tmp_nmatch = 2; 762 break; 763 764 default: 765 /* error */ 766 rc = 1; 767 break; 768 } 769 770 if ( rc ) { 771 return 1; 772 } 773 774 if ( !regex_matches( &bdn->a_pat, opndn->bv_val, 775 e->e_ndn, tmp_nmatch, tmp_matchesp ) ) 776 { 777 return 1; 778 } 779 } 780 781 } else { 782 struct berval pat; 783 ber_len_t patlen, odnlen; 784 int got_match = 0; 785 786 if ( e->e_dn == NULL ) 787 return 1; 788 789 if ( bdn->a_expand ) { 790 struct berval bv; 791 char buf[ACL_BUF_SIZE]; 792 793 int tmp_nmatch; 794 regmatch_t tmp_matches[2], 795 *tmp_matchesp = tmp_matches; 796 797 int rc = 0; 798 799 bv.bv_len = sizeof( buf ) - 1; 800 bv.bv_val = buf; 801 802 switch ( a->acl_dn_style ) { 803 case ACL_STYLE_REGEX: 804 if ( !BER_BVISNULL( &a->acl_dn_pat ) ) { 805 tmp_matchesp = matches; 806 tmp_nmatch = nmatch; 807 break; 808 } 809 /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */ 810 811 case ACL_STYLE_BASE: 812 tmp_matches[0].rm_so = 0; 813 tmp_matches[0].rm_eo = e->e_nname.bv_len; 814 tmp_nmatch = 1; 815 break; 816 817 case ACL_STYLE_ONE: 818 case ACL_STYLE_SUBTREE: 819 case ACL_STYLE_CHILDREN: 820 tmp_matches[0].rm_so = 0; 821 tmp_matches[0].rm_eo = e->e_nname.bv_len; 822 tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len; 823 tmp_matches[1].rm_eo = e->e_nname.bv_len; 824 tmp_nmatch = 2; 825 break; 826 827 default: 828 /* error */ 829 rc = 1; 830 break; 831 } 832 833 if ( rc ) { 834 return 1; 835 } 836 837 if ( acl_string_expand( &bv, &bdn->a_pat, 838 e->e_nname.bv_val, 839 tmp_nmatch, tmp_matchesp ) ) 840 { 841 return 1; 842 } 843 844 if ( dnNormalize(0, NULL, NULL, &bv, 845 &pat, op->o_tmpmemctx ) 846 != LDAP_SUCCESS ) 847 { 848 /* did not expand to a valid dn */ 849 return 1; 850 } 851 852 } else { 853 pat = bdn->a_pat; 854 } 855 856 patlen = pat.bv_len; 857 odnlen = opndn->bv_len; 858 if ( odnlen < patlen ) { 859 goto dn_match_cleanup; 860 861 } 862 863 if ( bdn->a_style == ACL_STYLE_BASE ) { 864 /* base dn -- entire object DN must match */ 865 if ( odnlen != patlen ) { 866 goto dn_match_cleanup; 867 } 868 869 } else if ( bdn->a_style == ACL_STYLE_ONE ) { 870 ber_len_t rdnlen = 0; 871 872 if ( odnlen <= patlen ) { 873 goto dn_match_cleanup; 874 } 875 876 if ( !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) { 877 goto dn_match_cleanup; 878 } 879 880 rdnlen = dn_rdnlen( NULL, opndn ); 881 if ( rdnlen - ( odnlen - patlen - 1 ) != 0 ) { 882 goto dn_match_cleanup; 883 } 884 885 } else if ( bdn->a_style == ACL_STYLE_SUBTREE ) { 886 if ( odnlen > patlen && !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) { 887 goto dn_match_cleanup; 888 } 889 890 } else if ( bdn->a_style == ACL_STYLE_CHILDREN ) { 891 if ( odnlen <= patlen ) { 892 goto dn_match_cleanup; 893 } 894 895 if ( !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) { 896 goto dn_match_cleanup; 897 } 898 899 } else if ( bdn->a_style == ACL_STYLE_LEVEL ) { 900 int level = bdn->a_level; 901 struct berval ndn; 902 903 if ( odnlen <= patlen ) { 904 goto dn_match_cleanup; 905 } 906 907 if ( level > 0 && !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) 908 { 909 goto dn_match_cleanup; 910 } 911 912 ndn = *opndn; 913 for ( ; level > 0; level-- ) { 914 if ( BER_BVISEMPTY( &ndn ) ) { 915 goto dn_match_cleanup; 916 } 917 dnParent( &ndn, &ndn ); 918 if ( ndn.bv_len < patlen ) { 919 goto dn_match_cleanup; 920 } 921 } 922 923 if ( ndn.bv_len != patlen ) { 924 goto dn_match_cleanup; 925 } 926 } 927 928 got_match = !strcmp( pat.bv_val, &opndn->bv_val[ odnlen - patlen ] ); 929 930 dn_match_cleanup:; 931 if ( pat.bv_val != bdn->a_pat.bv_val ) { 932 slap_sl_free( pat.bv_val, op->o_tmpmemctx ); 933 } 934 935 if ( !got_match ) { 936 return 1; 937 } 938 } 939 940 return 0; 941 } 942 943 static int 944 acl_mask_dnattr( 945 Operation *op, 946 Entry *e, 947 struct berval *val, 948 AccessControl *a, 949 Access *b, 950 int i, 951 regmatch_t *matches, 952 int count, 953 AccessControlState *state, 954 slap_dn_access *bdn, 955 struct berval *opndn ) 956 { 957 Attribute *at; 958 struct berval bv; 959 int rc, match = 0; 960 const char *text; 961 const char *attr = bdn->a_at->ad_cname.bv_val; 962 963 assert( attr != NULL ); 964 965 if ( BER_BVISEMPTY( opndn ) ) { 966 return 1; 967 } 968 969 Debug( LDAP_DEBUG_ACL, "<= check a_dn_at: %s\n", attr, 0, 0 ); 970 bv = *opndn; 971 972 /* see if asker is listed in dnattr */ 973 for ( at = attrs_find( e->e_attrs, bdn->a_at ); 974 at != NULL; 975 at = attrs_find( at->a_next, bdn->a_at ) ) 976 { 977 if ( attr_valfind( at, 978 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 979 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 980 &bv, NULL, op->o_tmpmemctx ) == 0 ) 981 { 982 /* found it */ 983 match = 1; 984 break; 985 } 986 } 987 988 if ( match ) { 989 /* have a dnattr match. if this is a self clause then 990 * the target must also match the op dn. 991 */ 992 if ( bdn->a_self ) { 993 /* check if the target is an attribute. */ 994 if ( val == NULL ) return 1; 995 996 /* target is attribute, check if the attribute value 997 * is the op dn. 998 */ 999 rc = value_match( &match, bdn->a_at, 1000 bdn->a_at->ad_type->sat_equality, 0, 1001 val, &bv, &text ); 1002 /* on match error or no match, fail the ACL clause */ 1003 if ( rc != LDAP_SUCCESS || match != 0 ) 1004 return 1; 1005 } 1006 1007 } else { 1008 /* no dnattr match, check if this is a self clause */ 1009 if ( ! bdn->a_self ) 1010 return 1; 1011 1012 ACL_RECORD_VALUE_STATE; 1013 1014 /* this is a self clause, check if the target is an 1015 * attribute. 1016 */ 1017 if ( val == NULL ) 1018 return 1; 1019 1020 /* target is attribute, check if the attribute value 1021 * is the op dn. 1022 */ 1023 rc = value_match( &match, bdn->a_at, 1024 bdn->a_at->ad_type->sat_equality, 0, 1025 val, &bv, &text ); 1026 1027 /* on match error or no match, fail the ACL clause */ 1028 if ( rc != LDAP_SUCCESS || match != 0 ) 1029 return 1; 1030 } 1031 1032 return 0; 1033 } 1034 1035 1036 /* 1037 * slap_acl_mask - modifies mask based upon the given acl and the 1038 * requested access to entry e, attribute attr, value val. if val 1039 * is null, access to the whole attribute is assumed (all values). 1040 * 1041 * returns 0 access NOT allowed 1042 * 1 access allowed 1043 */ 1044 1045 static slap_control_t 1046 slap_acl_mask( 1047 AccessControl *a, 1048 slap_mask_t *mask, 1049 Operation *op, 1050 Entry *e, 1051 AttributeDescription *desc, 1052 struct berval *val, 1053 int nmatch, 1054 regmatch_t *matches, 1055 int count, 1056 AccessControlState *state ) 1057 { 1058 int i; 1059 Access *b; 1060 #ifdef LDAP_DEBUG 1061 char accessmaskbuf[ACCESSMASK_MAXLEN]; 1062 #endif /* DEBUG */ 1063 const char *attr; 1064 slap_mask_t a2pmask = ACL_ACCESS2PRIV( *mask ); 1065 1066 assert( a != NULL ); 1067 assert( mask != NULL ); 1068 assert( desc != NULL ); 1069 1070 attr = desc->ad_cname.bv_val; 1071 1072 assert( attr != NULL ); 1073 1074 Debug( LDAP_DEBUG_ACL, 1075 "=> acl_mask: access to entry \"%s\", attr \"%s\" requested\n", 1076 e->e_dn, attr, 0 ); 1077 1078 Debug( LDAP_DEBUG_ACL, 1079 "=> acl_mask: to %s by \"%s\", (%s) \n", 1080 val ? "value" : "all values", 1081 op->o_ndn.bv_val ? op->o_ndn.bv_val : "", 1082 accessmask2str( *mask, accessmaskbuf, 1 ) ); 1083 1084 1085 b = a->acl_access; 1086 i = 1; 1087 1088 for ( ; b != NULL; b = b->a_next, i++ ) { 1089 slap_mask_t oldmask, modmask; 1090 1091 ACL_INVALIDATE( modmask ); 1092 1093 /* AND <who> clauses */ 1094 if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) { 1095 Debug( LDAP_DEBUG_ACL, "<= check a_dn_pat: %s\n", 1096 b->a_dn_pat.bv_val, 0, 0); 1097 /* 1098 * if access applies to the entry itself, and the 1099 * user is bound as somebody in the same namespace as 1100 * the entry, OR the given dn matches the dn pattern 1101 */ 1102 /* 1103 * NOTE: styles "anonymous", "users" and "self" 1104 * have been moved to enum slap_style_t, whose 1105 * value is set in a_dn_style; however, the string 1106 * is maintained in a_dn_pat. 1107 */ 1108 1109 if ( acl_mask_dn( op, e, desc, val, a, nmatch, matches, 1110 &b->a_dn, &op->o_ndn ) ) 1111 { 1112 continue; 1113 } 1114 } 1115 1116 if ( !BER_BVISEMPTY( &b->a_realdn_pat ) ) { 1117 struct berval ndn; 1118 1119 Debug( LDAP_DEBUG_ACL, "<= check a_realdn_pat: %s\n", 1120 b->a_realdn_pat.bv_val, 0, 0); 1121 /* 1122 * if access applies to the entry itself, and the 1123 * user is bound as somebody in the same namespace as 1124 * the entry, OR the given dn matches the dn pattern 1125 */ 1126 /* 1127 * NOTE: styles "anonymous", "users" and "self" 1128 * have been moved to enum slap_style_t, whose 1129 * value is set in a_dn_style; however, the string 1130 * is maintained in a_dn_pat. 1131 */ 1132 1133 if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) ) 1134 { 1135 ndn = op->o_conn->c_ndn; 1136 } else { 1137 ndn = op->o_ndn; 1138 } 1139 1140 if ( acl_mask_dn( op, e, desc, val, a, nmatch, matches, 1141 &b->a_realdn, &ndn ) ) 1142 { 1143 continue; 1144 } 1145 } 1146 1147 if ( !BER_BVISEMPTY( &b->a_sockurl_pat ) ) { 1148 if ( ! op->o_conn->c_listener ) { 1149 continue; 1150 } 1151 Debug( LDAP_DEBUG_ACL, "<= check a_sockurl_pat: %s\n", 1152 b->a_sockurl_pat.bv_val, 0, 0 ); 1153 1154 if ( !ber_bvccmp( &b->a_sockurl_pat, '*' ) ) { 1155 if ( b->a_sockurl_style == ACL_STYLE_REGEX) { 1156 if (!regex_matches( &b->a_sockurl_pat, op->o_conn->c_listener_url.bv_val, 1157 e->e_ndn, nmatch, matches ) ) 1158 { 1159 continue; 1160 } 1161 1162 } else if ( b->a_sockurl_style == ACL_STYLE_EXPAND ) { 1163 struct berval bv; 1164 char buf[ACL_BUF_SIZE]; 1165 1166 bv.bv_len = sizeof( buf ) - 1; 1167 bv.bv_val = buf; 1168 if ( acl_string_expand( &bv, &b->a_sockurl_pat, 1169 e->e_ndn, nmatch, matches ) ) 1170 { 1171 continue; 1172 } 1173 1174 if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_listener_url ) != 0 ) 1175 { 1176 continue; 1177 } 1178 1179 } else { 1180 if ( ber_bvstrcasecmp( &b->a_sockurl_pat, &op->o_conn->c_listener_url ) != 0 ) 1181 { 1182 continue; 1183 } 1184 } 1185 } 1186 } 1187 1188 if ( !BER_BVISEMPTY( &b->a_domain_pat ) ) { 1189 if ( !op->o_conn->c_peer_domain.bv_val ) { 1190 continue; 1191 } 1192 Debug( LDAP_DEBUG_ACL, "<= check a_domain_pat: %s\n", 1193 b->a_domain_pat.bv_val, 0, 0 ); 1194 if ( !ber_bvccmp( &b->a_domain_pat, '*' ) ) { 1195 if ( b->a_domain_style == ACL_STYLE_REGEX) { 1196 if (!regex_matches( &b->a_domain_pat, op->o_conn->c_peer_domain.bv_val, 1197 e->e_ndn, nmatch, matches ) ) 1198 { 1199 continue; 1200 } 1201 } else { 1202 char buf[ACL_BUF_SIZE]; 1203 1204 struct berval cmp = op->o_conn->c_peer_domain; 1205 struct berval pat = b->a_domain_pat; 1206 1207 if ( b->a_domain_expand ) { 1208 struct berval bv; 1209 1210 bv.bv_len = sizeof(buf) - 1; 1211 bv.bv_val = buf; 1212 1213 if ( acl_string_expand(&bv, &b->a_domain_pat, 1214 e->e_ndn, nmatch, matches) ) 1215 { 1216 continue; 1217 } 1218 pat = bv; 1219 } 1220 1221 if ( b->a_domain_style == ACL_STYLE_SUBTREE ) { 1222 int offset = cmp.bv_len - pat.bv_len; 1223 if ( offset < 0 ) { 1224 continue; 1225 } 1226 1227 if ( offset == 1 || ( offset > 1 && cmp.bv_val[ offset - 1 ] != '.' ) ) { 1228 continue; 1229 } 1230 1231 /* trim the domain */ 1232 cmp.bv_val = &cmp.bv_val[ offset ]; 1233 cmp.bv_len -= offset; 1234 } 1235 1236 if ( ber_bvstrcasecmp( &pat, &cmp ) != 0 ) { 1237 continue; 1238 } 1239 } 1240 } 1241 } 1242 1243 if ( !BER_BVISEMPTY( &b->a_peername_pat ) ) { 1244 if ( !op->o_conn->c_peer_name.bv_val ) { 1245 continue; 1246 } 1247 Debug( LDAP_DEBUG_ACL, "<= check a_peername_path: %s\n", 1248 b->a_peername_pat.bv_val, 0, 0 ); 1249 if ( !ber_bvccmp( &b->a_peername_pat, '*' ) ) { 1250 if ( b->a_peername_style == ACL_STYLE_REGEX ) { 1251 if (!regex_matches( &b->a_peername_pat, op->o_conn->c_peer_name.bv_val, 1252 e->e_ndn, nmatch, matches ) ) 1253 { 1254 continue; 1255 } 1256 1257 } else { 1258 /* try exact match */ 1259 if ( b->a_peername_style == ACL_STYLE_BASE ) { 1260 if ( ber_bvstrcasecmp( &b->a_peername_pat, &op->o_conn->c_peer_name ) != 0 ) { 1261 continue; 1262 } 1263 1264 } else if ( b->a_peername_style == ACL_STYLE_EXPAND ) { 1265 struct berval bv; 1266 char buf[ACL_BUF_SIZE]; 1267 1268 bv.bv_len = sizeof( buf ) - 1; 1269 bv.bv_val = buf; 1270 if ( acl_string_expand( &bv, &b->a_peername_pat, 1271 e->e_ndn, nmatch, matches ) ) 1272 { 1273 continue; 1274 } 1275 1276 if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_peer_name ) != 0 ) { 1277 continue; 1278 } 1279 1280 /* extract IP and try exact match */ 1281 } else if ( b->a_peername_style == ACL_STYLE_IP ) { 1282 char *port; 1283 char buf[STRLENOF("255.255.255.255") + 1]; 1284 struct berval ip; 1285 unsigned long addr; 1286 int port_number = -1; 1287 1288 if ( strncasecmp( op->o_conn->c_peer_name.bv_val, 1289 acl_bv_ip_eq.bv_val, 1290 acl_bv_ip_eq.bv_len ) != 0 ) 1291 continue; 1292 1293 ip.bv_val = op->o_conn->c_peer_name.bv_val + acl_bv_ip_eq.bv_len; 1294 ip.bv_len = op->o_conn->c_peer_name.bv_len - acl_bv_ip_eq.bv_len; 1295 1296 port = strrchr( ip.bv_val, ':' ); 1297 if ( port ) { 1298 ip.bv_len = port - ip.bv_val; 1299 ++port; 1300 if ( lutil_atoi( &port_number, port ) != 0 ) 1301 continue; 1302 } 1303 1304 /* the port check can be anticipated here */ 1305 if ( b->a_peername_port != -1 && port_number != b->a_peername_port ) 1306 continue; 1307 1308 /* address longer than expected? */ 1309 if ( ip.bv_len >= sizeof(buf) ) 1310 continue; 1311 1312 AC_MEMCPY( buf, ip.bv_val, ip.bv_len ); 1313 buf[ ip.bv_len ] = '\0'; 1314 1315 addr = inet_addr( buf ); 1316 1317 /* unable to convert? */ 1318 if ( addr == (unsigned long)(-1) ) 1319 continue; 1320 1321 if ( (addr & b->a_peername_mask) != b->a_peername_addr ) 1322 continue; 1323 1324 #ifdef LDAP_PF_INET6 1325 /* extract IPv6 and try exact match */ 1326 } else if ( b->a_peername_style == ACL_STYLE_IPV6 ) { 1327 char *port; 1328 char buf[STRLENOF("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF") + 1]; 1329 struct berval ip; 1330 struct in6_addr addr; 1331 int port_number = -1; 1332 1333 if ( strncasecmp( op->o_conn->c_peer_name.bv_val, 1334 acl_bv_ipv6_eq.bv_val, 1335 acl_bv_ipv6_eq.bv_len ) != 0 ) 1336 continue; 1337 1338 ip.bv_val = op->o_conn->c_peer_name.bv_val + acl_bv_ipv6_eq.bv_len; 1339 ip.bv_len = op->o_conn->c_peer_name.bv_len - acl_bv_ipv6_eq.bv_len; 1340 1341 port = strrchr( ip.bv_val, ']' ); 1342 if ( port ) { 1343 ip.bv_len = port - ip.bv_val; 1344 ++port; 1345 if ( port[0] == ':' && lutil_atoi( &port_number, ++port ) != 0 ) 1346 continue; 1347 } 1348 1349 /* the port check can be anticipated here */ 1350 if ( b->a_peername_port != -1 && port_number != b->a_peername_port ) 1351 continue; 1352 1353 /* address longer than expected? */ 1354 if ( ip.bv_len >= sizeof(buf) ) 1355 continue; 1356 1357 AC_MEMCPY( buf, ip.bv_val, ip.bv_len ); 1358 buf[ ip.bv_len ] = '\0'; 1359 1360 if ( inet_pton( AF_INET6, buf, &addr ) != 1 ) 1361 continue; 1362 1363 /* check mask */ 1364 if ( !slap_addr6_mask( &addr, &b->a_peername_mask6, &b->a_peername_addr6 ) ) 1365 continue; 1366 #endif /* LDAP_PF_INET6 */ 1367 1368 #ifdef LDAP_PF_LOCAL 1369 /* extract path and try exact match */ 1370 } else if ( b->a_peername_style == ACL_STYLE_PATH ) { 1371 struct berval path; 1372 1373 if ( strncmp( op->o_conn->c_peer_name.bv_val, 1374 acl_bv_path_eq.bv_val, 1375 acl_bv_path_eq.bv_len ) != 0 ) 1376 continue; 1377 1378 path.bv_val = op->o_conn->c_peer_name.bv_val 1379 + acl_bv_path_eq.bv_len; 1380 path.bv_len = op->o_conn->c_peer_name.bv_len 1381 - acl_bv_path_eq.bv_len; 1382 1383 if ( ber_bvcmp( &b->a_peername_pat, &path ) != 0 ) 1384 continue; 1385 1386 #endif /* LDAP_PF_LOCAL */ 1387 1388 /* exact match (very unlikely...) */ 1389 } else if ( ber_bvcmp( &op->o_conn->c_peer_name, &b->a_peername_pat ) != 0 ) { 1390 continue; 1391 } 1392 } 1393 } 1394 } 1395 1396 if ( !BER_BVISEMPTY( &b->a_sockname_pat ) ) { 1397 if ( BER_BVISNULL( &op->o_conn->c_sock_name ) ) { 1398 continue; 1399 } 1400 Debug( LDAP_DEBUG_ACL, "<= check a_sockname_path: %s\n", 1401 b->a_sockname_pat.bv_val, 0, 0 ); 1402 if ( !ber_bvccmp( &b->a_sockname_pat, '*' ) ) { 1403 if ( b->a_sockname_style == ACL_STYLE_REGEX) { 1404 if (!regex_matches( &b->a_sockname_pat, op->o_conn->c_sock_name.bv_val, 1405 e->e_ndn, nmatch, matches ) ) 1406 { 1407 continue; 1408 } 1409 1410 } else if ( b->a_sockname_style == ACL_STYLE_EXPAND ) { 1411 struct berval bv; 1412 char buf[ACL_BUF_SIZE]; 1413 1414 bv.bv_len = sizeof( buf ) - 1; 1415 bv.bv_val = buf; 1416 if ( acl_string_expand( &bv, &b->a_sockname_pat, 1417 e->e_ndn, nmatch, matches ) ) 1418 { 1419 continue; 1420 } 1421 1422 if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_sock_name ) != 0 ) { 1423 continue; 1424 } 1425 1426 } else { 1427 if ( ber_bvstrcasecmp( &b->a_sockname_pat, &op->o_conn->c_sock_name ) != 0 ) { 1428 continue; 1429 } 1430 } 1431 } 1432 } 1433 1434 if ( b->a_dn_at != NULL ) { 1435 if ( acl_mask_dnattr( op, e, val, a, b, i, 1436 matches, count, state, 1437 &b->a_dn, &op->o_ndn ) ) 1438 { 1439 continue; 1440 } 1441 } 1442 1443 if ( b->a_realdn_at != NULL ) { 1444 struct berval ndn; 1445 1446 if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) ) 1447 { 1448 ndn = op->o_conn->c_ndn; 1449 } else { 1450 ndn = op->o_ndn; 1451 } 1452 1453 if ( acl_mask_dnattr( op, e, val, a, b, i, 1454 matches, count, state, 1455 &b->a_realdn, &ndn ) ) 1456 { 1457 continue; 1458 } 1459 } 1460 1461 if ( !BER_BVISEMPTY( &b->a_group_pat ) ) { 1462 struct berval bv; 1463 struct berval ndn = BER_BVNULL; 1464 int rc; 1465 1466 if ( op->o_ndn.bv_len == 0 ) { 1467 continue; 1468 } 1469 1470 Debug( LDAP_DEBUG_ACL, "<= check a_group_pat: %s\n", 1471 b->a_group_pat.bv_val, 0, 0 ); 1472 1473 /* b->a_group is an unexpanded entry name, expanded it should be an 1474 * entry with objectclass group* and we test to see if odn is one of 1475 * the values in the attribute group 1476 */ 1477 /* see if asker is listed in dnattr */ 1478 if ( b->a_group_style == ACL_STYLE_EXPAND ) { 1479 char buf[ACL_BUF_SIZE]; 1480 int tmp_nmatch; 1481 regmatch_t tmp_matches[2], 1482 *tmp_matchesp = tmp_matches; 1483 1484 bv.bv_len = sizeof(buf) - 1; 1485 bv.bv_val = buf; 1486 1487 rc = 0; 1488 1489 switch ( a->acl_dn_style ) { 1490 case ACL_STYLE_REGEX: 1491 if ( !BER_BVISNULL( &a->acl_dn_pat ) ) { 1492 tmp_matchesp = matches; 1493 tmp_nmatch = nmatch; 1494 break; 1495 } 1496 1497 /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */ 1498 case ACL_STYLE_BASE: 1499 tmp_matches[0].rm_so = 0; 1500 tmp_matches[0].rm_eo = e->e_nname.bv_len; 1501 tmp_nmatch = 1; 1502 break; 1503 1504 case ACL_STYLE_ONE: 1505 case ACL_STYLE_SUBTREE: 1506 case ACL_STYLE_CHILDREN: 1507 tmp_matches[0].rm_so = 0; 1508 tmp_matches[0].rm_eo = e->e_nname.bv_len; 1509 tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len; 1510 tmp_matches[1].rm_eo = e->e_nname.bv_len; 1511 tmp_nmatch = 2; 1512 break; 1513 1514 default: 1515 /* error */ 1516 rc = 1; 1517 break; 1518 } 1519 1520 if ( rc ) { 1521 continue; 1522 } 1523 1524 if ( acl_string_expand( &bv, &b->a_group_pat, 1525 e->e_nname.bv_val, 1526 tmp_nmatch, tmp_matchesp ) ) 1527 { 1528 continue; 1529 } 1530 1531 if ( dnNormalize( 0, NULL, NULL, &bv, &ndn, 1532 op->o_tmpmemctx ) != LDAP_SUCCESS ) 1533 { 1534 /* did not expand to a valid dn */ 1535 continue; 1536 } 1537 1538 bv = ndn; 1539 1540 } else { 1541 bv = b->a_group_pat; 1542 } 1543 1544 rc = backend_group( op, e, &bv, &op->o_ndn, 1545 b->a_group_oc, b->a_group_at ); 1546 1547 if ( ndn.bv_val ) { 1548 slap_sl_free( ndn.bv_val, op->o_tmpmemctx ); 1549 } 1550 1551 if ( rc != 0 ) { 1552 continue; 1553 } 1554 } 1555 1556 if ( !BER_BVISEMPTY( &b->a_set_pat ) ) { 1557 struct berval bv; 1558 char buf[ACL_BUF_SIZE]; 1559 1560 Debug( LDAP_DEBUG_ACL, "<= check a_set_pat: %s\n", 1561 b->a_set_pat.bv_val, 0, 0 ); 1562 1563 if ( b->a_set_style == ACL_STYLE_EXPAND ) { 1564 int tmp_nmatch; 1565 regmatch_t tmp_matches[2], 1566 *tmp_matchesp = tmp_matches; 1567 int rc = 0; 1568 1569 bv.bv_len = sizeof( buf ) - 1; 1570 bv.bv_val = buf; 1571 1572 rc = 0; 1573 1574 switch ( a->acl_dn_style ) { 1575 case ACL_STYLE_REGEX: 1576 if ( !BER_BVISNULL( &a->acl_dn_pat ) ) { 1577 tmp_matchesp = matches; 1578 tmp_nmatch = nmatch; 1579 break; 1580 } 1581 1582 /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */ 1583 case ACL_STYLE_BASE: 1584 tmp_matches[0].rm_so = 0; 1585 tmp_matches[0].rm_eo = e->e_nname.bv_len; 1586 tmp_nmatch = 1; 1587 break; 1588 1589 case ACL_STYLE_ONE: 1590 case ACL_STYLE_SUBTREE: 1591 case ACL_STYLE_CHILDREN: 1592 tmp_matches[0].rm_so = 0; 1593 tmp_matches[0].rm_eo = e->e_nname.bv_len; 1594 tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len; 1595 tmp_matches[1].rm_eo = e->e_nname.bv_len; 1596 tmp_nmatch = 2; 1597 break; 1598 1599 default: 1600 /* error */ 1601 rc = 1; 1602 break; 1603 } 1604 1605 if ( rc ) { 1606 continue; 1607 } 1608 1609 if ( acl_string_expand( &bv, &b->a_set_pat, 1610 e->e_nname.bv_val, 1611 tmp_nmatch, tmp_matchesp ) ) 1612 { 1613 continue; 1614 } 1615 1616 } else { 1617 bv = b->a_set_pat; 1618 } 1619 1620 if ( acl_match_set( &bv, op, e, NULL ) == 0 ) { 1621 continue; 1622 } 1623 } 1624 1625 if ( b->a_authz.sai_ssf ) { 1626 Debug( LDAP_DEBUG_ACL, "<= check a_authz.sai_ssf: ACL %u > OP %u\n", 1627 b->a_authz.sai_ssf, op->o_ssf, 0 ); 1628 if ( b->a_authz.sai_ssf > op->o_ssf ) { 1629 continue; 1630 } 1631 } 1632 1633 if ( b->a_authz.sai_transport_ssf ) { 1634 Debug( LDAP_DEBUG_ACL, 1635 "<= check a_authz.sai_transport_ssf: ACL %u > OP %u\n", 1636 b->a_authz.sai_transport_ssf, op->o_transport_ssf, 0 ); 1637 if ( b->a_authz.sai_transport_ssf > op->o_transport_ssf ) { 1638 continue; 1639 } 1640 } 1641 1642 if ( b->a_authz.sai_tls_ssf ) { 1643 Debug( LDAP_DEBUG_ACL, 1644 "<= check a_authz.sai_tls_ssf: ACL %u > OP %u\n", 1645 b->a_authz.sai_tls_ssf, op->o_tls_ssf, 0 ); 1646 if ( b->a_authz.sai_tls_ssf > op->o_tls_ssf ) { 1647 continue; 1648 } 1649 } 1650 1651 if ( b->a_authz.sai_sasl_ssf ) { 1652 Debug( LDAP_DEBUG_ACL, 1653 "<= check a_authz.sai_sasl_ssf: ACL %u > OP %u\n", 1654 b->a_authz.sai_sasl_ssf, op->o_sasl_ssf, 0 ); 1655 if ( b->a_authz.sai_sasl_ssf > op->o_sasl_ssf ) { 1656 continue; 1657 } 1658 } 1659 1660 /* check for the "self" modifier in the <access> field */ 1661 if ( b->a_dn.a_self ) { 1662 const char *dummy; 1663 int rc, match = 0; 1664 1665 ACL_RECORD_VALUE_STATE; 1666 1667 /* must have DN syntax */ 1668 if ( desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName && 1669 !is_at_syntax( desc->ad_type, SLAPD_NAMEUID_SYNTAX )) continue; 1670 1671 /* check if the target is an attribute. */ 1672 if ( val == NULL ) continue; 1673 1674 /* a DN must be present */ 1675 if ( BER_BVISEMPTY( &op->o_ndn ) ) { 1676 continue; 1677 } 1678 1679 /* target is attribute, check if the attribute value 1680 * is the op dn. 1681 */ 1682 rc = value_match( &match, desc, 1683 desc->ad_type->sat_equality, 0, 1684 val, &op->o_ndn, &dummy ); 1685 /* on match error or no match, fail the ACL clause */ 1686 if ( rc != LDAP_SUCCESS || match != 0 ) 1687 continue; 1688 } 1689 1690 #ifdef SLAP_DYNACL 1691 if ( b->a_dynacl ) { 1692 slap_dynacl_t *da; 1693 slap_access_t tgrant, tdeny; 1694 1695 Debug( LDAP_DEBUG_ACL, "<= check a_dynacl\n", 1696 0, 0, 0 ); 1697 1698 /* this case works different from the others above. 1699 * since dynamic ACL's themselves give permissions, we need 1700 * to first check b->a_access_mask, the ACL's access level. 1701 */ 1702 /* first check if the right being requested 1703 * is allowed by the ACL clause. 1704 */ 1705 if ( ! ACL_PRIV_ISSET( b->a_access_mask, a2pmask ) ) { 1706 continue; 1707 } 1708 1709 /* start out with nothing granted, nothing denied */ 1710 ACL_INVALIDATE(tgrant); 1711 ACL_INVALIDATE(tdeny); 1712 1713 for ( da = b->a_dynacl; da; da = da->da_next ) { 1714 slap_access_t grant, 1715 deny; 1716 1717 ACL_INVALIDATE(grant); 1718 ACL_INVALIDATE(deny); 1719 1720 Debug( LDAP_DEBUG_ACL, " <= check a_dynacl: %s\n", 1721 da->da_name, 0, 0 ); 1722 1723 (void)da->da_mask( da->da_private, op, e, desc, 1724 val, nmatch, matches, &grant, &deny ); 1725 1726 tgrant |= grant; 1727 tdeny |= deny; 1728 } 1729 1730 /* remove anything that the ACL clause does not allow */ 1731 tgrant &= b->a_access_mask & ACL_PRIV_MASK; 1732 tdeny &= ACL_PRIV_MASK; 1733 1734 /* see if we have anything to contribute */ 1735 if( ACL_IS_INVALID(tgrant) && ACL_IS_INVALID(tdeny) ) { 1736 continue; 1737 } 1738 1739 /* this could be improved by changing slap_acl_mask so that it can deal with 1740 * by clauses that return grant/deny pairs. Right now, it does either 1741 * additive or subtractive rights, but not both at the same time. So, 1742 * we need to combine the grant/deny pair into a single rights mask in 1743 * a smart way: if either grant or deny is "empty", then we use the 1744 * opposite as is, otherwise we remove any denied rights from the grant 1745 * rights mask and construct an additive mask. 1746 */ 1747 if (ACL_IS_INVALID(tdeny)) { 1748 modmask = tgrant | ACL_PRIV_ADDITIVE; 1749 1750 } else if (ACL_IS_INVALID(tgrant)) { 1751 modmask = tdeny | ACL_PRIV_SUBSTRACTIVE; 1752 1753 } else { 1754 modmask = (tgrant & ~tdeny) | ACL_PRIV_ADDITIVE; 1755 } 1756 1757 } else 1758 #endif /* SLAP_DYNACL */ 1759 { 1760 modmask = b->a_access_mask; 1761 } 1762 1763 Debug( LDAP_DEBUG_ACL, 1764 "<= acl_mask: [%d] applying %s (%s)\n", 1765 i, accessmask2str( modmask, accessmaskbuf, 1 ), 1766 b->a_type == ACL_CONTINUE 1767 ? "continue" 1768 : b->a_type == ACL_BREAK 1769 ? "break" 1770 : "stop" ); 1771 /* save old mask */ 1772 oldmask = *mask; 1773 1774 if( ACL_IS_ADDITIVE(modmask) ) { 1775 /* add privs */ 1776 ACL_PRIV_SET( *mask, modmask ); 1777 1778 /* cleanup */ 1779 ACL_PRIV_CLR( *mask, ~ACL_PRIV_MASK ); 1780 1781 } else if( ACL_IS_SUBTRACTIVE(modmask) ) { 1782 /* substract privs */ 1783 ACL_PRIV_CLR( *mask, modmask ); 1784 1785 /* cleanup */ 1786 ACL_PRIV_CLR( *mask, ~ACL_PRIV_MASK ); 1787 1788 } else { 1789 /* assign privs */ 1790 *mask = modmask; 1791 } 1792 1793 a2pmask = *mask; 1794 1795 Debug( LDAP_DEBUG_ACL, 1796 "<= acl_mask: [%d] mask: %s\n", 1797 i, accessmask2str(*mask, accessmaskbuf, 1), 0 ); 1798 1799 if( b->a_type == ACL_CONTINUE ) { 1800 continue; 1801 1802 } else if ( b->a_type == ACL_BREAK ) { 1803 return ACL_BREAK; 1804 1805 } else { 1806 return ACL_STOP; 1807 } 1808 } 1809 1810 /* implicit "by * none" clause */ 1811 ACL_INIT(*mask); 1812 1813 Debug( LDAP_DEBUG_ACL, 1814 "<= acl_mask: no more <who> clauses, returning %s (stop)\n", 1815 accessmask2str(*mask, accessmaskbuf, 1), 0, 0 ); 1816 return ACL_STOP; 1817 } 1818 1819 /* 1820 * acl_check_modlist - check access control on the given entry to see if 1821 * it allows the given modifications by the user associated with op. 1822 * returns 1 if mods allowed ok 1823 * 0 mods not allowed 1824 */ 1825 1826 int 1827 acl_check_modlist( 1828 Operation *op, 1829 Entry *e, 1830 Modifications *mlist ) 1831 { 1832 struct berval *bv; 1833 AccessControlState state = ACL_STATE_INIT; 1834 Backend *be; 1835 int be_null = 0; 1836 int ret = 1; /* default is access allowed */ 1837 1838 be = op->o_bd; 1839 if ( be == NULL ) { 1840 be = LDAP_STAILQ_FIRST(&backendDB); 1841 be_null = 1; 1842 op->o_bd = be; 1843 } 1844 assert( be != NULL ); 1845 1846 /* short circuit root database access */ 1847 if ( be_isroot( op ) ) { 1848 Debug( LDAP_DEBUG_ACL, 1849 "<= acl_access_allowed: granted to database root\n", 1850 0, 0, 0 ); 1851 goto done; 1852 } 1853 1854 /* use backend default access if no backend acls */ 1855 if( op->o_bd != NULL && op->o_bd->be_acl == NULL ) { 1856 Debug( LDAP_DEBUG_ACL, 1857 "=> access_allowed: backend default %s access %s to \"%s\"\n", 1858 access2str( ACL_WRITE ), 1859 op->o_bd->be_dfltaccess >= ACL_WRITE 1860 ? "granted" : "denied", 1861 op->o_dn.bv_val ); 1862 ret = (op->o_bd->be_dfltaccess >= ACL_WRITE); 1863 goto done; 1864 } 1865 1866 for ( ; mlist != NULL; mlist = mlist->sml_next ) { 1867 /* 1868 * Internal mods are ignored by ACL_WRITE checking 1869 */ 1870 if ( mlist->sml_flags & SLAP_MOD_INTERNAL ) { 1871 Debug( LDAP_DEBUG_ACL, "acl: internal mod %s:" 1872 " modify access granted\n", 1873 mlist->sml_desc->ad_cname.bv_val, 0, 0 ); 1874 continue; 1875 } 1876 1877 /* 1878 * no-user-modification operational attributes are ignored 1879 * by ACL_WRITE checking as any found here are not provided 1880 * by the user 1881 */ 1882 if ( is_at_no_user_mod( mlist->sml_desc->ad_type ) 1883 && ! ( mlist->sml_flags & SLAP_MOD_MANAGING ) ) 1884 { 1885 Debug( LDAP_DEBUG_ACL, "acl: no-user-mod %s:" 1886 " modify access granted\n", 1887 mlist->sml_desc->ad_cname.bv_val, 0, 0 ); 1888 continue; 1889 } 1890 1891 switch ( mlist->sml_op ) { 1892 case LDAP_MOD_REPLACE: 1893 case LDAP_MOD_INCREMENT: 1894 /* 1895 * We must check both permission to delete the whole 1896 * attribute and permission to add the specific attributes. 1897 * This prevents abuse from selfwriters. 1898 */ 1899 if ( ! access_allowed( op, e, 1900 mlist->sml_desc, NULL, 1901 ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL, 1902 &state ) ) 1903 { 1904 ret = 0; 1905 goto done; 1906 } 1907 1908 if ( mlist->sml_values == NULL ) break; 1909 1910 /* fall thru to check value to add */ 1911 1912 case LDAP_MOD_ADD: 1913 assert( mlist->sml_values != NULL ); 1914 1915 for ( bv = mlist->sml_nvalues 1916 ? mlist->sml_nvalues : mlist->sml_values; 1917 bv->bv_val != NULL; bv++ ) 1918 { 1919 if ( ! access_allowed( op, e, 1920 mlist->sml_desc, bv, 1921 ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WADD, 1922 &state ) ) 1923 { 1924 ret = 0; 1925 goto done; 1926 } 1927 } 1928 break; 1929 1930 case LDAP_MOD_DELETE: 1931 if ( mlist->sml_values == NULL ) { 1932 if ( ! access_allowed( op, e, 1933 mlist->sml_desc, NULL, 1934 ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL, 1935 NULL ) ) 1936 { 1937 ret = 0; 1938 goto done; 1939 } 1940 break; 1941 } 1942 for ( bv = mlist->sml_nvalues 1943 ? mlist->sml_nvalues : mlist->sml_values; 1944 bv->bv_val != NULL; bv++ ) 1945 { 1946 if ( ! access_allowed( op, e, 1947 mlist->sml_desc, bv, 1948 ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL, 1949 &state ) ) 1950 { 1951 ret = 0; 1952 goto done; 1953 } 1954 } 1955 break; 1956 1957 case SLAP_MOD_SOFTADD: 1958 /* allow adding attribute via modrdn thru */ 1959 break; 1960 1961 default: 1962 assert( 0 ); 1963 /* not reached */ 1964 ret = 0; 1965 break; 1966 } 1967 } 1968 1969 done: 1970 if (be_null) op->o_bd = NULL; 1971 return( ret ); 1972 } 1973 1974 int 1975 acl_get_part( 1976 struct berval *list, 1977 int ix, 1978 char sep, 1979 struct berval *bv ) 1980 { 1981 int len; 1982 char *p; 1983 1984 if ( bv ) { 1985 BER_BVZERO( bv ); 1986 } 1987 len = list->bv_len; 1988 p = list->bv_val; 1989 while ( len >= 0 && --ix >= 0 ) { 1990 while ( --len >= 0 && *p++ != sep ) 1991 ; 1992 } 1993 while ( len >= 0 && *p == ' ' ) { 1994 len--; 1995 p++; 1996 } 1997 if ( len < 0 ) { 1998 return -1; 1999 } 2000 2001 if ( !bv ) { 2002 return 0; 2003 } 2004 2005 bv->bv_val = p; 2006 while ( --len >= 0 && *p != sep ) { 2007 bv->bv_len++; 2008 p++; 2009 } 2010 while ( bv->bv_len > 0 && *--p == ' ' ) { 2011 bv->bv_len--; 2012 } 2013 2014 return bv->bv_len; 2015 } 2016 2017 typedef struct acl_set_gather_t { 2018 SetCookie *cookie; 2019 BerVarray bvals; 2020 } acl_set_gather_t; 2021 2022 static int 2023 acl_set_cb_gather( Operation *op, SlapReply *rs ) 2024 { 2025 acl_set_gather_t *p = (acl_set_gather_t *)op->o_callback->sc_private; 2026 2027 if ( rs->sr_type == REP_SEARCH ) { 2028 BerValue bvals[ 2 ]; 2029 BerVarray bvalsp = NULL; 2030 int j; 2031 2032 for ( j = 0; !BER_BVISNULL( &rs->sr_attrs[ j ].an_name ); j++ ) { 2033 AttributeDescription *desc = rs->sr_attrs[ j ].an_desc; 2034 2035 if ( desc == NULL ) { 2036 continue; 2037 } 2038 2039 if ( desc == slap_schema.si_ad_entryDN ) { 2040 bvalsp = bvals; 2041 bvals[ 0 ] = rs->sr_entry->e_nname; 2042 BER_BVZERO( &bvals[ 1 ] ); 2043 2044 } else { 2045 Attribute *a; 2046 2047 a = attr_find( rs->sr_entry->e_attrs, desc ); 2048 if ( a != NULL ) { 2049 bvalsp = a->a_nvals; 2050 } 2051 } 2052 2053 if ( bvalsp ) { 2054 p->bvals = slap_set_join( p->cookie, p->bvals, 2055 ( '|' | SLAP_SET_RREF ), bvalsp ); 2056 } 2057 } 2058 2059 } else { 2060 assert( rs->sr_type == REP_RESULT ); 2061 } 2062 2063 return 0; 2064 } 2065 2066 BerVarray 2067 acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *desc ) 2068 { 2069 AclSetCookie *cp = (AclSetCookie *)cookie; 2070 int rc = 0; 2071 LDAPURLDesc *ludp = NULL; 2072 Operation op2 = { 0 }; 2073 SlapReply rs = {REP_RESULT}; 2074 AttributeName anlist[ 2 ], *anlistp = NULL; 2075 int nattrs = 0; 2076 slap_callback cb = { NULL, acl_set_cb_gather, NULL, NULL }; 2077 acl_set_gather_t p = { 0 }; 2078 2079 /* this routine needs to return the bervals instead of 2080 * plain strings, since syntax is not known. It should 2081 * also return the syntax or some "comparison cookie". 2082 */ 2083 if ( strncasecmp( name->bv_val, "ldap:///", STRLENOF( "ldap:///" ) ) != 0 ) { 2084 return acl_set_gather2( cookie, name, desc ); 2085 } 2086 2087 rc = ldap_url_parse( name->bv_val, &ludp ); 2088 if ( rc != LDAP_URL_SUCCESS ) { 2089 Debug( LDAP_DEBUG_TRACE, 2090 "%s acl_set_gather: unable to parse URL=\"%s\"\n", 2091 cp->asc_op->o_log_prefix, name->bv_val, 0 ); 2092 2093 rc = LDAP_PROTOCOL_ERROR; 2094 goto url_done; 2095 } 2096 2097 if ( ( ludp->lud_host && ludp->lud_host[0] ) || ludp->lud_exts ) 2098 { 2099 /* host part must be empty */ 2100 /* extensions parts must be empty */ 2101 Debug( LDAP_DEBUG_TRACE, 2102 "%s acl_set_gather: host/exts must be absent in URL=\"%s\"\n", 2103 cp->asc_op->o_log_prefix, name->bv_val, 0 ); 2104 2105 rc = LDAP_PROTOCOL_ERROR; 2106 goto url_done; 2107 } 2108 2109 /* Grab the searchbase and see if an appropriate database can be found */ 2110 ber_str2bv( ludp->lud_dn, 0, 0, &op2.o_req_dn ); 2111 rc = dnNormalize( 0, NULL, NULL, &op2.o_req_dn, 2112 &op2.o_req_ndn, cp->asc_op->o_tmpmemctx ); 2113 BER_BVZERO( &op2.o_req_dn ); 2114 if ( rc != LDAP_SUCCESS ) { 2115 Debug( LDAP_DEBUG_TRACE, 2116 "%s acl_set_gather: DN=\"%s\" normalize failed\n", 2117 cp->asc_op->o_log_prefix, op2.o_req_dn.bv_val, 0 ); 2118 2119 goto url_done; 2120 } 2121 2122 op2.o_bd = select_backend( &op2.o_req_ndn, 1 ); 2123 if ( ( op2.o_bd == NULL ) || ( op2.o_bd->be_search == NULL ) ) { 2124 Debug( LDAP_DEBUG_TRACE, 2125 "%s acl_set_gather: no database could be selected for DN=\"%s\"\n", 2126 cp->asc_op->o_log_prefix, op2.o_req_ndn.bv_val, 0 ); 2127 2128 rc = LDAP_NO_SUCH_OBJECT; 2129 goto url_done; 2130 } 2131 2132 /* Grab the filter */ 2133 if ( ludp->lud_filter ) { 2134 ber_str2bv_x( ludp->lud_filter, 0, 0, &op2.ors_filterstr, 2135 cp->asc_op->o_tmpmemctx ); 2136 op2.ors_filter = str2filter_x( cp->asc_op, op2.ors_filterstr.bv_val ); 2137 if ( op2.ors_filter == NULL ) { 2138 Debug( LDAP_DEBUG_TRACE, 2139 "%s acl_set_gather: unable to parse filter=\"%s\"\n", 2140 cp->asc_op->o_log_prefix, op2.ors_filterstr.bv_val, 0 ); 2141 2142 rc = LDAP_PROTOCOL_ERROR; 2143 goto url_done; 2144 } 2145 2146 } else { 2147 op2.ors_filterstr = *slap_filterstr_objectClass_pres; 2148 op2.ors_filter = (Filter *)slap_filter_objectClass_pres; 2149 } 2150 2151 2152 /* Grab the scope */ 2153 op2.ors_scope = ludp->lud_scope; 2154 2155 /* Grap the attributes */ 2156 if ( ludp->lud_attrs ) { 2157 int i; 2158 2159 for ( ; ludp->lud_attrs[ nattrs ]; nattrs++ ) 2160 ; 2161 2162 anlistp = slap_sl_calloc( sizeof( AttributeName ), nattrs + 2, 2163 cp->asc_op->o_tmpmemctx ); 2164 2165 for ( i = 0, nattrs = 0; ludp->lud_attrs[ i ]; i++ ) { 2166 struct berval name; 2167 AttributeDescription *desc = NULL; 2168 const char *text = NULL; 2169 2170 ber_str2bv( ludp->lud_attrs[ i ], 0, 0, &name ); 2171 rc = slap_bv2ad( &name, &desc, &text ); 2172 if ( rc == LDAP_SUCCESS ) { 2173 anlistp[ nattrs ].an_name = name; 2174 anlistp[ nattrs ].an_desc = desc; 2175 nattrs++; 2176 } 2177 } 2178 2179 } else { 2180 anlistp = anlist; 2181 } 2182 2183 anlistp[ nattrs ].an_name = desc->ad_cname; 2184 anlistp[ nattrs ].an_desc = desc; 2185 2186 BER_BVZERO( &anlistp[ nattrs + 1 ].an_name ); 2187 2188 p.cookie = cookie; 2189 2190 op2.o_hdr = cp->asc_op->o_hdr; 2191 op2.o_tag = LDAP_REQ_SEARCH; 2192 op2.o_ndn = op2.o_bd->be_rootndn; 2193 op2.o_callback = &cb; 2194 slap_op_time( &op2.o_time, &op2.o_tincr ); 2195 op2.o_do_not_cache = 1; 2196 op2.o_is_auth_check = 0; 2197 ber_dupbv_x( &op2.o_req_dn, &op2.o_req_ndn, cp->asc_op->o_tmpmemctx ); 2198 op2.ors_slimit = SLAP_NO_LIMIT; 2199 op2.ors_tlimit = SLAP_NO_LIMIT; 2200 op2.ors_attrs = anlistp; 2201 op2.ors_attrsonly = 0; 2202 op2.o_private = cp->asc_op->o_private; 2203 op2.o_extra = cp->asc_op->o_extra; 2204 2205 cb.sc_private = &p; 2206 2207 rc = op2.o_bd->be_search( &op2, &rs ); 2208 if ( rc != 0 ) { 2209 goto url_done; 2210 } 2211 2212 url_done:; 2213 if ( op2.ors_filter && op2.ors_filter != slap_filter_objectClass_pres ) { 2214 filter_free_x( cp->asc_op, op2.ors_filter ); 2215 } 2216 if ( !BER_BVISNULL( &op2.o_req_ndn ) ) { 2217 slap_sl_free( op2.o_req_ndn.bv_val, cp->asc_op->o_tmpmemctx ); 2218 } 2219 if ( !BER_BVISNULL( &op2.o_req_dn ) ) { 2220 slap_sl_free( op2.o_req_dn.bv_val, cp->asc_op->o_tmpmemctx ); 2221 } 2222 if ( ludp ) { 2223 ldap_free_urldesc( ludp ); 2224 } 2225 if ( anlistp && anlistp != anlist ) { 2226 slap_sl_free( anlistp, cp->asc_op->o_tmpmemctx ); 2227 } 2228 2229 return p.bvals; 2230 } 2231 2232 BerVarray 2233 acl_set_gather2( SetCookie *cookie, struct berval *name, AttributeDescription *desc ) 2234 { 2235 AclSetCookie *cp = (AclSetCookie *)cookie; 2236 BerVarray bvals = NULL; 2237 struct berval ndn; 2238 int rc = 0; 2239 2240 /* this routine needs to return the bervals instead of 2241 * plain strings, since syntax is not known. It should 2242 * also return the syntax or some "comparison cookie". 2243 */ 2244 rc = dnNormalize( 0, NULL, NULL, name, &ndn, cp->asc_op->o_tmpmemctx ); 2245 if ( rc == LDAP_SUCCESS ) { 2246 if ( desc == slap_schema.si_ad_entryDN ) { 2247 bvals = (BerVarray)slap_sl_malloc( sizeof( BerValue ) * 2, 2248 cp->asc_op->o_tmpmemctx ); 2249 bvals[ 0 ] = ndn; 2250 BER_BVZERO( &bvals[ 1 ] ); 2251 BER_BVZERO( &ndn ); 2252 2253 } else { 2254 backend_attribute( cp->asc_op, 2255 cp->asc_e, &ndn, desc, &bvals, ACL_NONE ); 2256 } 2257 2258 if ( !BER_BVISNULL( &ndn ) ) { 2259 slap_sl_free( ndn.bv_val, cp->asc_op->o_tmpmemctx ); 2260 } 2261 } 2262 2263 return bvals; 2264 } 2265 2266 int 2267 acl_match_set ( 2268 struct berval *subj, 2269 Operation *op, 2270 Entry *e, 2271 struct berval *default_set_attribute ) 2272 { 2273 struct berval set = BER_BVNULL; 2274 int rc = 0; 2275 AclSetCookie cookie; 2276 2277 if ( default_set_attribute == NULL ) { 2278 ber_dupbv_x( &set, subj, op->o_tmpmemctx ); 2279 2280 } else { 2281 struct berval subjdn, ndn = BER_BVNULL; 2282 struct berval setat; 2283 BerVarray bvals = NULL; 2284 const char *text; 2285 AttributeDescription *desc = NULL; 2286 2287 /* format of string is "entry/setAttrName" */ 2288 if ( acl_get_part( subj, 0, '/', &subjdn ) < 0 ) { 2289 return 0; 2290 } 2291 2292 if ( acl_get_part( subj, 1, '/', &setat ) < 0 ) { 2293 setat = *default_set_attribute; 2294 } 2295 2296 /* 2297 * NOTE: dnNormalize honors the ber_len field 2298 * as the length of the dn to be normalized 2299 */ 2300 if ( slap_bv2ad( &setat, &desc, &text ) == LDAP_SUCCESS ) { 2301 if ( dnNormalize( 0, NULL, NULL, &subjdn, &ndn, op->o_tmpmemctx ) == LDAP_SUCCESS ) 2302 { 2303 backend_attribute( op, e, &ndn, desc, &bvals, ACL_NONE ); 2304 if ( bvals != NULL && !BER_BVISNULL( &bvals[0] ) ) { 2305 int i; 2306 2307 set = bvals[0]; 2308 BER_BVZERO( &bvals[0] ); 2309 for ( i = 1; !BER_BVISNULL( &bvals[i] ); i++ ) 2310 /* count */ ; 2311 bvals[0].bv_val = bvals[i-1].bv_val; 2312 BER_BVZERO( &bvals[i-1] ); 2313 } 2314 ber_bvarray_free_x( bvals, op->o_tmpmemctx ); 2315 slap_sl_free( ndn.bv_val, op->o_tmpmemctx ); 2316 } 2317 } 2318 } 2319 2320 if ( !BER_BVISNULL( &set ) ) { 2321 cookie.asc_op = op; 2322 cookie.asc_e = e; 2323 rc = ( slap_set_filter( 2324 acl_set_gather, 2325 (SetCookie *)&cookie, &set, 2326 &op->o_ndn, &e->e_nname, NULL ) > 0 ); 2327 slap_sl_free( set.bv_val, op->o_tmpmemctx ); 2328 } 2329 2330 return(rc); 2331 } 2332 2333 #ifdef SLAP_DYNACL 2334 2335 /* 2336 * dynamic ACL infrastructure 2337 */ 2338 static slap_dynacl_t *da_list = NULL; 2339 2340 int 2341 slap_dynacl_register( slap_dynacl_t *da ) 2342 { 2343 slap_dynacl_t *tmp; 2344 2345 for ( tmp = da_list; tmp; tmp = tmp->da_next ) { 2346 if ( strcasecmp( da->da_name, tmp->da_name ) == 0 ) { 2347 break; 2348 } 2349 } 2350 2351 if ( tmp != NULL ) { 2352 return -1; 2353 } 2354 2355 if ( da->da_mask == NULL ) { 2356 return -1; 2357 } 2358 2359 da->da_private = NULL; 2360 da->da_next = da_list; 2361 da_list = da; 2362 2363 return 0; 2364 } 2365 2366 static slap_dynacl_t * 2367 slap_dynacl_next( slap_dynacl_t *da ) 2368 { 2369 if ( da ) { 2370 return da->da_next; 2371 } 2372 return da_list; 2373 } 2374 2375 slap_dynacl_t * 2376 slap_dynacl_get( const char *name ) 2377 { 2378 slap_dynacl_t *da; 2379 2380 for ( da = slap_dynacl_next( NULL ); da; da = slap_dynacl_next( da ) ) { 2381 if ( strcasecmp( da->da_name, name ) == 0 ) { 2382 break; 2383 } 2384 } 2385 2386 return da; 2387 } 2388 #endif /* SLAP_DYNACL */ 2389 2390 /* 2391 * statically built-in dynamic ACL initialization 2392 */ 2393 static int (*acl_init_func[])( void ) = { 2394 #ifdef SLAP_DYNACL 2395 /* TODO: remove when ACI will only be dynamic */ 2396 #if SLAPD_ACI_ENABLED == SLAPD_MOD_STATIC 2397 dynacl_aci_init, 2398 #endif /* SLAPD_ACI_ENABLED */ 2399 #endif /* SLAP_DYNACL */ 2400 2401 NULL 2402 }; 2403 2404 int 2405 acl_init( void ) 2406 { 2407 int i, rc; 2408 2409 for ( i = 0; acl_init_func[ i ] != NULL; i++ ) { 2410 rc = (*(acl_init_func[ i ]))(); 2411 if ( rc != 0 ) { 2412 return rc; 2413 } 2414 } 2415 2416 return 0; 2417 } 2418 2419 int 2420 acl_string_expand( 2421 struct berval *bv, 2422 struct berval *pat, 2423 char *match, 2424 int nmatch, 2425 regmatch_t *matches) 2426 { 2427 ber_len_t size; 2428 char *sp; 2429 char *dp; 2430 int flag; 2431 2432 size = 0; 2433 bv->bv_val[0] = '\0'; 2434 bv->bv_len--; /* leave space for lone $ */ 2435 2436 flag = 0; 2437 for ( dp = bv->bv_val, sp = pat->bv_val; size < bv->bv_len && 2438 sp < pat->bv_val + pat->bv_len ; sp++ ) 2439 { 2440 /* did we previously see a $ */ 2441 if ( flag ) { 2442 if ( flag == 1 && *sp == '$' ) { 2443 *dp++ = '$'; 2444 size++; 2445 flag = 0; 2446 2447 } else if ( flag == 1 && *sp == '{' /*'}'*/) { 2448 flag = 2; 2449 2450 } else if ( *sp >= '0' && *sp <= '9' ) { 2451 int n; 2452 int i; 2453 int l; 2454 2455 n = *sp - '0'; 2456 2457 if ( flag == 2 ) { 2458 for ( sp++; *sp != '\0' && *sp != /*'{'*/ '}'; sp++ ) { 2459 if ( *sp >= '0' && *sp <= '9' ) { 2460 n = 10*n + ( *sp - '0' ); 2461 } 2462 } 2463 2464 if ( *sp != /*'{'*/ '}' ) { 2465 /* FIXME: error */ 2466 return 1; 2467 } 2468 } 2469 2470 if ( n >= nmatch ) { 2471 /* FIXME: error */ 2472 return 1; 2473 } 2474 2475 *dp = '\0'; 2476 i = matches[n].rm_so; 2477 l = matches[n].rm_eo; 2478 for ( ; size < bv->bv_len && i < l; size++, i++ ) { 2479 *dp++ = match[i]; 2480 } 2481 *dp = '\0'; 2482 2483 flag = 0; 2484 } 2485 } else { 2486 if (*sp == '$') { 2487 flag = 1; 2488 } else { 2489 *dp++ = *sp; 2490 size++; 2491 } 2492 } 2493 } 2494 2495 if ( flag ) { 2496 /* must have ended with a single $ */ 2497 *dp++ = '$'; 2498 size++; 2499 } 2500 2501 *dp = '\0'; 2502 bv->bv_len = size; 2503 2504 Debug( LDAP_DEBUG_TRACE, "=> acl_string_expand: pattern: %.*s\n", (int)pat->bv_len, pat->bv_val, 0 ); 2505 Debug( LDAP_DEBUG_TRACE, "=> acl_string_expand: expanded: %s\n", bv->bv_val, 0, 0 ); 2506 2507 return 0; 2508 } 2509 2510 static int 2511 regex_matches( 2512 struct berval *pat, /* pattern to expand and match against */ 2513 char *str, /* string to match against pattern */ 2514 char *buf, /* buffer with $N expansion variables */ 2515 int nmatch, /* size of the matches array */ 2516 regmatch_t *matches /* offsets in buffer for $N expansion variables */ 2517 ) 2518 { 2519 regex_t re; 2520 char newbuf[ACL_BUF_SIZE]; 2521 struct berval bv; 2522 int rc; 2523 2524 bv.bv_len = sizeof( newbuf ) - 1; 2525 bv.bv_val = newbuf; 2526 2527 if (str == NULL) { 2528 str = ""; 2529 }; 2530 2531 acl_string_expand( &bv, pat, buf, nmatch, matches ); 2532 rc = regcomp( &re, newbuf, REG_EXTENDED|REG_ICASE ); 2533 if ( rc ) { 2534 char error[ACL_BUF_SIZE]; 2535 regerror( rc, &re, error, sizeof( error ) ); 2536 2537 Debug( LDAP_DEBUG_TRACE, 2538 "compile( \"%s\", \"%s\") failed %s\n", 2539 pat->bv_val, str, error ); 2540 return( 0 ); 2541 } 2542 2543 rc = regexec( &re, str, 0, NULL, 0 ); 2544 regfree( &re ); 2545 2546 Debug( LDAP_DEBUG_TRACE, 2547 "=> regex_matches: string: %s\n", str, 0, 0 ); 2548 Debug( LDAP_DEBUG_TRACE, 2549 "=> regex_matches: rc: %d %s\n", 2550 rc, !rc ? "matches" : "no matches", 0 ); 2551 return( !rc ); 2552 } 2553 2554