1 /* $NetBSD: acl.c,v 1.1.1.7 2018/02/06 01:53:13 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-2017 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.1.1.7 2018/02/06 01:53:13 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", 0, 0, 0 ); 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, 0, 0 ); 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], 0, 0 ); 270 } 271 } 272 Debug( LDAP_DEBUG_ACL, "\n", 0, 0, 0 ); 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], 0, 0 ); 288 } 289 } 290 Debug( LDAP_DEBUG_ACL, "\n", 0, 0, 0 ); 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, 0 ); 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", 0, 0, 0 ); 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, 0, 0 ); 422 return state->as_result; 423 } else { 424 Debug( LDAP_DEBUG_ACL, 425 "=> access_allowed: result not in cache (%s)\n", 426 attr, 0, 0 ); 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, 0 ); 470 ACL_INIT( mask ); 471 472 } else { 473 Debug( LDAP_DEBUG_ACL, 474 "=> access_allowed: no more rules\n", 0, 0, 0 ); 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, 0 ); 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, 0, 0 ); 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, 0, 0 ); 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, 0, 0 ); 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, 0); 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", 0, 0, 0 ); 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, 0, 0 ); 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, 0 ); 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, 0, 0); 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, 0, 0); 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, 0, 0 ); 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, 0, 0 ); 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, 0, 0 ); 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, 0, 0 ); 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, 0, 0 ); 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, 0, 0 ); 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, 0 ); 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, 0 ); 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, 0 ); 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, 0 ); 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 0, 0, 0 ); 1774 1775 /* this case works different from the others above. 1776 * since dynamic ACL's themselves give permissions, we need 1777 * to first check b->a_access_mask, the ACL's access level. 1778 */ 1779 /* first check if the right being requested 1780 * is allowed by the ACL clause. 1781 */ 1782 if ( ! ACL_PRIV_ISSET( b->a_access_mask, a2pmask ) ) { 1783 continue; 1784 } 1785 1786 /* start out with nothing granted, nothing denied */ 1787 ACL_INVALIDATE(tgrant); 1788 ACL_INVALIDATE(tdeny); 1789 1790 for ( da = b->a_dynacl; da; da = da->da_next ) { 1791 slap_access_t grant, 1792 deny; 1793 1794 ACL_INVALIDATE(grant); 1795 ACL_INVALIDATE(deny); 1796 1797 Debug( LDAP_DEBUG_ACL, " <= check a_dynacl: %s\n", 1798 da->da_name, 0, 0 ); 1799 1800 /* 1801 * XXXmanu Only DN matches are supplied 1802 * sending attribute values matches require 1803 * an API update 1804 */ 1805 (void)da->da_mask( da->da_private, op, e, desc, 1806 val, matches->dn_count, matches->dn_data, 1807 &grant, &deny ); 1808 1809 tgrant |= grant; 1810 tdeny |= deny; 1811 } 1812 1813 /* remove anything that the ACL clause does not allow */ 1814 tgrant &= b->a_access_mask & ACL_PRIV_MASK; 1815 tdeny &= ACL_PRIV_MASK; 1816 1817 /* see if we have anything to contribute */ 1818 if( ACL_IS_INVALID(tgrant) && ACL_IS_INVALID(tdeny) ) { 1819 continue; 1820 } 1821 1822 /* this could be improved by changing slap_acl_mask so that it can deal with 1823 * by clauses that return grant/deny pairs. Right now, it does either 1824 * additive or subtractive rights, but not both at the same time. So, 1825 * we need to combine the grant/deny pair into a single rights mask in 1826 * a smart way: if either grant or deny is "empty", then we use the 1827 * opposite as is, otherwise we remove any denied rights from the grant 1828 * rights mask and construct an additive mask. 1829 */ 1830 if (ACL_IS_INVALID(tdeny)) { 1831 modmask = tgrant | ACL_PRIV_ADDITIVE; 1832 1833 } else if (ACL_IS_INVALID(tgrant)) { 1834 modmask = tdeny | ACL_PRIV_SUBSTRACTIVE; 1835 1836 } else { 1837 modmask = (tgrant & ~tdeny) | ACL_PRIV_ADDITIVE; 1838 } 1839 1840 } else 1841 #endif /* SLAP_DYNACL */ 1842 { 1843 modmask = b->a_access_mask; 1844 } 1845 1846 Debug( LDAP_DEBUG_ACL, 1847 "<= acl_mask: [%d] applying %s (%s)\n", 1848 i, accessmask2str( modmask, accessmaskbuf, 1 ), 1849 b->a_type == ACL_CONTINUE 1850 ? "continue" 1851 : b->a_type == ACL_BREAK 1852 ? "break" 1853 : "stop" ); 1854 /* save old mask */ 1855 oldmask = *mask; 1856 1857 if( ACL_IS_ADDITIVE(modmask) ) { 1858 /* add privs */ 1859 ACL_PRIV_SET( *mask, modmask ); 1860 1861 /* cleanup */ 1862 ACL_PRIV_CLR( *mask, ~ACL_PRIV_MASK ); 1863 1864 } else if( ACL_IS_SUBTRACTIVE(modmask) ) { 1865 /* substract privs */ 1866 ACL_PRIV_CLR( *mask, modmask ); 1867 1868 /* cleanup */ 1869 ACL_PRIV_CLR( *mask, ~ACL_PRIV_MASK ); 1870 1871 } else { 1872 /* assign privs */ 1873 *mask = modmask; 1874 } 1875 1876 Debug( LDAP_DEBUG_ACL, 1877 "<= acl_mask: [%d] mask: %s\n", 1878 i, accessmask2str(*mask, accessmaskbuf, 1), 0 ); 1879 1880 if( b->a_type == ACL_CONTINUE ) { 1881 continue; 1882 1883 } else if ( b->a_type == ACL_BREAK ) { 1884 return ACL_BREAK; 1885 1886 } else { 1887 return ACL_STOP; 1888 } 1889 } 1890 1891 /* implicit "by * none" clause */ 1892 ACL_INIT(*mask); 1893 1894 Debug( LDAP_DEBUG_ACL, 1895 "<= acl_mask: no more <who> clauses, returning %s (stop)\n", 1896 accessmask2str(*mask, accessmaskbuf, 1), 0, 0 ); 1897 return ACL_STOP; 1898 } 1899 1900 /* 1901 * acl_check_modlist - check access control on the given entry to see if 1902 * it allows the given modifications by the user associated with op. 1903 * returns 1 if mods allowed ok 1904 * 0 mods not allowed 1905 */ 1906 1907 int 1908 acl_check_modlist( 1909 Operation *op, 1910 Entry *e, 1911 Modifications *mlist ) 1912 { 1913 struct berval *bv; 1914 AccessControlState state = ACL_STATE_INIT; 1915 Backend *be; 1916 int be_null = 0; 1917 int ret = 1; /* default is access allowed */ 1918 1919 be = op->o_bd; 1920 if ( be == NULL ) { 1921 be = LDAP_STAILQ_FIRST(&backendDB); 1922 be_null = 1; 1923 op->o_bd = be; 1924 } 1925 assert( be != NULL ); 1926 1927 /* If ADD attribute checking is not enabled, just allow it */ 1928 if ( op->o_tag == LDAP_REQ_ADD && !SLAP_DBACL_ADD( be )) 1929 return 1; 1930 1931 /* short circuit root database access */ 1932 if ( be_isroot( op ) ) { 1933 Debug( LDAP_DEBUG_ACL, 1934 "<= acl_access_allowed: granted to database root\n", 1935 0, 0, 0 ); 1936 goto done; 1937 } 1938 1939 /* use backend default access if no backend acls */ 1940 if( op->o_bd != NULL && op->o_bd->be_acl == NULL && frontendDB->be_acl == NULL ) { 1941 Debug( LDAP_DEBUG_ACL, 1942 "=> access_allowed: backend default %s access %s to \"%s\"\n", 1943 access2str( ACL_WRITE ), 1944 op->o_bd->be_dfltaccess >= ACL_WRITE 1945 ? "granted" : "denied", 1946 op->o_dn.bv_val ); 1947 ret = (op->o_bd->be_dfltaccess >= ACL_WRITE); 1948 goto done; 1949 } 1950 1951 for ( ; mlist != NULL; mlist = mlist->sml_next ) { 1952 /* 1953 * Internal mods are ignored by ACL_WRITE checking 1954 */ 1955 if ( mlist->sml_flags & SLAP_MOD_INTERNAL ) { 1956 Debug( LDAP_DEBUG_ACL, "acl: internal mod %s:" 1957 " modify access granted\n", 1958 mlist->sml_desc->ad_cname.bv_val, 0, 0 ); 1959 continue; 1960 } 1961 1962 /* 1963 * no-user-modification operational attributes are ignored 1964 * by ACL_WRITE checking as any found here are not provided 1965 * by the user 1966 */ 1967 if ( is_at_no_user_mod( mlist->sml_desc->ad_type ) 1968 && ! ( mlist->sml_flags & SLAP_MOD_MANAGING ) ) 1969 { 1970 Debug( LDAP_DEBUG_ACL, "acl: no-user-mod %s:" 1971 " modify access granted\n", 1972 mlist->sml_desc->ad_cname.bv_val, 0, 0 ); 1973 continue; 1974 } 1975 1976 switch ( mlist->sml_op ) { 1977 case LDAP_MOD_REPLACE: 1978 case LDAP_MOD_INCREMENT: 1979 /* 1980 * We must check both permission to delete the whole 1981 * attribute and permission to add the specific attributes. 1982 * This prevents abuse from selfwriters. 1983 */ 1984 if ( ! access_allowed( op, e, 1985 mlist->sml_desc, NULL, 1986 ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL, 1987 &state ) ) 1988 { 1989 ret = 0; 1990 goto done; 1991 } 1992 1993 if ( mlist->sml_values == NULL ) break; 1994 1995 /* fall thru to check value to add */ 1996 1997 case LDAP_MOD_ADD: 1998 case SLAP_MOD_ADD_IF_NOT_PRESENT: 1999 assert( mlist->sml_values != NULL ); 2000 2001 if ( mlist->sml_op == SLAP_MOD_ADD_IF_NOT_PRESENT 2002 && attr_find( e->e_attrs, mlist->sml_desc ) ) 2003 { 2004 break; 2005 } 2006 2007 for ( bv = mlist->sml_nvalues 2008 ? mlist->sml_nvalues : mlist->sml_values; 2009 bv->bv_val != NULL; bv++ ) 2010 { 2011 if ( ! access_allowed( op, e, 2012 mlist->sml_desc, bv, 2013 ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WADD, 2014 &state ) ) 2015 { 2016 ret = 0; 2017 goto done; 2018 } 2019 } 2020 break; 2021 2022 case LDAP_MOD_DELETE: 2023 case SLAP_MOD_SOFTDEL: 2024 if ( mlist->sml_values == NULL ) { 2025 if ( ! access_allowed( op, e, 2026 mlist->sml_desc, NULL, 2027 ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL, 2028 &state ) ) 2029 { 2030 ret = 0; 2031 goto done; 2032 } 2033 break; 2034 } 2035 for ( bv = mlist->sml_nvalues 2036 ? mlist->sml_nvalues : mlist->sml_values; 2037 bv->bv_val != NULL; bv++ ) 2038 { 2039 if ( ! access_allowed( op, e, 2040 mlist->sml_desc, bv, 2041 ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL, 2042 &state ) ) 2043 { 2044 ret = 0; 2045 goto done; 2046 } 2047 } 2048 break; 2049 2050 case SLAP_MOD_SOFTADD: 2051 /* allow adding attribute via modrdn thru */ 2052 break; 2053 2054 default: 2055 assert( 0 ); 2056 /* not reached */ 2057 ret = 0; 2058 break; 2059 } 2060 } 2061 2062 done: 2063 if (be_null) op->o_bd = NULL; 2064 return( ret ); 2065 } 2066 2067 int 2068 acl_get_part( 2069 struct berval *list, 2070 int ix, 2071 char sep, 2072 struct berval *bv ) 2073 { 2074 int len; 2075 char *p; 2076 2077 if ( bv ) { 2078 BER_BVZERO( bv ); 2079 } 2080 len = list->bv_len; 2081 p = list->bv_val; 2082 while ( len >= 0 && --ix >= 0 ) { 2083 while ( --len >= 0 && *p++ != sep ) 2084 ; 2085 } 2086 while ( len >= 0 && *p == ' ' ) { 2087 len--; 2088 p++; 2089 } 2090 if ( len < 0 ) { 2091 return -1; 2092 } 2093 2094 if ( !bv ) { 2095 return 0; 2096 } 2097 2098 bv->bv_val = p; 2099 while ( --len >= 0 && *p != sep ) { 2100 bv->bv_len++; 2101 p++; 2102 } 2103 while ( bv->bv_len > 0 && *--p == ' ' ) { 2104 bv->bv_len--; 2105 } 2106 2107 return bv->bv_len; 2108 } 2109 2110 typedef struct acl_set_gather_t { 2111 SetCookie *cookie; 2112 BerVarray bvals; 2113 } acl_set_gather_t; 2114 2115 static int 2116 acl_set_cb_gather( Operation *op, SlapReply *rs ) 2117 { 2118 acl_set_gather_t *p = (acl_set_gather_t *)op->o_callback->sc_private; 2119 2120 if ( rs->sr_type == REP_SEARCH ) { 2121 BerValue bvals[ 2 ]; 2122 BerVarray bvalsp = NULL; 2123 int j; 2124 2125 for ( j = 0; !BER_BVISNULL( &rs->sr_attrs[ j ].an_name ); j++ ) { 2126 AttributeDescription *desc = rs->sr_attrs[ j ].an_desc; 2127 2128 if ( desc == NULL ) { 2129 continue; 2130 } 2131 2132 if ( desc == slap_schema.si_ad_entryDN ) { 2133 bvalsp = bvals; 2134 bvals[ 0 ] = rs->sr_entry->e_nname; 2135 BER_BVZERO( &bvals[ 1 ] ); 2136 2137 } else { 2138 Attribute *a; 2139 2140 a = attr_find( rs->sr_entry->e_attrs, desc ); 2141 if ( a != NULL ) { 2142 bvalsp = a->a_nvals; 2143 } 2144 } 2145 2146 if ( bvalsp ) { 2147 p->bvals = slap_set_join( p->cookie, p->bvals, 2148 ( '|' | SLAP_SET_RREF ), bvalsp ); 2149 } 2150 } 2151 2152 } else { 2153 switch ( rs->sr_type ) { 2154 case REP_SEARCHREF: 2155 case REP_INTERMEDIATE: 2156 /* ignore */ 2157 break; 2158 2159 default: 2160 assert( rs->sr_type == REP_RESULT ); 2161 break; 2162 } 2163 } 2164 2165 return 0; 2166 } 2167 2168 BerVarray 2169 acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *desc ) 2170 { 2171 AclSetCookie *cp = (AclSetCookie *)cookie; 2172 int rc = 0; 2173 LDAPURLDesc *ludp = NULL; 2174 Operation op2 = { 0 }; 2175 SlapReply rs = {REP_RESULT}; 2176 AttributeName anlist[ 2 ], *anlistp = NULL; 2177 int nattrs = 0; 2178 slap_callback cb = { NULL, acl_set_cb_gather, NULL, NULL }; 2179 acl_set_gather_t p = { 0 }; 2180 2181 /* this routine needs to return the bervals instead of 2182 * plain strings, since syntax is not known. It should 2183 * also return the syntax or some "comparison cookie". 2184 */ 2185 if ( strncasecmp( name->bv_val, "ldap:///", STRLENOF( "ldap:///" ) ) != 0 ) { 2186 return acl_set_gather2( cookie, name, desc ); 2187 } 2188 2189 rc = ldap_url_parse( name->bv_val, &ludp ); 2190 if ( rc != LDAP_URL_SUCCESS ) { 2191 Debug( LDAP_DEBUG_TRACE, 2192 "%s acl_set_gather: unable to parse URL=\"%s\"\n", 2193 cp->asc_op->o_log_prefix, name->bv_val, 0 ); 2194 2195 rc = LDAP_PROTOCOL_ERROR; 2196 goto url_done; 2197 } 2198 2199 if ( ( ludp->lud_host && ludp->lud_host[0] ) || ludp->lud_exts ) 2200 { 2201 /* host part must be empty */ 2202 /* extensions parts must be empty */ 2203 Debug( LDAP_DEBUG_TRACE, 2204 "%s acl_set_gather: host/exts must be absent in URL=\"%s\"\n", 2205 cp->asc_op->o_log_prefix, name->bv_val, 0 ); 2206 2207 rc = LDAP_PROTOCOL_ERROR; 2208 goto url_done; 2209 } 2210 2211 /* Grab the searchbase and see if an appropriate database can be found */ 2212 ber_str2bv( ludp->lud_dn, 0, 0, &op2.o_req_dn ); 2213 rc = dnNormalize( 0, NULL, NULL, &op2.o_req_dn, 2214 &op2.o_req_ndn, cp->asc_op->o_tmpmemctx ); 2215 BER_BVZERO( &op2.o_req_dn ); 2216 if ( rc != LDAP_SUCCESS ) { 2217 Debug( LDAP_DEBUG_TRACE, 2218 "%s acl_set_gather: DN=\"%s\" normalize failed\n", 2219 cp->asc_op->o_log_prefix, ludp->lud_dn, 0 ); 2220 2221 goto url_done; 2222 } 2223 2224 op2.o_bd = select_backend( &op2.o_req_ndn, 1 ); 2225 if ( ( op2.o_bd == NULL ) || ( op2.o_bd->be_search == NULL ) ) { 2226 Debug( LDAP_DEBUG_TRACE, 2227 "%s acl_set_gather: no database could be selected for DN=\"%s\"\n", 2228 cp->asc_op->o_log_prefix, op2.o_req_ndn.bv_val, 0 ); 2229 2230 rc = LDAP_NO_SUCH_OBJECT; 2231 goto url_done; 2232 } 2233 2234 /* Grab the filter */ 2235 if ( ludp->lud_filter ) { 2236 ber_str2bv_x( ludp->lud_filter, 0, 0, &op2.ors_filterstr, 2237 cp->asc_op->o_tmpmemctx ); 2238 op2.ors_filter = str2filter_x( cp->asc_op, op2.ors_filterstr.bv_val ); 2239 if ( op2.ors_filter == NULL ) { 2240 Debug( LDAP_DEBUG_TRACE, 2241 "%s acl_set_gather: unable to parse filter=\"%s\"\n", 2242 cp->asc_op->o_log_prefix, op2.ors_filterstr.bv_val, 0 ); 2243 2244 rc = LDAP_PROTOCOL_ERROR; 2245 goto url_done; 2246 } 2247 2248 } else { 2249 op2.ors_filterstr = *slap_filterstr_objectClass_pres; 2250 op2.ors_filter = (Filter *)slap_filter_objectClass_pres; 2251 } 2252 2253 2254 /* Grab the scope */ 2255 op2.ors_scope = ludp->lud_scope; 2256 2257 /* Grap the attributes */ 2258 if ( ludp->lud_attrs ) { 2259 int i; 2260 2261 for ( ; ludp->lud_attrs[ nattrs ]; nattrs++ ) 2262 ; 2263 2264 anlistp = slap_sl_calloc( sizeof( AttributeName ), nattrs + 2, 2265 cp->asc_op->o_tmpmemctx ); 2266 2267 for ( i = 0, nattrs = 0; ludp->lud_attrs[ i ]; i++ ) { 2268 struct berval name; 2269 AttributeDescription *desc = NULL; 2270 const char *text = NULL; 2271 2272 ber_str2bv( ludp->lud_attrs[ i ], 0, 0, &name ); 2273 rc = slap_bv2ad( &name, &desc, &text ); 2274 if ( rc == LDAP_SUCCESS ) { 2275 anlistp[ nattrs ].an_name = name; 2276 anlistp[ nattrs ].an_desc = desc; 2277 nattrs++; 2278 } 2279 } 2280 2281 } else { 2282 anlistp = anlist; 2283 } 2284 2285 anlistp[ nattrs ].an_name = desc->ad_cname; 2286 anlistp[ nattrs ].an_desc = desc; 2287 2288 BER_BVZERO( &anlistp[ nattrs + 1 ].an_name ); 2289 2290 p.cookie = cookie; 2291 2292 op2.o_hdr = cp->asc_op->o_hdr; 2293 op2.o_tag = LDAP_REQ_SEARCH; 2294 op2.o_ndn = op2.o_bd->be_rootndn; 2295 op2.o_callback = &cb; 2296 slap_op_time( &op2.o_time, &op2.o_tincr ); 2297 op2.o_do_not_cache = 1; 2298 op2.o_is_auth_check = 0; 2299 ber_dupbv_x( &op2.o_req_dn, &op2.o_req_ndn, cp->asc_op->o_tmpmemctx ); 2300 op2.ors_slimit = SLAP_NO_LIMIT; 2301 op2.ors_tlimit = SLAP_NO_LIMIT; 2302 op2.ors_attrs = anlistp; 2303 op2.ors_attrsonly = 0; 2304 op2.o_private = cp->asc_op->o_private; 2305 op2.o_extra = cp->asc_op->o_extra; 2306 2307 cb.sc_private = &p; 2308 2309 rc = op2.o_bd->be_search( &op2, &rs ); 2310 if ( rc != 0 ) { 2311 goto url_done; 2312 } 2313 2314 url_done:; 2315 if ( op2.ors_filter && op2.ors_filter != slap_filter_objectClass_pres ) { 2316 filter_free_x( cp->asc_op, op2.ors_filter, 1 ); 2317 } 2318 if ( !BER_BVISNULL( &op2.o_req_ndn ) ) { 2319 slap_sl_free( op2.o_req_ndn.bv_val, cp->asc_op->o_tmpmemctx ); 2320 } 2321 if ( !BER_BVISNULL( &op2.o_req_dn ) ) { 2322 slap_sl_free( op2.o_req_dn.bv_val, cp->asc_op->o_tmpmemctx ); 2323 } 2324 if ( ludp ) { 2325 ldap_free_urldesc( ludp ); 2326 } 2327 if ( anlistp && anlistp != anlist ) { 2328 slap_sl_free( anlistp, cp->asc_op->o_tmpmemctx ); 2329 } 2330 2331 return p.bvals; 2332 } 2333 2334 BerVarray 2335 acl_set_gather2( SetCookie *cookie, struct berval *name, AttributeDescription *desc ) 2336 { 2337 AclSetCookie *cp = (AclSetCookie *)cookie; 2338 BerVarray bvals = NULL; 2339 struct berval ndn; 2340 int rc = 0; 2341 2342 /* this routine needs to return the bervals instead of 2343 * plain strings, since syntax is not known. It should 2344 * also return the syntax or some "comparison cookie". 2345 */ 2346 rc = dnNormalize( 0, NULL, NULL, name, &ndn, cp->asc_op->o_tmpmemctx ); 2347 if ( rc == LDAP_SUCCESS ) { 2348 if ( desc == slap_schema.si_ad_entryDN ) { 2349 bvals = (BerVarray)slap_sl_malloc( sizeof( BerValue ) * 2, 2350 cp->asc_op->o_tmpmemctx ); 2351 bvals[ 0 ] = ndn; 2352 BER_BVZERO( &bvals[ 1 ] ); 2353 BER_BVZERO( &ndn ); 2354 2355 } else { 2356 backend_attribute( cp->asc_op, 2357 cp->asc_e, &ndn, desc, &bvals, ACL_NONE ); 2358 } 2359 2360 if ( !BER_BVISNULL( &ndn ) ) { 2361 slap_sl_free( ndn.bv_val, cp->asc_op->o_tmpmemctx ); 2362 } 2363 } 2364 2365 return bvals; 2366 } 2367 2368 int 2369 acl_match_set ( 2370 struct berval *subj, 2371 Operation *op, 2372 Entry *e, 2373 struct berval *default_set_attribute ) 2374 { 2375 struct berval set = BER_BVNULL; 2376 int rc = 0; 2377 AclSetCookie cookie; 2378 2379 if ( default_set_attribute == NULL ) { 2380 set = *subj; 2381 2382 } else { 2383 struct berval subjdn, ndn = BER_BVNULL; 2384 struct berval setat; 2385 BerVarray bvals = NULL; 2386 const char *text; 2387 AttributeDescription *desc = NULL; 2388 2389 /* format of string is "entry/setAttrName" */ 2390 if ( acl_get_part( subj, 0, '/', &subjdn ) < 0 ) { 2391 return 0; 2392 } 2393 2394 if ( acl_get_part( subj, 1, '/', &setat ) < 0 ) { 2395 setat = *default_set_attribute; 2396 } 2397 2398 /* 2399 * NOTE: dnNormalize honors the ber_len field 2400 * as the length of the dn to be normalized 2401 */ 2402 if ( slap_bv2ad( &setat, &desc, &text ) == LDAP_SUCCESS ) { 2403 if ( dnNormalize( 0, NULL, NULL, &subjdn, &ndn, op->o_tmpmemctx ) == LDAP_SUCCESS ) 2404 { 2405 backend_attribute( op, e, &ndn, desc, &bvals, ACL_NONE ); 2406 if ( bvals != NULL && !BER_BVISNULL( &bvals[0] ) ) { 2407 int i; 2408 2409 set = bvals[0]; 2410 BER_BVZERO( &bvals[0] ); 2411 for ( i = 1; !BER_BVISNULL( &bvals[i] ); i++ ) 2412 /* count */ ; 2413 bvals[0].bv_val = bvals[i-1].bv_val; 2414 BER_BVZERO( &bvals[i-1] ); 2415 } 2416 ber_bvarray_free_x( bvals, op->o_tmpmemctx ); 2417 slap_sl_free( ndn.bv_val, op->o_tmpmemctx ); 2418 } 2419 } 2420 } 2421 2422 if ( !BER_BVISNULL( &set ) ) { 2423 cookie.asc_op = op; 2424 cookie.asc_e = e; 2425 rc = ( slap_set_filter( 2426 acl_set_gather, 2427 (SetCookie *)&cookie, &set, 2428 &op->o_ndn, &e->e_nname, NULL ) > 0 ); 2429 if ( set.bv_val != subj->bv_val ) { 2430 slap_sl_free( set.bv_val, op->o_tmpmemctx ); 2431 } 2432 } 2433 2434 return(rc); 2435 } 2436 2437 #ifdef SLAP_DYNACL 2438 2439 /* 2440 * dynamic ACL infrastructure 2441 */ 2442 static slap_dynacl_t *da_list = NULL; 2443 2444 int 2445 slap_dynacl_register( slap_dynacl_t *da ) 2446 { 2447 slap_dynacl_t *tmp; 2448 2449 for ( tmp = da_list; tmp; tmp = tmp->da_next ) { 2450 if ( strcasecmp( da->da_name, tmp->da_name ) == 0 ) { 2451 break; 2452 } 2453 } 2454 2455 if ( tmp != NULL ) { 2456 return -1; 2457 } 2458 2459 if ( da->da_mask == NULL ) { 2460 return -1; 2461 } 2462 2463 da->da_private = NULL; 2464 da->da_next = da_list; 2465 da_list = da; 2466 2467 return 0; 2468 } 2469 2470 static slap_dynacl_t * 2471 slap_dynacl_next( slap_dynacl_t *da ) 2472 { 2473 if ( da ) { 2474 return da->da_next; 2475 } 2476 return da_list; 2477 } 2478 2479 slap_dynacl_t * 2480 slap_dynacl_get( const char *name ) 2481 { 2482 slap_dynacl_t *da; 2483 2484 for ( da = slap_dynacl_next( NULL ); da; da = slap_dynacl_next( da ) ) { 2485 if ( strcasecmp( da->da_name, name ) == 0 ) { 2486 break; 2487 } 2488 } 2489 2490 return da; 2491 } 2492 #endif /* SLAP_DYNACL */ 2493 2494 /* 2495 * statically built-in dynamic ACL initialization 2496 */ 2497 static int (*acl_init_func[])( void ) = { 2498 #ifdef SLAP_DYNACL 2499 /* TODO: remove when ACI will only be dynamic */ 2500 #if SLAPD_ACI_ENABLED == SLAPD_MOD_STATIC 2501 dynacl_aci_init, 2502 #endif /* SLAPD_ACI_ENABLED */ 2503 #endif /* SLAP_DYNACL */ 2504 2505 NULL 2506 }; 2507 2508 int 2509 acl_init( void ) 2510 { 2511 int i, rc; 2512 2513 for ( i = 0; acl_init_func[ i ] != NULL; i++ ) { 2514 rc = (*(acl_init_func[ i ]))(); 2515 if ( rc != 0 ) { 2516 return rc; 2517 } 2518 } 2519 2520 return 0; 2521 } 2522 2523 int 2524 acl_string_expand( 2525 struct berval *bv, 2526 struct berval *pat, 2527 struct berval *dn_matches, 2528 struct berval *val_matches, 2529 AclRegexMatches *matches) 2530 { 2531 ber_len_t size; 2532 char *sp; 2533 char *dp; 2534 int flag; 2535 enum { DN_FLAG, VAL_FLAG } tflag; 2536 2537 size = 0; 2538 bv->bv_val[0] = '\0'; 2539 bv->bv_len--; /* leave space for lone $ */ 2540 2541 flag = 0; 2542 tflag = DN_FLAG; 2543 for ( dp = bv->bv_val, sp = pat->bv_val; size < bv->bv_len && 2544 sp < pat->bv_val + pat->bv_len ; sp++ ) 2545 { 2546 /* did we previously see a $ */ 2547 if ( flag ) { 2548 if ( flag == 1 && *sp == '$' ) { 2549 *dp++ = '$'; 2550 size++; 2551 flag = 0; 2552 tflag = DN_FLAG; 2553 2554 } else if ( flag == 2 && *sp == 'v' /*'}'*/) { 2555 tflag = VAL_FLAG; 2556 2557 } else if ( flag == 2 && *sp == 'd' /*'}'*/) { 2558 tflag = DN_FLAG; 2559 2560 } else if ( flag == 1 && *sp == '{' /*'}'*/) { 2561 flag = 2; 2562 2563 } else if ( *sp >= '0' && *sp <= '9' ) { 2564 int nm; 2565 regmatch_t *m; 2566 char *data; 2567 int n; 2568 int i; 2569 int l; 2570 2571 n = *sp - '0'; 2572 2573 if ( flag == 2 ) { 2574 for ( sp++; *sp != '\0' && *sp != /*'{'*/ '}'; sp++ ) { 2575 if ( *sp >= '0' && *sp <= '9' ) { 2576 n = 10*n + ( *sp - '0' ); 2577 } 2578 } 2579 2580 if ( *sp != /*'{'*/ '}' ) { 2581 /* FIXME: error */ 2582 return 1; 2583 } 2584 } 2585 2586 switch (tflag) { 2587 case DN_FLAG: 2588 nm = matches->dn_count; 2589 m = matches->dn_data; 2590 data = dn_matches ? dn_matches->bv_val : NULL; 2591 break; 2592 case VAL_FLAG: 2593 nm = matches->val_count; 2594 m = matches->val_data; 2595 data = val_matches ? val_matches->bv_val : NULL; 2596 break; 2597 default: 2598 assert( 0 ); 2599 } 2600 if ( n >= nm ) { 2601 /* FIXME: error */ 2602 return 1; 2603 } 2604 if ( data == NULL ) { 2605 /* FIXME: error */ 2606 return 1; 2607 } 2608 2609 *dp = '\0'; 2610 i = m[n].rm_so; 2611 l = m[n].rm_eo; 2612 2613 for ( ; size < bv->bv_len && i < l; size++, i++ ) { 2614 *dp++ = data[i]; 2615 } 2616 *dp = '\0'; 2617 2618 flag = 0; 2619 tflag = DN_FLAG; 2620 } 2621 } else { 2622 if (*sp == '$') { 2623 flag = 1; 2624 } else { 2625 *dp++ = *sp; 2626 size++; 2627 } 2628 } 2629 } 2630 2631 if ( flag ) { 2632 /* must have ended with a single $ */ 2633 *dp++ = '$'; 2634 size++; 2635 } 2636 2637 *dp = '\0'; 2638 bv->bv_len = size; 2639 2640 Debug( LDAP_DEBUG_ACL, "=> acl_string_expand: pattern: %.*s\n", (int)pat->bv_len, pat->bv_val, 0 ); 2641 Debug( LDAP_DEBUG_ACL, "=> acl_string_expand: expanded: %s\n", bv->bv_val, 0, 0 ); 2642 2643 return 0; 2644 } 2645 2646 static int 2647 regex_matches( 2648 struct berval *pat, /* pattern to expand and match against */ 2649 char *str, /* string to match against pattern */ 2650 struct berval *dn_matches, /* buffer with $N expansion variables from DN */ 2651 struct berval *val_matches, /* buffer with $N expansion variables from val */ 2652 AclRegexMatches *matches /* offsets in buffer for $N expansion variables */ 2653 ) 2654 { 2655 regex_t re; 2656 char newbuf[ACL_BUF_SIZE]; 2657 struct berval bv; 2658 int rc; 2659 2660 bv.bv_len = sizeof( newbuf ) - 1; 2661 bv.bv_val = newbuf; 2662 2663 if (str == NULL) { 2664 str = ""; 2665 }; 2666 2667 if ( acl_string_expand( &bv, pat, dn_matches, val_matches, matches )) { 2668 Debug( LDAP_DEBUG_TRACE, 2669 "expand( \"%s\", \"%s\") failed\n", 2670 pat->bv_val, str, 0 ); 2671 return( 0 ); 2672 } 2673 rc = regcomp( &re, newbuf, REG_EXTENDED|REG_ICASE ); 2674 if ( rc ) { 2675 char error[ACL_BUF_SIZE]; 2676 regerror( rc, &re, error, sizeof( error ) ); 2677 2678 Debug( LDAP_DEBUG_TRACE, 2679 "compile( \"%s\", \"%s\") failed %s\n", 2680 pat->bv_val, str, error ); 2681 return( 0 ); 2682 } 2683 2684 rc = regexec( &re, str, 0, NULL, 0 ); 2685 regfree( &re ); 2686 2687 Debug( LDAP_DEBUG_TRACE, 2688 "=> regex_matches: string: %s\n", str, 0, 0 ); 2689 Debug( LDAP_DEBUG_TRACE, 2690 "=> regex_matches: rc: %d %s\n", 2691 rc, !rc ? "matches" : "no matches", 0 ); 2692 return( !rc ); 2693 } 2694 2695