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