1 /* $NetBSD: dynlist.c,v 1.1.1.5 2014/05/28 09:58:52 tron Exp $ */ 2 3 /* dynlist.c - dynamic list overlay */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2003-2014 The OpenLDAP Foundation. 8 * Portions Copyright 2004-2005 Pierangelo Masarati. 9 * Portions Copyright 2008 Emmanuel Dreyfus. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted only as authorized by the OpenLDAP 14 * Public License. 15 * 16 * A copy of this license is available in the file LICENSE in the 17 * top-level directory of the distribution or, alternatively, at 18 * <http://www.OpenLDAP.org/license.html>. 19 */ 20 /* ACKNOWLEDGEMENTS: 21 * This work was initially developed by Pierangelo Masarati 22 * for SysNet s.n.c., for inclusion in OpenLDAP Software. 23 */ 24 25 #include "portable.h" 26 27 #ifdef SLAPD_OVER_DYNLIST 28 29 #if SLAPD_OVER_DYNGROUP != SLAPD_MOD_STATIC 30 #define TAKEOVER_DYNGROUP 31 #endif 32 33 #include <stdio.h> 34 35 #include <ac/string.h> 36 37 #include "slap.h" 38 #include "config.h" 39 #include "lutil.h" 40 41 static AttributeDescription *ad_dgIdentity, *ad_dgAuthz; 42 43 typedef struct dynlist_map_t { 44 AttributeDescription *dlm_member_ad; 45 AttributeDescription *dlm_mapped_ad; 46 struct dynlist_map_t *dlm_next; 47 } dynlist_map_t; 48 49 typedef struct dynlist_info_t { 50 ObjectClass *dli_oc; 51 AttributeDescription *dli_ad; 52 struct dynlist_map_t *dli_dlm; 53 struct berval dli_uri; 54 LDAPURLDesc *dli_lud; 55 struct berval dli_uri_nbase; 56 Filter *dli_uri_filter; 57 struct berval dli_default_filter; 58 struct dynlist_info_t *dli_next; 59 } dynlist_info_t; 60 61 #define DYNLIST_USAGE \ 62 "\"dynlist-attrset <oc> [uri] <URL-ad> [[<mapped-ad>:]<member-ad> ...]\": " 63 64 static dynlist_info_t * 65 dynlist_is_dynlist_next( Operation *op, SlapReply *rs, dynlist_info_t *old_dli ) 66 { 67 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 68 dynlist_info_t *dli; 69 70 Attribute *a; 71 72 if ( old_dli == NULL ) { 73 dli = (dynlist_info_t *)on->on_bi.bi_private; 74 75 } else { 76 dli = old_dli->dli_next; 77 } 78 79 a = attrs_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass ); 80 if ( a == NULL ) { 81 /* FIXME: objectClass must be present; for non-storage 82 * backends, like back-ldap, it needs to be added 83 * to the requested attributes */ 84 return NULL; 85 } 86 87 for ( ; dli; dli = dli->dli_next ) { 88 if ( dli->dli_lud != NULL ) { 89 /* check base and scope */ 90 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) 91 && !dnIsSuffixScope( &rs->sr_entry->e_nname, 92 &dli->dli_uri_nbase, 93 dli->dli_lud->lud_scope ) ) 94 { 95 continue; 96 } 97 98 /* check filter */ 99 if ( dli->dli_uri_filter && test_filter( op, rs->sr_entry, dli->dli_uri_filter ) != LDAP_COMPARE_TRUE ) { 100 continue; 101 } 102 } 103 104 if ( attr_valfind( a, 105 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 106 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 107 &dli->dli_oc->soc_cname, NULL, 108 op->o_tmpmemctx ) == 0 ) 109 { 110 return dli; 111 } 112 } 113 114 return NULL; 115 } 116 117 static int 118 dynlist_make_filter( Operation *op, Entry *e, const char *url, struct berval *oldf, struct berval *newf ) 119 { 120 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 121 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private; 122 123 char *ptr; 124 int needBrackets = 0; 125 126 assert( oldf != NULL ); 127 assert( newf != NULL ); 128 assert( !BER_BVISNULL( oldf ) ); 129 assert( !BER_BVISEMPTY( oldf ) ); 130 131 if ( oldf->bv_val[0] != '(' ) { 132 Debug( LDAP_DEBUG_ANY, "%s: dynlist, DN=\"%s\": missing brackets in URI=\"%s\" filter\n", 133 op->o_log_prefix, e->e_name.bv_val, url ); 134 needBrackets = 2; 135 } 136 137 newf->bv_len = STRLENOF( "(&(!(objectClass=" "))" ")" ) 138 + dli->dli_oc->soc_cname.bv_len + oldf->bv_len + needBrackets; 139 newf->bv_val = op->o_tmpalloc( newf->bv_len + 1, op->o_tmpmemctx ); 140 if ( newf->bv_val == NULL ) { 141 return -1; 142 } 143 ptr = lutil_strcopy( newf->bv_val, "(&(!(objectClass=" ); 144 ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val ); 145 ptr = lutil_strcopy( ptr, "))" ); 146 if ( needBrackets ) *ptr++ = '('; 147 ptr = lutil_strcopy( ptr, oldf->bv_val ); 148 if ( needBrackets ) *ptr++ = ')'; 149 ptr = lutil_strcopy( ptr, ")" ); 150 newf->bv_len = ptr - newf->bv_val; 151 152 return 0; 153 } 154 155 /* dynlist_sc_update() callback info set by dynlist_prepare_entry() */ 156 typedef struct dynlist_sc_t { 157 dynlist_info_t *dlc_dli; 158 Entry *dlc_e; 159 } dynlist_sc_t; 160 161 static int 162 dynlist_sc_update( Operation *op, SlapReply *rs ) 163 { 164 Entry *e; 165 Attribute *a; 166 int opattrs, 167 userattrs; 168 AccessControlState acl_state = ACL_STATE_INIT; 169 170 dynlist_sc_t *dlc; 171 dynlist_map_t *dlm; 172 173 if ( rs->sr_type != REP_SEARCH ) { 174 return 0; 175 } 176 177 dlc = (dynlist_sc_t *)op->o_callback->sc_private; 178 e = dlc->dlc_e; 179 180 assert( e != NULL ); 181 assert( rs->sr_entry != NULL ); 182 183 /* test access to entry */ 184 if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry, 185 NULL, ACL_READ, NULL ) ) 186 { 187 goto done; 188 } 189 190 /* if there is only one member_ad, and it's not mapped, 191 * consider it as old-style member listing */ 192 dlm = dlc->dlc_dli->dli_dlm; 193 if ( dlm && dlm->dlm_mapped_ad == NULL && dlm->dlm_next == NULL ) { 194 /* if access allowed, try to add values, emulating permissive 195 * control to silently ignore duplicates */ 196 if ( access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry, 197 NULL, ACL_READ, NULL ) ) 198 { 199 Modification mod; 200 const char *text = NULL; 201 char textbuf[1024]; 202 struct berval vals[ 2 ], nvals[ 2 ]; 203 204 vals[ 0 ] = rs->sr_entry->e_name; 205 BER_BVZERO( &vals[ 1 ] ); 206 nvals[ 0 ] = rs->sr_entry->e_nname; 207 BER_BVZERO( &nvals[ 1 ] ); 208 209 mod.sm_op = LDAP_MOD_ADD; 210 mod.sm_desc = dlm->dlm_member_ad; 211 mod.sm_type = dlm->dlm_member_ad->ad_cname; 212 mod.sm_values = vals; 213 mod.sm_nvalues = nvals; 214 mod.sm_numvals = 1; 215 216 (void)modify_add_values( e, &mod, /* permissive */ 1, 217 &text, textbuf, sizeof( textbuf ) ); 218 } 219 220 goto done; 221 } 222 223 opattrs = SLAP_OPATTRS( rs->sr_attr_flags ); 224 userattrs = SLAP_USERATTRS( rs->sr_attr_flags ); 225 226 for ( a = rs->sr_entry->e_attrs; a != NULL; a = a->a_next ) { 227 BerVarray vals, nvals = NULL; 228 int i, j, 229 is_oc = a->a_desc == slap_schema.si_ad_objectClass; 230 231 /* if attribute is not requested, skip it */ 232 if ( rs->sr_attrs == NULL ) { 233 if ( is_at_operational( a->a_desc->ad_type ) ) { 234 continue; 235 } 236 237 } else { 238 if ( is_at_operational( a->a_desc->ad_type ) ) { 239 if ( !opattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) ) 240 { 241 continue; 242 } 243 244 } else { 245 if ( !userattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) ) 246 { 247 continue; 248 } 249 } 250 } 251 252 /* test access to attribute */ 253 if ( op->ors_attrsonly ) { 254 if ( !access_allowed( op, rs->sr_entry, a->a_desc, NULL, 255 ACL_READ, &acl_state ) ) 256 { 257 continue; 258 } 259 } 260 261 /* single-value check: keep first only */ 262 if ( is_at_single_value( a->a_desc->ad_type ) ) { 263 if ( attr_find( e->e_attrs, a->a_desc ) != NULL ) { 264 continue; 265 } 266 } 267 268 /* test access to attribute */ 269 i = a->a_numvals; 270 271 vals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx ); 272 if ( a->a_nvals != a->a_vals ) { 273 nvals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx ); 274 } 275 276 for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) { 277 if ( is_oc ) { 278 ObjectClass *soc = oc_bvfind( &a->a_vals[i] ); 279 280 if ( soc->soc_kind == LDAP_SCHEMA_STRUCTURAL ) { 281 continue; 282 } 283 } 284 285 if ( access_allowed( op, rs->sr_entry, a->a_desc, 286 &a->a_nvals[i], ACL_READ, &acl_state ) ) 287 { 288 vals[j] = a->a_vals[i]; 289 if ( nvals ) { 290 nvals[j] = a->a_nvals[i]; 291 } 292 j++; 293 } 294 } 295 296 /* if access allowed, try to add values, emulating permissive 297 * control to silently ignore duplicates */ 298 if ( j != 0 ) { 299 Modification mod; 300 const char *text = NULL; 301 char textbuf[1024]; 302 dynlist_map_t *dlm; 303 AttributeDescription *ad; 304 305 BER_BVZERO( &vals[j] ); 306 if ( nvals ) { 307 BER_BVZERO( &nvals[j] ); 308 } 309 310 ad = a->a_desc; 311 for ( dlm = dlc->dlc_dli->dli_dlm; dlm; dlm = dlm->dlm_next ) { 312 if ( dlm->dlm_member_ad == a->a_desc ) { 313 if ( dlm->dlm_mapped_ad ) { 314 ad = dlm->dlm_mapped_ad; 315 } 316 break; 317 } 318 } 319 320 mod.sm_op = LDAP_MOD_ADD; 321 mod.sm_desc = ad; 322 mod.sm_type = ad->ad_cname; 323 mod.sm_values = vals; 324 mod.sm_nvalues = nvals; 325 mod.sm_numvals = j; 326 327 (void)modify_add_values( e, &mod, /* permissive */ 1, 328 &text, textbuf, sizeof( textbuf ) ); 329 } 330 331 op->o_tmpfree( vals, op->o_tmpmemctx ); 332 if ( nvals ) { 333 op->o_tmpfree( nvals, op->o_tmpmemctx ); 334 } 335 } 336 337 done:; 338 if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) { 339 entry_free( rs->sr_entry ); 340 rs->sr_entry = NULL; 341 rs->sr_flags &= ~REP_ENTRY_MASK; 342 } 343 344 return 0; 345 } 346 347 static int 348 dynlist_prepare_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli ) 349 { 350 Attribute *a, *id = NULL; 351 slap_callback cb; 352 Operation o = *op; 353 struct berval *url; 354 Entry *e; 355 int opattrs, 356 userattrs; 357 dynlist_sc_t dlc = { 0 }; 358 dynlist_map_t *dlm; 359 360 a = attrs_find( rs->sr_entry->e_attrs, dli->dli_ad ); 361 if ( a == NULL ) { 362 /* FIXME: error? */ 363 return SLAP_CB_CONTINUE; 364 } 365 366 opattrs = SLAP_OPATTRS( rs->sr_attr_flags ); 367 userattrs = SLAP_USERATTRS( rs->sr_attr_flags ); 368 369 /* Don't generate member list if it wasn't requested */ 370 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) { 371 AttributeDescription *ad = dlm->dlm_mapped_ad ? dlm->dlm_mapped_ad : dlm->dlm_member_ad; 372 if ( userattrs || ad_inlist( ad, rs->sr_attrs ) ) 373 break; 374 } 375 if ( dli->dli_dlm && !dlm ) 376 return SLAP_CB_CONTINUE; 377 378 if ( ad_dgIdentity && ( id = attrs_find( rs->sr_entry->e_attrs, ad_dgIdentity ))) { 379 Attribute *authz = NULL; 380 381 /* if not rootdn and dgAuthz is present, 382 * check if user can be authorized as dgIdentity */ 383 if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op ) 384 && ( authz = attrs_find( rs->sr_entry->e_attrs, ad_dgAuthz ) ) ) 385 { 386 if ( slap_sasl_matches( op, authz->a_nvals, 387 &o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS ) 388 { 389 return SLAP_CB_CONTINUE; 390 } 391 } 392 393 o.o_dn = id->a_vals[0]; 394 o.o_ndn = id->a_nvals[0]; 395 o.o_groups = NULL; 396 } 397 398 e = rs->sr_entry; 399 /* ensure e is modifiable, but do not replace 400 * sr_entry yet since we have pointers into it */ 401 if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) { 402 e = entry_dup( rs->sr_entry ); 403 } 404 405 dlc.dlc_e = e; 406 dlc.dlc_dli = dli; 407 cb.sc_private = &dlc; 408 cb.sc_response = dynlist_sc_update; 409 cb.sc_cleanup = NULL; 410 cb.sc_next = NULL; 411 412 o.o_callback = &cb; 413 o.ors_deref = LDAP_DEREF_NEVER; 414 o.ors_limit = NULL; 415 o.ors_tlimit = SLAP_NO_LIMIT; 416 o.ors_slimit = SLAP_NO_LIMIT; 417 418 for ( url = a->a_nvals; !BER_BVISNULL( url ); url++ ) { 419 LDAPURLDesc *lud = NULL; 420 int i, j; 421 struct berval dn; 422 int rc; 423 424 BER_BVZERO( &o.o_req_dn ); 425 BER_BVZERO( &o.o_req_ndn ); 426 o.ors_filter = NULL; 427 o.ors_attrs = NULL; 428 BER_BVZERO( &o.ors_filterstr ); 429 430 if ( ldap_url_parse( url->bv_val, &lud ) != LDAP_URL_SUCCESS ) { 431 /* FIXME: error? */ 432 continue; 433 } 434 435 if ( lud->lud_host != NULL ) { 436 /* FIXME: host not allowed; reject as illegal? */ 437 Debug( LDAP_DEBUG_ANY, "dynlist_prepare_entry(\"%s\"): " 438 "illegal URI \"%s\"\n", 439 e->e_name.bv_val, url->bv_val, 0 ); 440 goto cleanup; 441 } 442 443 if ( lud->lud_dn == NULL ) { 444 /* note that an empty base is not honored in terms 445 * of defaultSearchBase, because select_backend() 446 * is not aware of the defaultSearchBase option; 447 * this can be useful in case of a database serving 448 * the empty suffix */ 449 BER_BVSTR( &dn, "" ); 450 451 } else { 452 ber_str2bv( lud->lud_dn, 0, 0, &dn ); 453 } 454 rc = dnPrettyNormal( NULL, &dn, &o.o_req_dn, &o.o_req_ndn, op->o_tmpmemctx ); 455 if ( rc != LDAP_SUCCESS ) { 456 /* FIXME: error? */ 457 goto cleanup; 458 } 459 o.ors_scope = lud->lud_scope; 460 461 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) { 462 if ( dlm->dlm_mapped_ad != NULL ) { 463 break; 464 } 465 } 466 467 if ( dli->dli_dlm && !dlm ) { 468 /* if ( lud->lud_attrs != NULL ), 469 * the URL should be ignored */ 470 o.ors_attrs = slap_anlist_no_attrs; 471 472 } else if ( lud->lud_attrs == NULL ) { 473 o.ors_attrs = rs->sr_attrs; 474 475 } else { 476 for ( i = 0; lud->lud_attrs[i]; i++) 477 /* just count */ ; 478 479 o.ors_attrs = op->o_tmpcalloc( i + 1, sizeof( AttributeName ), op->o_tmpmemctx ); 480 for ( i = 0, j = 0; lud->lud_attrs[i]; i++) { 481 const char *text = NULL; 482 483 ber_str2bv( lud->lud_attrs[i], 0, 0, &o.ors_attrs[j].an_name ); 484 o.ors_attrs[j].an_desc = NULL; 485 (void)slap_bv2ad( &o.ors_attrs[j].an_name, &o.ors_attrs[j].an_desc, &text ); 486 /* FIXME: ignore errors... */ 487 488 if ( rs->sr_attrs == NULL ) { 489 if ( o.ors_attrs[j].an_desc != NULL && 490 is_at_operational( o.ors_attrs[j].an_desc->ad_type ) ) 491 { 492 continue; 493 } 494 495 } else { 496 if ( o.ors_attrs[j].an_desc != NULL && 497 is_at_operational( o.ors_attrs[j].an_desc->ad_type ) ) 498 { 499 if ( !opattrs ) { 500 continue; 501 } 502 503 if ( !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) ) { 504 /* lookup if mapped -- linear search, 505 * not very efficient unless list 506 * is very short */ 507 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) { 508 if ( dlm->dlm_member_ad == o.ors_attrs[j].an_desc ) { 509 break; 510 } 511 } 512 513 if ( dlm == NULL ) { 514 continue; 515 } 516 } 517 518 } else { 519 if ( !userattrs && 520 o.ors_attrs[j].an_desc != NULL && 521 !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) ) 522 { 523 /* lookup if mapped -- linear search, 524 * not very efficient unless list 525 * is very short */ 526 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) { 527 if ( dlm->dlm_member_ad == o.ors_attrs[j].an_desc ) { 528 break; 529 } 530 } 531 532 if ( dlm == NULL ) { 533 continue; 534 } 535 } 536 } 537 } 538 539 j++; 540 } 541 542 if ( j == 0 ) { 543 goto cleanup; 544 } 545 546 BER_BVZERO( &o.ors_attrs[j].an_name ); 547 } 548 549 if ( lud->lud_filter == NULL ) { 550 ber_dupbv_x( &o.ors_filterstr, 551 &dli->dli_default_filter, op->o_tmpmemctx ); 552 553 } else { 554 struct berval flt; 555 ber_str2bv( lud->lud_filter, 0, 0, &flt ); 556 if ( dynlist_make_filter( op, rs->sr_entry, url->bv_val, &flt, &o.ors_filterstr ) ) { 557 /* error */ 558 goto cleanup; 559 } 560 } 561 o.ors_filter = str2filter_x( op, o.ors_filterstr.bv_val ); 562 if ( o.ors_filter == NULL ) { 563 goto cleanup; 564 } 565 566 o.o_bd = select_backend( &o.o_req_ndn, 1 ); 567 if ( o.o_bd && o.o_bd->be_search ) { 568 SlapReply r = { REP_SEARCH }; 569 r.sr_attr_flags = slap_attr_flags( o.ors_attrs ); 570 (void)o.o_bd->be_search( &o, &r ); 571 } 572 573 cleanup:; 574 if ( id ) { 575 slap_op_groups_free( &o ); 576 } 577 if ( o.ors_filter ) { 578 filter_free_x( &o, o.ors_filter, 1 ); 579 } 580 if ( o.ors_attrs && o.ors_attrs != rs->sr_attrs 581 && o.ors_attrs != slap_anlist_no_attrs ) 582 { 583 op->o_tmpfree( o.ors_attrs, op->o_tmpmemctx ); 584 } 585 if ( !BER_BVISNULL( &o.o_req_dn ) ) { 586 op->o_tmpfree( o.o_req_dn.bv_val, op->o_tmpmemctx ); 587 } 588 if ( !BER_BVISNULL( &o.o_req_ndn ) ) { 589 op->o_tmpfree( o.o_req_ndn.bv_val, op->o_tmpmemctx ); 590 } 591 assert( BER_BVISNULL( &o.ors_filterstr ) 592 || o.ors_filterstr.bv_val != lud->lud_filter ); 593 op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx ); 594 ldap_free_urldesc( lud ); 595 } 596 597 if ( e != rs->sr_entry ) { 598 rs_replace_entry( op, rs, (slap_overinst *)op->o_bd->bd_info, e ); 599 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED; 600 } 601 602 return SLAP_CB_CONTINUE; 603 } 604 605 /* dynlist_sc_compare_entry() callback set by dynlist_compare() */ 606 typedef struct dynlist_cc_t { 607 slap_callback dc_cb; 608 # define dc_ava dc_cb.sc_private /* attr:val to compare with */ 609 int *dc_res; 610 } dynlist_cc_t; 611 612 static int 613 dynlist_sc_compare_entry( Operation *op, SlapReply *rs ) 614 { 615 if ( rs->sr_type == REP_SEARCH && rs->sr_entry != NULL ) { 616 dynlist_cc_t *dc = (dynlist_cc_t *)op->o_callback; 617 AttributeAssertion *ava = dc->dc_ava; 618 Attribute *a = attrs_find( rs->sr_entry->e_attrs, ava->aa_desc ); 619 620 if ( a != NULL ) { 621 while ( LDAP_SUCCESS != attr_valfind( a, 622 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 623 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 624 &ava->aa_value, NULL, op->o_tmpmemctx ) 625 && (a = attrs_find( a->a_next, ava->aa_desc )) != NULL ) 626 ; 627 *dc->dc_res = a ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE; 628 } 629 } 630 631 return 0; 632 } 633 634 static int 635 dynlist_compare( Operation *op, SlapReply *rs ) 636 { 637 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 638 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private; 639 Operation o = *op; 640 Entry *e = NULL; 641 dynlist_map_t *dlm; 642 BackendDB *be; 643 644 for ( ; dli != NULL; dli = dli->dli_next ) { 645 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) 646 if ( op->oq_compare.rs_ava->aa_desc == dlm->dlm_member_ad ) 647 break; 648 649 if ( dlm ) { 650 /* This compare is for one of the attributes we're 651 * interested in. We'll use slapd's existing dyngroup 652 * evaluator to get the answer we want. 653 */ 654 BerVarray id = NULL, authz = NULL; 655 656 o.o_do_not_cache = 1; 657 658 if ( ad_dgIdentity && backend_attribute( &o, NULL, &o.o_req_ndn, 659 ad_dgIdentity, &id, ACL_READ ) == LDAP_SUCCESS ) 660 { 661 /* if not rootdn and dgAuthz is present, 662 * check if user can be authorized as dgIdentity */ 663 if ( ad_dgAuthz && !BER_BVISEMPTY( id ) && !be_isroot( op ) 664 && backend_attribute( &o, NULL, &o.o_req_ndn, 665 ad_dgAuthz, &authz, ACL_READ ) == LDAP_SUCCESS ) 666 { 667 668 rs->sr_err = slap_sasl_matches( op, authz, 669 &o.o_ndn, &o.o_ndn ); 670 ber_bvarray_free_x( authz, op->o_tmpmemctx ); 671 if ( rs->sr_err != LDAP_SUCCESS ) { 672 goto done; 673 } 674 } 675 676 o.o_dn = *id; 677 o.o_ndn = *id; 678 o.o_groups = NULL; /* authz changed, invalidate cached groups */ 679 } 680 681 rs->sr_err = backend_group( &o, NULL, &o.o_req_ndn, 682 &o.oq_compare.rs_ava->aa_value, dli->dli_oc, dli->dli_ad ); 683 switch ( rs->sr_err ) { 684 case LDAP_SUCCESS: 685 rs->sr_err = LDAP_COMPARE_TRUE; 686 break; 687 688 case LDAP_NO_SUCH_OBJECT: 689 /* NOTE: backend_group() returns noSuchObject 690 * if op_ndn does not exist; however, since 691 * dynamic list expansion means that the 692 * member attribute is virtually present, the 693 * non-existence of the asserted value implies 694 * the assertion is FALSE rather than 695 * UNDEFINED */ 696 rs->sr_err = LDAP_COMPARE_FALSE; 697 break; 698 } 699 700 done:; 701 if ( id ) ber_bvarray_free_x( id, o.o_tmpmemctx ); 702 703 return SLAP_CB_CONTINUE; 704 } 705 } 706 707 be = select_backend( &o.o_req_ndn, 1 ); 708 if ( !be || !be->be_search ) { 709 return SLAP_CB_CONTINUE; 710 } 711 712 if ( overlay_entry_get_ov( &o, &o.o_req_ndn, NULL, NULL, 0, &e, on ) != 713 LDAP_SUCCESS || e == NULL ) 714 { 715 return SLAP_CB_CONTINUE; 716 } 717 718 /* check for dynlist objectClass; done if not found */ 719 dli = (dynlist_info_t *)on->on_bi.bi_private; 720 while ( dli != NULL && !is_entry_objectclass_or_sub( e, dli->dli_oc ) ) { 721 dli = dli->dli_next; 722 } 723 if ( dli == NULL ) { 724 goto release; 725 } 726 727 if ( ad_dgIdentity ) { 728 Attribute *id = attrs_find( e->e_attrs, ad_dgIdentity ); 729 if ( id ) { 730 Attribute *authz; 731 732 /* if not rootdn and dgAuthz is present, 733 * check if user can be authorized as dgIdentity */ 734 if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op ) 735 && ( authz = attrs_find( e->e_attrs, ad_dgAuthz ) ) ) 736 { 737 if ( slap_sasl_matches( op, authz->a_nvals, 738 &o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS ) 739 { 740 goto release; 741 } 742 } 743 744 o.o_dn = id->a_vals[0]; 745 o.o_ndn = id->a_nvals[0]; 746 o.o_groups = NULL; 747 } 748 } 749 750 /* generate dynamic list with dynlist_response() and compare */ 751 { 752 SlapReply r = { REP_SEARCH }; 753 dynlist_cc_t dc = { { 0, dynlist_sc_compare_entry, 0, 0 }, 0 }; 754 AttributeName an[2]; 755 756 dc.dc_ava = op->orc_ava; 757 dc.dc_res = &rs->sr_err; 758 o.o_callback = (slap_callback *) &dc; 759 760 o.o_tag = LDAP_REQ_SEARCH; 761 o.ors_limit = NULL; 762 o.ors_tlimit = SLAP_NO_LIMIT; 763 o.ors_slimit = SLAP_NO_LIMIT; 764 765 o.ors_filterstr = *slap_filterstr_objectClass_pres; 766 o.ors_filter = (Filter *) slap_filter_objectClass_pres; 767 768 o.ors_scope = LDAP_SCOPE_BASE; 769 o.ors_deref = LDAP_DEREF_NEVER; 770 an[0].an_name = op->orc_ava->aa_desc->ad_cname; 771 an[0].an_desc = op->orc_ava->aa_desc; 772 BER_BVZERO( &an[1].an_name ); 773 o.ors_attrs = an; 774 o.ors_attrsonly = 0; 775 776 o.o_acl_priv = ACL_COMPARE; 777 778 o.o_bd = be; 779 (void)be->be_search( &o, &r ); 780 781 if ( o.o_dn.bv_val != op->o_dn.bv_val ) { 782 slap_op_groups_free( &o ); 783 } 784 } 785 786 release:; 787 if ( e != NULL ) { 788 overlay_entry_release_ov( &o, e, 0, on ); 789 } 790 791 return SLAP_CB_CONTINUE; 792 } 793 794 static int 795 dynlist_response( Operation *op, SlapReply *rs ) 796 { 797 switch ( op->o_tag ) { 798 case LDAP_REQ_SEARCH: 799 if ( rs->sr_type == REP_SEARCH && !get_manageDSAit( op ) ) 800 { 801 int rc = SLAP_CB_CONTINUE; 802 dynlist_info_t *dli = NULL; 803 804 while ( (dli = dynlist_is_dynlist_next( op, rs, dli )) != NULL ) { 805 rc = dynlist_prepare_entry( op, rs, dli ); 806 } 807 808 return rc; 809 } 810 break; 811 812 case LDAP_REQ_COMPARE: 813 switch ( rs->sr_err ) { 814 /* NOTE: we waste a few cycles running the dynamic list 815 * also when the result is FALSE, which occurs if the 816 * dynamic entry itself contains the AVA attribute */ 817 /* FIXME: this approach is less than optimal; a dedicated 818 * compare op should be implemented, that fetches the 819 * entry, checks if it has the appropriate objectClass 820 * and, in case, runs a compare thru all the URIs, 821 * stopping at the first positive occurrence; see ITS#3756 */ 822 case LDAP_COMPARE_FALSE: 823 case LDAP_NO_SUCH_ATTRIBUTE: 824 return dynlist_compare( op, rs ); 825 } 826 break; 827 } 828 829 return SLAP_CB_CONTINUE; 830 } 831 832 static int 833 dynlist_build_def_filter( dynlist_info_t *dli ) 834 { 835 char *ptr; 836 837 dli->dli_default_filter.bv_len = STRLENOF( "(!(objectClass=" "))" ) 838 + dli->dli_oc->soc_cname.bv_len; 839 dli->dli_default_filter.bv_val = ch_malloc( dli->dli_default_filter.bv_len + 1 ); 840 if ( dli->dli_default_filter.bv_val == NULL ) { 841 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: malloc failed.\n", 842 0, 0, 0 ); 843 return -1; 844 } 845 846 ptr = lutil_strcopy( dli->dli_default_filter.bv_val, "(!(objectClass=" ); 847 ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val ); 848 ptr = lutil_strcopy( ptr, "))" ); 849 850 assert( ptr == &dli->dli_default_filter.bv_val[dli->dli_default_filter.bv_len] ); 851 852 return 0; 853 } 854 855 enum { 856 DL_ATTRSET = 1, 857 DL_ATTRPAIR, 858 DL_ATTRPAIR_COMPAT, 859 DL_LAST 860 }; 861 862 static ConfigDriver dl_cfgen; 863 864 /* XXXmanu 255 is the maximum arguments we allow. Can we go beyond? */ 865 static ConfigTable dlcfg[] = { 866 { "dynlist-attrset", "group-oc> [uri] <URL-ad> <[mapped:]member-ad> [...]", 867 3, 0, 0, ARG_MAGIC|DL_ATTRSET, dl_cfgen, 868 "( OLcfgOvAt:8.1 NAME 'olcDlAttrSet' " 869 "DESC 'Dynamic list: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' " 870 "EQUALITY caseIgnoreMatch " 871 "SYNTAX OMsDirectoryString " 872 "X-ORDERED 'VALUES' )", 873 NULL, NULL }, 874 { "dynlist-attrpair", "member-ad> <URL-ad", 875 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR, dl_cfgen, 876 NULL, NULL, NULL }, 877 #ifdef TAKEOVER_DYNGROUP 878 { "attrpair", "member-ad> <URL-ad", 879 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR_COMPAT, dl_cfgen, 880 NULL, NULL, NULL }, 881 #endif 882 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 883 }; 884 885 static ConfigOCs dlocs[] = { 886 { "( OLcfgOvOc:8.1 " 887 "NAME 'olcDynamicList' " 888 "DESC 'Dynamic list configuration' " 889 "SUP olcOverlayConfig " 890 "MAY olcDLattrSet )", 891 Cft_Overlay, dlcfg, NULL, NULL }, 892 { NULL, 0, NULL } 893 }; 894 895 static int 896 dl_cfgen( ConfigArgs *c ) 897 { 898 slap_overinst *on = (slap_overinst *)c->bi; 899 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private; 900 901 int rc = 0, i; 902 903 if ( c->op == SLAP_CONFIG_EMIT ) { 904 switch( c->type ) { 905 case DL_ATTRSET: 906 for ( i = 0; dli; i++, dli = dli->dli_next ) { 907 struct berval bv; 908 char *ptr = c->cr_msg; 909 dynlist_map_t *dlm; 910 911 assert( dli->dli_oc != NULL ); 912 assert( dli->dli_ad != NULL ); 913 914 /* FIXME: check buffer overflow! */ 915 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ), 916 SLAP_X_ORDERED_FMT "%s", i, 917 dli->dli_oc->soc_cname.bv_val ); 918 919 if ( !BER_BVISNULL( &dli->dli_uri ) ) { 920 *ptr++ = ' '; 921 *ptr++ = '"'; 922 ptr = lutil_strncopy( ptr, dli->dli_uri.bv_val, 923 dli->dli_uri.bv_len ); 924 *ptr++ = '"'; 925 } 926 927 *ptr++ = ' '; 928 ptr = lutil_strncopy( ptr, dli->dli_ad->ad_cname.bv_val, 929 dli->dli_ad->ad_cname.bv_len ); 930 931 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) { 932 ptr[ 0 ] = ' '; 933 ptr++; 934 if ( dlm->dlm_mapped_ad ) { 935 ptr = lutil_strcopy( ptr, dlm->dlm_mapped_ad->ad_cname.bv_val ); 936 ptr[ 0 ] = ':'; 937 ptr++; 938 } 939 940 ptr = lutil_strcopy( ptr, dlm->dlm_member_ad->ad_cname.bv_val ); 941 } 942 943 bv.bv_val = c->cr_msg; 944 bv.bv_len = ptr - bv.bv_val; 945 value_add_one( &c->rvalue_vals, &bv ); 946 } 947 break; 948 949 case DL_ATTRPAIR_COMPAT: 950 case DL_ATTRPAIR: 951 rc = 1; 952 break; 953 954 default: 955 rc = 1; 956 break; 957 } 958 959 return rc; 960 961 } else if ( c->op == LDAP_MOD_DELETE ) { 962 switch( c->type ) { 963 case DL_ATTRSET: 964 if ( c->valx < 0 ) { 965 dynlist_info_t *dli_next; 966 967 for ( dli_next = dli; dli_next; dli = dli_next ) { 968 dynlist_map_t *dlm = dli->dli_dlm; 969 dynlist_map_t *dlm_next; 970 971 dli_next = dli->dli_next; 972 973 if ( !BER_BVISNULL( &dli->dli_uri ) ) { 974 ch_free( dli->dli_uri.bv_val ); 975 } 976 977 if ( dli->dli_lud != NULL ) { 978 ldap_free_urldesc( dli->dli_lud ); 979 } 980 981 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) { 982 ber_memfree( dli->dli_uri_nbase.bv_val ); 983 } 984 985 if ( dli->dli_uri_filter != NULL ) { 986 filter_free( dli->dli_uri_filter ); 987 } 988 989 ch_free( dli->dli_default_filter.bv_val ); 990 991 while ( dlm != NULL ) { 992 dlm_next = dlm->dlm_next; 993 ch_free( dlm ); 994 dlm = dlm_next; 995 } 996 ch_free( dli ); 997 } 998 999 on->on_bi.bi_private = NULL; 1000 1001 } else { 1002 dynlist_info_t **dlip; 1003 dynlist_map_t *dlm; 1004 dynlist_map_t *dlm_next; 1005 1006 for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private; 1007 i < c->valx; i++ ) 1008 { 1009 if ( *dlip == NULL ) { 1010 return 1; 1011 } 1012 dlip = &(*dlip)->dli_next; 1013 } 1014 1015 dli = *dlip; 1016 *dlip = dli->dli_next; 1017 1018 if ( !BER_BVISNULL( &dli->dli_uri ) ) { 1019 ch_free( dli->dli_uri.bv_val ); 1020 } 1021 1022 if ( dli->dli_lud != NULL ) { 1023 ldap_free_urldesc( dli->dli_lud ); 1024 } 1025 1026 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) { 1027 ber_memfree( dli->dli_uri_nbase.bv_val ); 1028 } 1029 1030 if ( dli->dli_uri_filter != NULL ) { 1031 filter_free( dli->dli_uri_filter ); 1032 } 1033 1034 ch_free( dli->dli_default_filter.bv_val ); 1035 1036 dlm = dli->dli_dlm; 1037 while ( dlm != NULL ) { 1038 dlm_next = dlm->dlm_next; 1039 ch_free( dlm ); 1040 dlm = dlm_next; 1041 } 1042 ch_free( dli ); 1043 1044 dli = (dynlist_info_t *)on->on_bi.bi_private; 1045 } 1046 break; 1047 1048 case DL_ATTRPAIR_COMPAT: 1049 case DL_ATTRPAIR: 1050 rc = 1; 1051 break; 1052 1053 default: 1054 rc = 1; 1055 break; 1056 } 1057 1058 return rc; 1059 } 1060 1061 switch( c->type ) { 1062 case DL_ATTRSET: { 1063 dynlist_info_t **dlip, 1064 *dli_next = NULL; 1065 ObjectClass *oc = NULL; 1066 AttributeDescription *ad = NULL; 1067 int attridx = 2; 1068 LDAPURLDesc *lud = NULL; 1069 struct berval nbase = BER_BVNULL; 1070 Filter *filter = NULL; 1071 struct berval uri = BER_BVNULL; 1072 dynlist_map_t *dlm = NULL, *dlml = NULL; 1073 const char *text; 1074 1075 oc = oc_find( c->argv[ 1 ] ); 1076 if ( oc == NULL ) { 1077 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE 1078 "unable to find ObjectClass \"%s\"", 1079 c->argv[ 1 ] ); 1080 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1081 c->log, c->cr_msg, 0 ); 1082 return 1; 1083 } 1084 1085 if ( strncasecmp( c->argv[ attridx ], "ldap://", STRLENOF("ldap://") ) == 0 ) { 1086 if ( ldap_url_parse( c->argv[ attridx ], &lud ) != LDAP_URL_SUCCESS ) { 1087 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE 1088 "unable to parse URI \"%s\"", 1089 c->argv[ attridx ] ); 1090 rc = 1; 1091 goto done_uri; 1092 } 1093 1094 if ( lud->lud_host != NULL ) { 1095 if ( lud->lud_host[0] == '\0' ) { 1096 ch_free( lud->lud_host ); 1097 lud->lud_host = NULL; 1098 1099 } else { 1100 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE 1101 "host not allowed in URI \"%s\"", 1102 c->argv[ attridx ] ); 1103 rc = 1; 1104 goto done_uri; 1105 } 1106 } 1107 1108 if ( lud->lud_attrs != NULL ) { 1109 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE 1110 "attrs not allowed in URI \"%s\"", 1111 c->argv[ attridx ] ); 1112 rc = 1; 1113 goto done_uri; 1114 } 1115 1116 if ( lud->lud_exts != NULL ) { 1117 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE 1118 "extensions not allowed in URI \"%s\"", 1119 c->argv[ attridx ] ); 1120 rc = 1; 1121 goto done_uri; 1122 } 1123 1124 if ( lud->lud_dn != NULL && lud->lud_dn[ 0 ] != '\0' ) { 1125 struct berval dn; 1126 ber_str2bv( lud->lud_dn, 0, 0, &dn ); 1127 rc = dnNormalize( 0, NULL, NULL, &dn, &nbase, NULL ); 1128 if ( rc != LDAP_SUCCESS ) { 1129 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE 1130 "DN normalization failed in URI \"%s\"", 1131 c->argv[ attridx ] ); 1132 goto done_uri; 1133 } 1134 } 1135 1136 if ( lud->lud_filter != NULL && lud->lud_filter[ 0 ] != '\0' ) { 1137 filter = str2filter( lud->lud_filter ); 1138 if ( filter == NULL ) { 1139 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE 1140 "filter parsing failed in URI \"%s\"", 1141 c->argv[ attridx ] ); 1142 rc = 1; 1143 goto done_uri; 1144 } 1145 } 1146 1147 ber_str2bv( c->argv[ attridx ], 0, 1, &uri ); 1148 1149 done_uri:; 1150 if ( rc ) { 1151 if ( lud ) { 1152 ldap_free_urldesc( lud ); 1153 } 1154 1155 if ( !BER_BVISNULL( &nbase ) ) { 1156 ber_memfree( nbase.bv_val ); 1157 } 1158 1159 if ( filter != NULL ) { 1160 filter_free( filter ); 1161 } 1162 1163 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1164 c->log, c->cr_msg, 0 ); 1165 1166 return rc; 1167 } 1168 1169 attridx++; 1170 } 1171 1172 rc = slap_str2ad( c->argv[ attridx ], &ad, &text ); 1173 if ( rc != LDAP_SUCCESS ) { 1174 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE 1175 "unable to find AttributeDescription \"%s\"", 1176 c->argv[ attridx ] ); 1177 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1178 c->log, c->cr_msg, 0 ); 1179 return 1; 1180 } 1181 1182 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) { 1183 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE 1184 "AttributeDescription \"%s\" " 1185 "must be a subtype of \"labeledURI\"", 1186 c->argv[ attridx ] ); 1187 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1188 c->log, c->cr_msg, 0 ); 1189 return 1; 1190 } 1191 1192 attridx++; 1193 1194 for ( i = attridx; i < c->argc; i++ ) { 1195 char *arg; 1196 char *cp; 1197 AttributeDescription *member_ad = NULL; 1198 AttributeDescription *mapped_ad = NULL; 1199 dynlist_map_t *dlmp; 1200 1201 1202 /* 1203 * If no mapped attribute is given, dn is used 1204 * for backward compatibility. 1205 */ 1206 arg = c->argv[i]; 1207 if ( ( cp = strchr( arg, ':' ) ) != NULL ) { 1208 struct berval bv; 1209 ber_str2bv( arg, cp - arg, 0, &bv ); 1210 rc = slap_bv2ad( &bv, &mapped_ad, &text ); 1211 if ( rc != LDAP_SUCCESS ) { 1212 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1213 DYNLIST_USAGE 1214 "unable to find mapped AttributeDescription #%d \"%s\"\n", 1215 i - 3, c->argv[ i ] ); 1216 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1217 c->log, c->cr_msg, 0 ); 1218 return 1; 1219 } 1220 arg = cp + 1; 1221 } 1222 1223 rc = slap_str2ad( arg, &member_ad, &text ); 1224 if ( rc != LDAP_SUCCESS ) { 1225 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1226 DYNLIST_USAGE 1227 "unable to find AttributeDescription #%d \"%s\"\n", 1228 i - 3, c->argv[ i ] ); 1229 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1230 c->log, c->cr_msg, 0 ); 1231 return 1; 1232 } 1233 1234 dlmp = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) ); 1235 if ( dlm == NULL ) { 1236 dlm = dlmp; 1237 } 1238 dlmp->dlm_member_ad = member_ad; 1239 dlmp->dlm_mapped_ad = mapped_ad; 1240 dlmp->dlm_next = NULL; 1241 1242 if ( dlml != NULL ) 1243 dlml->dlm_next = dlmp; 1244 dlml = dlmp; 1245 } 1246 1247 if ( c->valx > 0 ) { 1248 int i; 1249 1250 for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private; 1251 i < c->valx; i++ ) 1252 { 1253 if ( *dlip == NULL ) { 1254 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1255 DYNLIST_USAGE 1256 "invalid index {%d}\n", 1257 c->valx ); 1258 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1259 c->log, c->cr_msg, 0 ); 1260 return 1; 1261 } 1262 dlip = &(*dlip)->dli_next; 1263 } 1264 dli_next = *dlip; 1265 1266 } else { 1267 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private; 1268 *dlip; dlip = &(*dlip)->dli_next ) 1269 /* goto last */; 1270 } 1271 1272 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) ); 1273 1274 (*dlip)->dli_oc = oc; 1275 (*dlip)->dli_ad = ad; 1276 (*dlip)->dli_dlm = dlm; 1277 (*dlip)->dli_next = dli_next; 1278 1279 (*dlip)->dli_lud = lud; 1280 (*dlip)->dli_uri_nbase = nbase; 1281 (*dlip)->dli_uri_filter = filter; 1282 (*dlip)->dli_uri = uri; 1283 1284 rc = dynlist_build_def_filter( *dlip ); 1285 1286 } break; 1287 1288 case DL_ATTRPAIR_COMPAT: 1289 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1290 "warning: \"attrpair\" only supported for limited " 1291 "backward compatibility with overlay \"dyngroup\"" ); 1292 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); 1293 /* fallthru */ 1294 1295 case DL_ATTRPAIR: { 1296 dynlist_info_t **dlip; 1297 ObjectClass *oc = NULL; 1298 AttributeDescription *ad = NULL, 1299 *member_ad = NULL; 1300 const char *text; 1301 1302 oc = oc_find( "groupOfURLs" ); 1303 if ( oc == NULL ) { 1304 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1305 "\"dynlist-attrpair <member-ad> <URL-ad>\": " 1306 "unable to find default ObjectClass \"groupOfURLs\"" ); 1307 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1308 c->log, c->cr_msg, 0 ); 1309 return 1; 1310 } 1311 1312 rc = slap_str2ad( c->argv[ 1 ], &member_ad, &text ); 1313 if ( rc != LDAP_SUCCESS ) { 1314 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1315 "\"dynlist-attrpair <member-ad> <URL-ad>\": " 1316 "unable to find AttributeDescription \"%s\"", 1317 c->argv[ 1 ] ); 1318 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1319 c->log, c->cr_msg, 0 ); 1320 return 1; 1321 } 1322 1323 rc = slap_str2ad( c->argv[ 2 ], &ad, &text ); 1324 if ( rc != LDAP_SUCCESS ) { 1325 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1326 "\"dynlist-attrpair <member-ad> <URL-ad>\": " 1327 "unable to find AttributeDescription \"%s\"\n", 1328 c->argv[ 2 ] ); 1329 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1330 c->log, c->cr_msg, 0 ); 1331 return 1; 1332 } 1333 1334 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) { 1335 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1336 DYNLIST_USAGE 1337 "AttributeDescription \"%s\" " 1338 "must be a subtype of \"labeledURI\"", 1339 c->argv[ 2 ] ); 1340 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1341 c->log, c->cr_msg, 0 ); 1342 return 1; 1343 } 1344 1345 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private; 1346 *dlip; dlip = &(*dlip)->dli_next ) 1347 { 1348 /* 1349 * The same URL attribute / member attribute pair 1350 * cannot be repeated, but we enforce this only 1351 * when the member attribute is unique. Performing 1352 * the check for multiple values would require 1353 * sorting and comparing the lists, which is left 1354 * as a future improvement 1355 */ 1356 if ( (*dlip)->dli_ad == ad && 1357 (*dlip)->dli_dlm->dlm_next == NULL && 1358 member_ad == (*dlip)->dli_dlm->dlm_member_ad ) { 1359 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1360 "\"dynlist-attrpair <member-ad> <URL-ad>\": " 1361 "URL attributeDescription \"%s\" already mapped.\n", 1362 ad->ad_cname.bv_val ); 1363 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1364 c->log, c->cr_msg, 0 ); 1365 #if 0 1366 /* make it a warning... */ 1367 return 1; 1368 #endif 1369 } 1370 } 1371 1372 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) ); 1373 1374 (*dlip)->dli_oc = oc; 1375 (*dlip)->dli_ad = ad; 1376 (*dlip)->dli_dlm = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) ); 1377 (*dlip)->dli_dlm->dlm_member_ad = member_ad; 1378 (*dlip)->dli_dlm->dlm_mapped_ad = NULL; 1379 1380 rc = dynlist_build_def_filter( *dlip ); 1381 1382 } break; 1383 1384 default: 1385 rc = 1; 1386 break; 1387 } 1388 1389 return rc; 1390 } 1391 1392 static int 1393 dynlist_db_open( 1394 BackendDB *be, 1395 ConfigReply *cr ) 1396 { 1397 slap_overinst *on = (slap_overinst *) be->bd_info; 1398 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private; 1399 ObjectClass *oc = NULL; 1400 AttributeDescription *ad = NULL; 1401 const char *text; 1402 int rc; 1403 1404 if ( dli == NULL ) { 1405 dli = ch_calloc( 1, sizeof( dynlist_info_t ) ); 1406 on->on_bi.bi_private = (void *)dli; 1407 } 1408 1409 for ( ; dli; dli = dli->dli_next ) { 1410 if ( dli->dli_oc == NULL ) { 1411 if ( oc == NULL ) { 1412 oc = oc_find( "groupOfURLs" ); 1413 if ( oc == NULL ) { 1414 snprintf( cr->msg, sizeof( cr->msg), 1415 "unable to fetch objectClass \"groupOfURLs\"" ); 1416 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 ); 1417 return 1; 1418 } 1419 } 1420 1421 dli->dli_oc = oc; 1422 } 1423 1424 if ( dli->dli_ad == NULL ) { 1425 if ( ad == NULL ) { 1426 rc = slap_str2ad( "memberURL", &ad, &text ); 1427 if ( rc != LDAP_SUCCESS ) { 1428 snprintf( cr->msg, sizeof( cr->msg), 1429 "unable to fetch attributeDescription \"memberURL\": %d (%s)", 1430 rc, text ); 1431 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 ); 1432 return 1; 1433 } 1434 } 1435 1436 dli->dli_ad = ad; 1437 } 1438 1439 if ( BER_BVISNULL( &dli->dli_default_filter ) ) { 1440 rc = dynlist_build_def_filter( dli ); 1441 if ( rc != 0 ) { 1442 return rc; 1443 } 1444 } 1445 } 1446 1447 if ( ad_dgIdentity == NULL ) { 1448 rc = slap_str2ad( "dgIdentity", &ad_dgIdentity, &text ); 1449 if ( rc != LDAP_SUCCESS ) { 1450 snprintf( cr->msg, sizeof( cr->msg), 1451 "unable to fetch attributeDescription \"dgIdentity\": %d (%s)", 1452 rc, text ); 1453 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg, 0, 0 ); 1454 /* Just a warning */ 1455 } 1456 } 1457 1458 if ( ad_dgAuthz == NULL ) { 1459 rc = slap_str2ad( "dgAuthz", &ad_dgAuthz, &text ); 1460 if ( rc != LDAP_SUCCESS ) { 1461 snprintf( cr->msg, sizeof( cr->msg), 1462 "unable to fetch attributeDescription \"dgAuthz\": %d (%s)", 1463 rc, text ); 1464 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg, 0, 0 ); 1465 /* Just a warning */ 1466 } 1467 } 1468 1469 return 0; 1470 } 1471 1472 static int 1473 dynlist_db_destroy( 1474 BackendDB *be, 1475 ConfigReply *cr ) 1476 { 1477 slap_overinst *on = (slap_overinst *) be->bd_info; 1478 1479 if ( on->on_bi.bi_private ) { 1480 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private, 1481 *dli_next; 1482 1483 for ( dli_next = dli; dli_next; dli = dli_next ) { 1484 dynlist_map_t *dlm; 1485 dynlist_map_t *dlm_next; 1486 1487 dli_next = dli->dli_next; 1488 1489 if ( !BER_BVISNULL( &dli->dli_uri ) ) { 1490 ch_free( dli->dli_uri.bv_val ); 1491 } 1492 1493 if ( dli->dli_lud != NULL ) { 1494 ldap_free_urldesc( dli->dli_lud ); 1495 } 1496 1497 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) { 1498 ber_memfree( dli->dli_uri_nbase.bv_val ); 1499 } 1500 1501 if ( dli->dli_uri_filter != NULL ) { 1502 filter_free( dli->dli_uri_filter ); 1503 } 1504 1505 ch_free( dli->dli_default_filter.bv_val ); 1506 1507 dlm = dli->dli_dlm; 1508 while ( dlm != NULL ) { 1509 dlm_next = dlm->dlm_next; 1510 ch_free( dlm ); 1511 dlm = dlm_next; 1512 } 1513 ch_free( dli ); 1514 } 1515 } 1516 1517 return 0; 1518 } 1519 1520 static slap_overinst dynlist = { { NULL } }; 1521 #ifdef TAKEOVER_DYNGROUP 1522 static char *obsolete_names[] = { 1523 "dyngroup", 1524 NULL 1525 }; 1526 #endif 1527 1528 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC 1529 static 1530 #endif /* SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC */ 1531 int 1532 dynlist_initialize(void) 1533 { 1534 int rc = 0; 1535 1536 dynlist.on_bi.bi_type = "dynlist"; 1537 1538 #ifdef TAKEOVER_DYNGROUP 1539 /* makes dynlist incompatible with dyngroup */ 1540 dynlist.on_bi.bi_obsolete_names = obsolete_names; 1541 #endif 1542 1543 dynlist.on_bi.bi_db_config = config_generic_wrapper; 1544 dynlist.on_bi.bi_db_open = dynlist_db_open; 1545 dynlist.on_bi.bi_db_destroy = dynlist_db_destroy; 1546 1547 dynlist.on_response = dynlist_response; 1548 1549 dynlist.on_bi.bi_cf_ocs = dlocs; 1550 1551 rc = config_register_schema( dlcfg, dlocs ); 1552 if ( rc ) { 1553 return rc; 1554 } 1555 1556 return overlay_register( &dynlist ); 1557 } 1558 1559 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC 1560 int 1561 init_module( int argc, char *argv[] ) 1562 { 1563 return dynlist_initialize(); 1564 } 1565 #endif 1566 1567 #endif /* SLAPD_OVER_DYNLIST */ 1568