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