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