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