1/* autogroup.c - automatic group overlay */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2007-2011 The OpenLDAP Foundation. 6 * Portions Copyright 2007 Michał Szulczyński. 7 * Portions Copyright 2009 Howard Chu. 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 Michał Szulczyński for inclusion in 20 * OpenLDAP Software. Additional significant contributors include: 21 * Howard Chu 22 * Raphael Ouazana 23 * Norbert Pueschel 24 * Christian Manal 25 */ 26 27#include "portable.h" 28 29#include <stdio.h> 30 31#include <ac/string.h> 32 33#include "slap.h" 34#include "config.h" 35#include "lutil.h" 36 37#ifndef SLAPD_MEMBEROF_ATTR 38#define SLAPD_MEMBEROF_ATTR "memberOf" 39#endif 40 41/* Filter represents the memberURL of a group. */ 42typedef struct autogroup_filter_t { 43 struct berval agf_dn; /* The base DN in memberURL */ 44 struct berval agf_ndn; 45 struct berval agf_filterstr; 46 Filter *agf_filter; 47 int agf_scope; 48 AttributeName *agf_anlist; 49 struct autogroup_filter_t *agf_next; 50} autogroup_filter_t; 51 52/* Description of group attributes. */ 53typedef struct autogroup_def_t { 54 ObjectClass *agd_oc; 55 AttributeDescription *agd_member_url_ad; 56 AttributeDescription *agd_member_ad; 57 struct autogroup_def_t *agd_next; 58} autogroup_def_t; 59 60/* Represents the group entry. */ 61typedef struct autogroup_entry_t { 62 BerValue age_dn; 63 BerValue age_ndn; 64 autogroup_filter_t *age_filter; /* List of filters made from memberURLs */ 65 autogroup_def_t *age_def; /* Attribute definition */ 66 ldap_pvt_thread_mutex_t age_mutex; 67 int age_mustrefresh; /* Defined in request to refresh in response */ 68 int age_modrdn_olddnmodified; /* Defined in request to refresh in response */ 69 struct autogroup_entry_t *age_next; 70} autogroup_entry_t; 71 72/* Holds pointers to attribute definitions and groups. */ 73typedef struct autogroup_info_t { 74 autogroup_def_t *agi_def; /* Group attributes definitions. */ 75 autogroup_entry_t *agi_entry; /* Group entries. */ 76 AttributeDescription *agi_memberof_ad; /* memberOf attribute description */ 77 ldap_pvt_thread_mutex_t agi_mutex; 78} autogroup_info_t; 79 80/* Search callback for adding groups initially. */ 81typedef struct autogroup_sc_t { 82 autogroup_info_t *ags_info; /* Group definitions and entries. */ 83 autogroup_def_t *ags_def; /* Attributes definition of the group being added. */ 84} autogroup_sc_t; 85 86/* Used for adding members, found when searching, to a group. */ 87typedef struct autogroup_ga_t { 88 autogroup_entry_t *agg_group; /* The group to which the members will be added. */ 89 autogroup_filter_t *agg_filter; /* Current filter */ 90 Entry *agg_entry; /* Used in autogroup_member_search_cb to modify 91 this entry with the search results. */ 92 93 Modifications *agg_mod; /* Used in autogroup_member_search_modify_cb to hold the 94 search results which will be added to the group. */ 95 96 Modifications *agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't 97 have to search for the last mod added. */ 98} autogroup_ga_t; 99 100 101/* 102** dn, ndn - the DN of the member to add 103** age - the group to which the member DN will be added 104*/ 105static int 106autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age ) 107{ 108 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 109 Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) ); 110 SlapReply sreply = {REP_RESULT}; 111 BerValue *vals, *nvals; 112 slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; 113 Operation o = *op; 114 115 assert( dn != NULL ); 116 assert( ndn != NULL ); 117 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n", 118 dn->bv_val, age->age_dn.bv_val, 0); 119 120 vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) ); 121 nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) ); 122 ber_dupbv( vals, dn ); 123 BER_BVZERO( &vals[ 1 ] ); 124 ber_dupbv( nvals, ndn ); 125 BER_BVZERO( &nvals[ 1 ] ); 126 127 modlist->sml_op = LDAP_MOD_ADD; 128 modlist->sml_desc = age->age_def->agd_member_ad; 129 modlist->sml_type = age->age_def->agd_member_ad->ad_cname; 130 modlist->sml_values = vals; 131 modlist->sml_nvalues = nvals; 132 modlist->sml_numvals = 1; 133 modlist->sml_flags = SLAP_MOD_INTERNAL; 134 modlist->sml_next = NULL; 135 136 o.o_tag = LDAP_REQ_MODIFY; 137 o.o_callback = &cb; 138 o.orm_modlist = modlist; 139 o.o_req_dn = age->age_dn; 140 o.o_req_ndn = age->age_ndn; 141 o.o_permissive_modify = 1; 142 o.o_managedsait = SLAP_CONTROL_CRITICAL; 143 o.o_relax = SLAP_CONTROL_CRITICAL; 144 145 o.o_bd->bd_info = (BackendInfo *)on->on_info; 146 (void)op->o_bd->be_modify( &o, &sreply ); 147 o.o_bd->bd_info = (BackendInfo *)on; 148 149 slap_mods_free( modlist, 1 ); 150 151 return sreply.sr_err; 152} 153 154/* 155** e - the entry where to get the attribute values 156** age - the group to which the values will be added 157*/ 158static int 159autogroup_add_member_values_to_group( Operation *op, Entry *e, autogroup_entry_t *age, AttributeDescription *attrdesc ) 160{ 161 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 162 Modifications modlist; 163 SlapReply sreply = {REP_RESULT}; 164 Attribute *attr; 165 slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; 166 Operation o = *op; 167 168 assert( e != NULL ); 169 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_values_to_group adding <%s> to <%s>\n", 170 e->e_name.bv_val, age->age_dn.bv_val, 0); 171 172 attr = attrs_find( e->e_attrs, attrdesc ); 173 if (!attr) { 174 // Nothing to add 175 return LDAP_SUCCESS; 176 } 177 178 modlist.sml_op = LDAP_MOD_ADD; 179 modlist.sml_desc = age->age_def->agd_member_ad; 180 modlist.sml_type = age->age_def->agd_member_ad->ad_cname; 181 modlist.sml_values = attr->a_vals; 182 modlist.sml_nvalues = attr->a_nvals; 183 modlist.sml_numvals = attr->a_numvals; 184 modlist.sml_flags = SLAP_MOD_INTERNAL; 185 modlist.sml_next = NULL; 186 187 o.o_tag = LDAP_REQ_MODIFY; 188 o.o_callback = &cb; 189 o.orm_modlist = &modlist; 190 o.o_req_dn = age->age_dn; 191 o.o_req_ndn = age->age_ndn; 192 o.o_permissive_modify = 1; 193 o.o_managedsait = SLAP_CONTROL_CRITICAL; 194 o.o_relax = SLAP_CONTROL_CRITICAL; 195 196 o.o_bd->bd_info = (BackendInfo *)on->on_info; 197 (void)op->o_bd->be_modify( &o, &sreply ); 198 o.o_bd->bd_info = (BackendInfo *)on; 199 200 return sreply.sr_err; 201} 202 203/* 204** dn,ndn - the DN to be deleted 205** age - the group from which the DN will be deleted 206** If we pass a NULL dn and ndn, all members are deleted from the group. 207*/ 208static int 209autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age ) 210{ 211 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 212 Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) ); 213 SlapReply sreply = {REP_RESULT}; 214 BerValue *vals, *nvals; 215 slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; 216 Operation o = *op; 217 218 if ( dn == NULL || ndn == NULL ) { 219 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n", 220 age->age_dn.bv_val, 0 ,0); 221 222 modlist->sml_values = NULL; 223 modlist->sml_nvalues = NULL; 224 modlist->sml_numvals = 0; 225 } else { 226 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n", 227 dn->bv_val, age->age_dn.bv_val, 0); 228 229 vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) ); 230 nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) ); 231 ber_dupbv( vals, dn ); 232 BER_BVZERO( &vals[ 1 ] ); 233 ber_dupbv( nvals, ndn ); 234 BER_BVZERO( &nvals[ 1 ] ); 235 236 modlist->sml_values = vals; 237 modlist->sml_nvalues = nvals; 238 modlist->sml_numvals = 1; 239 } 240 241 242 modlist->sml_op = LDAP_MOD_DELETE; 243 modlist->sml_desc = age->age_def->agd_member_ad; 244 modlist->sml_type = age->age_def->agd_member_ad->ad_cname; 245 modlist->sml_flags = SLAP_MOD_INTERNAL; 246 modlist->sml_next = NULL; 247 248 o.o_callback = &cb; 249 o.o_tag = LDAP_REQ_MODIFY; 250 o.orm_modlist = modlist; 251 o.o_req_dn = age->age_dn; 252 o.o_req_ndn = age->age_ndn; 253 o.o_relax = SLAP_CONTROL_CRITICAL; 254 o.o_managedsait = SLAP_CONTROL_CRITICAL; 255 o.o_permissive_modify = 1; 256 257 o.o_bd->bd_info = (BackendInfo *)on->on_info; 258 (void)op->o_bd->be_modify( &o, &sreply ); 259 o.o_bd->bd_info = (BackendInfo *)on; 260 261 slap_mods_free( modlist, 1 ); 262 263 return sreply.sr_err; 264} 265 266/* 267** e - the entry where to get the attribute values 268** age - the group from which the values will be deleted 269*/ 270static int 271autogroup_delete_member_values_from_group( Operation *op, Entry *e, autogroup_entry_t *age, AttributeDescription *attrdesc ) 272{ 273 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 274 Modifications modlist; 275 SlapReply sreply = {REP_RESULT}; 276 Attribute *attr; 277 slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; 278 Operation o = *op; 279 280 assert( e != NULL ); 281 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_values_from_group removing <%s> from <%s>\n", 282 e->e_name.bv_val, age->age_dn.bv_val, 0); 283 284 attr = attrs_find( e->e_attrs, attrdesc ); 285 if (!attr) { 286 // Nothing to add 287 return LDAP_SUCCESS; 288 } 289 290 modlist.sml_op = LDAP_MOD_DELETE; 291 modlist.sml_desc = age->age_def->agd_member_ad; 292 modlist.sml_type = age->age_def->agd_member_ad->ad_cname; 293 modlist.sml_values = attr->a_vals; 294 modlist.sml_nvalues = attr->a_nvals; 295 modlist.sml_numvals = attr->a_numvals; 296 modlist.sml_flags = SLAP_MOD_INTERNAL; 297 modlist.sml_next = NULL; 298 299 o.o_tag = LDAP_REQ_MODIFY; 300 o.o_callback = &cb; 301 o.orm_modlist = &modlist; 302 o.o_req_dn = age->age_dn; 303 o.o_req_ndn = age->age_ndn; 304 o.o_permissive_modify = 1; 305 o.o_managedsait = SLAP_CONTROL_CRITICAL; 306 o.o_relax = SLAP_CONTROL_CRITICAL; 307 308 o.o_bd->bd_info = (BackendInfo *)on->on_info; 309 (void)op->o_bd->be_modify( &o, &sreply ); 310 o.o_bd->bd_info = (BackendInfo *)on; 311 312 return sreply.sr_err; 313} 314 315/* 316** Callback used to add entries to a group, 317** which are going to be written in the database 318** (used in bi_op_add) 319** The group is passed in autogroup_ga_t->agg_group 320*/ 321static int 322autogroup_member_search_cb( Operation *op, SlapReply *rs ) 323{ 324 assert( op->o_tag == LDAP_REQ_SEARCH ); 325 326 if ( rs->sr_type == REP_SEARCH ) { 327 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private; 328 autogroup_entry_t *age = agg->agg_group; 329 autogroup_filter_t *agf = agg->agg_filter; 330 Modification mod; 331 const char *text = NULL; 332 char textbuf[1024]; 333 struct berval *vals, *nvals; 334 int numvals; 335 336 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n", 337 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0); 338 339 if ( agf->agf_anlist ) { 340 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc ); 341 if (attr) { 342 vals = attr->a_vals; 343 nvals = attr->a_nvals; 344 numvals = attr->a_numvals; 345 } else { 346 // Nothing to add 347 return 0; 348 } 349 } else { 350 struct berval lvals[ 2 ], lnvals[ 2 ]; 351 lvals[ 0 ] = rs->sr_entry->e_name; 352 BER_BVZERO( &lvals[ 1 ] ); 353 lnvals[ 0 ] = rs->sr_entry->e_nname; 354 BER_BVZERO( &lnvals[ 1 ] ); 355 vals = lvals; 356 nvals = lnvals; 357 numvals = 1; 358 } 359 360 mod.sm_op = LDAP_MOD_ADD; 361 mod.sm_desc = age->age_def->agd_member_ad; 362 mod.sm_type = age->age_def->agd_member_ad->ad_cname; 363 mod.sm_values = vals; 364 mod.sm_nvalues = nvals; 365 mod.sm_numvals = numvals; 366 367 modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) ); 368 } 369 370 return 0; 371} 372 373/* 374** Callback used to add entries to a group, which is already in the database. 375** (used in on_response) 376** The group is passed in autogroup_ga_t->agg_group 377** NOTE: Very slow. 378*/ 379static int 380autogroup_member_search_modify_cb( Operation *op, SlapReply *rs ) 381{ 382 assert( op->o_tag == LDAP_REQ_SEARCH ); 383 384 if ( rs->sr_type == REP_SEARCH ) { 385 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private; 386 autogroup_entry_t *age = agg->agg_group; 387 autogroup_filter_t *agf = agg->agg_filter; 388 Modifications *modlist; 389 struct berval *vals, *nvals; 390 int numvals; 391 392 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n", 393 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0); 394 395 if ( agf->agf_anlist ) { 396 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc ); 397 if (attr) { 398 vals = attr->a_vals; 399 nvals = attr->a_nvals; 400 numvals = attr->a_numvals; 401 } else { 402 // Nothing to add 403 return 0; 404 } 405 } else { 406 struct berval lvals[ 2 ], lnvals[ 2 ]; 407 lvals[ 0 ] = rs->sr_entry->e_name; 408 BER_BVZERO( &lvals[ 1 ] ); 409 lnvals[ 0 ] = rs->sr_entry->e_nname; 410 BER_BVZERO( &lnvals[ 1 ] ); 411 vals = lvals; 412 nvals = lnvals; 413 numvals = 1; 414 } 415 416 if ( numvals ) { 417 modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) ); 418 419 modlist->sml_op = LDAP_MOD_ADD; 420 modlist->sml_desc = age->age_def->agd_member_ad; 421 modlist->sml_type = age->age_def->agd_member_ad->ad_cname; 422 423 ber_bvarray_dup_x( &modlist->sml_values, vals, NULL ); 424 ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL ); 425 modlist->sml_numvals = numvals; 426 427 modlist->sml_flags = SLAP_MOD_INTERNAL; 428 modlist->sml_next = NULL; 429 430 if ( agg->agg_mod == NULL ) { 431 agg->agg_mod = modlist; 432 agg->agg_mod_last = modlist; 433 } else { 434 agg->agg_mod_last->sml_next = modlist; 435 agg->agg_mod_last = modlist; 436 } 437 } 438 439 } 440 441 return 0; 442} 443 444 445/* 446** Adds all entries matching the passed filter to the specified group. 447** If modify == 1, then we modify the group's entry in the database using be_modify. 448** If modify == 0, then, we must supply a rw entry for the group, 449** because we only modify the entry, without calling be_modify. 450** e - the group entry, to which the members will be added 451** age - the group 452** agf - the filter 453*/ 454static int 455autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify) 456{ 457 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 458 Operation o = *op; 459 SlapReply rs = { REP_SEARCH }; 460 slap_callback cb = { 0 }; 461 slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL }; 462 autogroup_ga_t agg; 463 464 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n", 465 age->age_dn.bv_val, 0, 0); 466 467 o.ors_attrsonly = 0; 468 o.o_tag = LDAP_REQ_SEARCH; 469 470 o.o_req_dn = agf->agf_dn; 471 o.o_req_ndn = agf->agf_ndn; 472 473 o.ors_filterstr = agf->agf_filterstr; 474 o.ors_filter = agf->agf_filter; 475 476 o.ors_scope = agf->agf_scope; 477 o.ors_deref = LDAP_DEREF_NEVER; 478 o.ors_limit = NULL; 479 o.ors_tlimit = SLAP_NO_LIMIT; 480 o.ors_slimit = SLAP_NO_LIMIT; 481 o.ors_attrs = agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs; 482 483 agg.agg_group = age; 484 agg.agg_filter = agf; 485 agg.agg_mod = NULL; 486 agg.agg_mod_last = NULL; 487 agg.agg_entry = e; 488 cb.sc_private = &agg; 489 490 if ( modify == 1 ) { 491 cb.sc_response = autogroup_member_search_modify_cb; 492 } else { 493 cb.sc_response = autogroup_member_search_cb; 494 } 495 496 cb.sc_cleanup = NULL; 497 cb.sc_next = NULL; 498 499 o.o_callback = &cb; 500 501 o.o_bd->bd_info = (BackendInfo *)on->on_info; 502 op->o_bd->be_search( &o, &rs ); 503 o.o_bd->bd_info = (BackendInfo *)on; 504 505 if ( modify == 1 && agg.agg_mod ) { 506 rs_reinit( &rs, REP_RESULT ); 507 508 o = *op; 509 o.o_callback = &null_cb; 510 o.o_tag = LDAP_REQ_MODIFY; 511 o.orm_modlist = agg.agg_mod; 512 o.o_req_dn = age->age_dn; 513 o.o_req_ndn = age->age_ndn; 514 o.o_relax = SLAP_CONTROL_CRITICAL; 515 o.o_managedsait = SLAP_CONTROL_NONCRITICAL; 516 o.o_permissive_modify = 1; 517 518 o.o_bd->bd_info = (BackendInfo *)on->on_info; 519 (void)op->o_bd->be_modify( &o, &rs ); 520 o.o_bd->bd_info = (BackendInfo *)on; 521 522 slap_mods_free(agg.agg_mod, 1); 523 } 524 525 return 0; 526} 527 528/* 529** Adds a group to the internal list from the passed entry. 530** scan specifies whether to add all maching members to the group. 531** modify specifies whether to modify the given group entry (when modify == 0), 532** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL). 533** agi - pointer to the groups and the attribute definitions 534** agd - the attribute definition of the added group 535** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1 536** ndn - the DN of the group, can be NULL if we give a non-NULL e 537*/ 538static int 539autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify) 540{ 541 autogroup_entry_t **agep = &agi->agi_entry; 542 autogroup_filter_t *agf, *agf_prev = NULL; 543 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 544 LDAPURLDesc *lud = NULL; 545 Attribute *a; 546 BerValue *bv, dn; 547 int rc = 0, match = 1, null_entry = 0; 548 549 if ( e == NULL ) { 550 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) != 551 LDAP_SUCCESS || e == NULL ) { 552 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0); 553 return 1; 554 } 555 556 null_entry = 1; 557 } 558 559 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n", 560 e->e_name.bv_val, 0, 0); 561 562 if ( agi->agi_entry != NULL ) { 563 for ( ; *agep ; agep = &(*agep)->age_next ) { 564 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn ); 565 if ( match == 0 ) { 566 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0); 567 return 1; 568 } 569 /* goto last */; 570 } 571 } 572 573 574 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) ); 575 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex ); 576 (*agep)->age_def = agd; 577 (*agep)->age_filter = NULL; 578 (*agep)->age_mustrefresh = 0; 579 (*agep)->age_modrdn_olddnmodified = 0; 580 581 ber_dupbv( &(*agep)->age_dn, &e->e_name ); 582 ber_dupbv( &(*agep)->age_ndn, &e->e_nname ); 583 584 a = attrs_find( e->e_attrs, agd->agd_member_url_ad ); 585 586 if ( null_entry == 1 ) { 587 a = attrs_dup( a ); 588 overlay_entry_release_ov( op, e, 0, on ); 589 } 590 591 if( a == NULL ) { 592 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0); 593 } else { 594 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) { 595 596 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) ); 597 598 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) { 599 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0); 600 /* FIXME: error? */ 601 ch_free( agf ); 602 continue; 603 } 604 605 agf->agf_scope = lud->lud_scope; 606 607 if ( lud->lud_dn == NULL ) { 608 BER_BVSTR( &dn, "" ); 609 } else { 610 ber_str2bv( lud->lud_dn, 0, 0, &dn ); 611 } 612 613 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL ); 614 if ( rc != LDAP_SUCCESS ) { 615 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0); 616 /* FIXME: error? */ 617 goto cleanup; 618 } 619 620 if ( lud->lud_filter != NULL ) { 621 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr); 622 agf->agf_filter = str2filter( lud->lud_filter ); 623 } 624 625 if ( lud->lud_attrs != NULL ) { 626 int i; 627 628 for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) { 629 /* Just counting */; 630 } 631 632 if ( i > 1 ) { 633 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: too many attributes specified in url <%s>\n", 634 bv->bv_val, 0, 0); 635 /* FIXME: error? */ 636 ldap_free_urldesc( lud ); 637 ch_free( agf ); 638 continue; 639 } 640 641 agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," ); 642 643 if ( agf->agf_anlist == NULL ) { 644 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n", 645 lud->lud_attrs[0], 0, 0 ); 646 /* FIXME: error? */ 647 ldap_free_urldesc( lud ); 648 ch_free( agf ); 649 continue; 650 } 651 } 652 653 agf->agf_next = NULL; 654 655 656 if( (*agep)->age_filter == NULL ) { 657 (*agep)->age_filter = agf; 658 } 659 660 if( agf_prev != NULL ) { 661 agf_prev->agf_next = agf; 662 } 663 664 agf_prev = agf; 665 666 if ( scan == 1 ){ 667 autogroup_add_members_from_filter( op, e, (*agep), agf, modify ); 668 } 669 670 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n", 671 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0); 672 673 ldap_free_urldesc( lud ); 674 675 continue; 676 677 678cleanup:; 679 680 ldap_free_urldesc( lud ); 681 ch_free( agf ); 682 } 683 } 684 685 if ( null_entry == 1 ) { 686 attrs_free( a ); 687 } 688 return rc; 689} 690 691/* 692** Used when opening the database to add all existing 693** groups from the database to our internal list. 694*/ 695static int 696autogroup_group_add_cb( Operation *op, SlapReply *rs ) 697{ 698 assert( op->o_tag == LDAP_REQ_SEARCH ); 699 700 if ( rs->sr_type == REP_SEARCH ) { 701 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private; 702 703 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n", 704 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0); 705 706 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0); 707 } 708 709 return 0; 710} 711 712 713/* 714** When adding a group, we first strip any existing members, 715** and add all which match the filters ourselfs. 716*/ 717static int 718autogroup_add_entry( Operation *op, SlapReply *rs) 719{ 720 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 721 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; 722 autogroup_def_t *agd = agi->agi_def; 723 autogroup_entry_t *age; 724 autogroup_filter_t *agf; 725 int rc = 0; 726 727 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n", 728 op->ora_e->e_name.bv_val, 0, 0); 729 730 ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); 731 732 /* Check if it's a group. */ 733 for ( ; agd ; agd = agd->agd_next ) { 734 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) { 735 Modification mod; 736 const char *text = NULL; 737 char textbuf[1024]; 738 739 mod.sm_op = LDAP_MOD_DELETE; 740 mod.sm_desc = agd->agd_member_ad; 741 mod.sm_type = agd->agd_member_ad->ad_cname; 742 mod.sm_values = NULL; 743 mod.sm_nvalues = NULL; 744 745 /* We don't want any member attributes added by the user. */ 746 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) ); 747 748 autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0); 749 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 750 return SLAP_CB_CONTINUE; 751 } 752 } 753 754 755 for ( age = agi->agi_entry; age ; age = age->age_next ) { 756 ldap_pvt_thread_mutex_lock( &age->age_mutex ); 757 758 /* Check if any of the filters are the suffix to the entry DN. 759 If yes, we can test that filter against the entry. */ 760 761 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) { 762 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { 763 rc = test_filter( op, op->ora_e, agf->agf_filter ); 764 if ( rc == LDAP_COMPARE_TRUE ) { 765 if ( agf->agf_anlist ) { 766 autogroup_add_member_values_to_group( op, op->ora_e, age, agf->agf_anlist[0].an_desc ); 767 } else { 768 autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age ); 769 } 770 break; 771 } 772 } 773 } 774 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 775 } 776 777 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 778 779 return SLAP_CB_CONTINUE; 780} 781 782/* 783** agi - internal group and attribute definitions list 784** e - the group to remove from the internal list 785*/ 786static int 787autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e ) 788{ 789 autogroup_entry_t *age = agi->agi_entry, 790 *age_prev = NULL, 791 *age_next; 792 int rc = 1; 793 794 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n", 795 age->age_dn.bv_val, 0, 0); 796 797 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) { 798 age_next = age->age_next; 799 800 if ( age == e ) { 801 autogroup_filter_t *agf = age->age_filter, 802 *agf_next; 803 804 if ( age_prev != NULL ) { 805 age_prev->age_next = age_next; 806 } else { 807 agi->agi_entry = NULL; 808 } 809 810 ch_free( age->age_dn.bv_val ); 811 ch_free( age->age_ndn.bv_val ); 812 813 for( agf_next = agf ; agf_next ; agf = agf_next ){ 814 agf_next = agf->agf_next; 815 816 filter_free( agf->agf_filter ); 817 ch_free( agf->agf_filterstr.bv_val ); 818 ch_free( agf->agf_dn.bv_val ); 819 ch_free( agf->agf_ndn.bv_val ); 820 anlist_free( agf->agf_anlist, 1, NULL ); 821 ch_free( agf ); 822 } 823 824 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 825 ldap_pvt_thread_mutex_destroy( &age->age_mutex ); 826 ch_free( age ); 827 828 rc = 0; 829 return rc; 830 831 } 832 } 833 834 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0); 835 836 return rc; 837 838} 839 840static int 841autogroup_delete_entry( Operation *op, SlapReply *rs) 842{ 843 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 844 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; 845 autogroup_entry_t *age, *age_prev, *age_next; 846 autogroup_filter_t *agf; 847 Entry *e; 848 int matched_group = 0, rc = 0; 849 850 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0); 851 852 ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); 853 854 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != 855 LDAP_SUCCESS || e == NULL ) { 856 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0); 857 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 858 return SLAP_CB_CONTINUE; 859 } 860 861 /* Check if the entry to be deleted is one of our groups. */ 862 for ( age_next = agi->agi_entry ; age_next ; age_prev = age ) { 863 age = age_next; 864 ldap_pvt_thread_mutex_lock( &age->age_mutex ); 865 age_next = age->age_next; 866 867 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) { 868 int match = 1; 869 870 matched_group = 1; 871 872 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn ); 873 874 if ( match == 0 ) { 875 autogroup_delete_group( agi, age ); 876 break; 877 } 878 } 879 880 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 881 } 882 883 if ( matched_group == 1 ) { 884 overlay_entry_release_ov( op, e, 0, on ); 885 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 886 return SLAP_CB_CONTINUE; 887 } 888 889 /* Check if the entry matches any of the groups. 890 If yes, we can delete the entry from that group. */ 891 892 for ( age = agi->agi_entry ; age ; age = age->age_next ) { 893 ldap_pvt_thread_mutex_lock( &age->age_mutex ); 894 895 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) { 896 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { 897 rc = test_filter( op, e, agf->agf_filter ); 898 if ( rc == LDAP_COMPARE_TRUE ) { 899 /* If the attribute is retrieved from the entry, we don't know what to delete 900 ** So the group must be entirely refreshed 901 ** But the refresh can't be done now because the entry is not deleted 902 ** So the group is marked as mustrefresh 903 */ 904 if ( agf->agf_anlist ) { 905 age->age_mustrefresh = 1; 906 } else { 907 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age ); 908 } 909 break; 910 } 911 } 912 } 913 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 914 } 915 916 overlay_entry_release_ov( op, e, 0, on ); 917 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 918 919 return SLAP_CB_CONTINUE; 920} 921 922static int 923autogroup_response( Operation *op, SlapReply *rs ) 924{ 925 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 926 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; 927 autogroup_def_t *agd = agi->agi_def; 928 autogroup_entry_t *age; 929 autogroup_filter_t *agf; 930 BerValue new_dn, new_ndn, pdn; 931 Entry *e, *group; 932 Attribute *a, *ea; 933 int is_olddn, is_newdn, is_value_refresh, dn_equal; 934 935 /* Handle all cases where a refresh of the group is needed */ 936 if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) { 937 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) { 938 939 ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); 940 941 for ( age = agi->agi_entry ; age ; age = age->age_next ) { 942 /* Request detected that the group must be refreshed */ 943 944 ldap_pvt_thread_mutex_lock( &age->age_mutex ); 945 946 if ( age->age_mustrefresh ) { 947 autogroup_delete_member_from_group( op, NULL, NULL, age) ; 948 949 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { 950 autogroup_add_members_from_filter( op, NULL, age, agf, 1 ); 951 } 952 } 953 954 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 955 } 956 957 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 958 } 959 } else if ( op->o_tag == LDAP_REQ_MODRDN ) { 960 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) { 961 962 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0); 963 964 ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); 965 966 if ( op->oq_modrdn.rs_newSup ) { 967 pdn = *op->oq_modrdn.rs_newSup; 968 } else { 969 dnParent( &op->o_req_dn, &pdn ); 970 } 971 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx ); 972 973 if ( op->oq_modrdn.rs_nnewSup ) { 974 pdn = *op->oq_modrdn.rs_nnewSup; 975 } else { 976 dnParent( &op->o_req_ndn, &pdn ); 977 } 978 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx ); 979 980 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0); 981 982 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn ); 983 984 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) != 985 LDAP_SUCCESS || e == NULL ) { 986 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0); 987 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 988 return SLAP_CB_CONTINUE; 989 } 990 991 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass ); 992 993 994 if ( a == NULL ) { 995 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0); 996 overlay_entry_release_ov( op, e, 0, on ); 997 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 998 return SLAP_CB_CONTINUE; 999 } 1000 1001 1002 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */ 1003 for ( ; agd; agd = agd->agd_next ) { 1004 1005 if ( value_find_ex( slap_schema.si_ad_objectClass, 1006 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 1007 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 1008 a->a_nvals, &agd->agd_oc->soc_cname, 1009 op->o_tmpmemctx ) == 0 ) 1010 { 1011 for ( age = agi->agi_entry ; age ; age = age->age_next ) { 1012 int match = 1; 1013 1014 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn ); 1015 if ( match == 0 ) { 1016 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0); 1017 ber_dupbv( &age->age_dn, &new_dn ); 1018 ber_dupbv( &age->age_ndn, &new_ndn ); 1019 1020 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx ); 1021 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx ); 1022 overlay_entry_release_ov( op, e, 0, on ); 1023 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1024 return SLAP_CB_CONTINUE; 1025 } 1026 } 1027 1028 } 1029 } 1030 1031 /* For each group: 1032 1. check if the orginal entry's DN is in the group. 1033 2. chceck if the any of the group filter's base DN is a suffix of the new DN 1034 1035 If 1 and 2 are both false, we do nothing. 1036 If 1 and 2 is true, we remove the old DN from the group, and add the new DN. 1037 If 1 is false, and 2 is true, we check the entry against the group's filters, 1038 and add it's DN to the group. 1039 If 1 is true, and 2 is false, we delete the entry's DN from the group. 1040 */ 1041 for ( age = agi->agi_entry ; age ; age = age->age_next ) { 1042 is_olddn = 0; 1043 is_newdn = 0; 1044 is_value_refresh = 0; 1045 1046 1047 ldap_pvt_thread_mutex_lock( &age->age_mutex ); 1048 1049 if ( age->age_filter && age->age_filter->agf_anlist ) { 1050 ea = attrs_find( e->e_attrs, age->age_filter->agf_anlist[0].an_desc ); 1051 } 1052 else { 1053 ea = NULL; 1054 } 1055 1056 if ( age->age_modrdn_olddnmodified ) { 1057 /* Resquest already marked this group to be updated */ 1058 is_olddn = 1; 1059 is_value_refresh = 1; 1060 age->age_modrdn_olddnmodified = 0; 1061 } else { 1062 1063 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) != 1064 LDAP_SUCCESS || group == NULL ) { 1065 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0); 1066 1067 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx ); 1068 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx ); 1069 1070 overlay_entry_release_ov( op, e, 0, on ); 1071 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 1072 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1073 return SLAP_CB_CONTINUE; 1074 } 1075 1076 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad ); 1077 1078 if ( a != NULL ) { 1079 if ( value_find_ex( age->age_def->agd_member_ad, 1080 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 1081 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 1082 a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 ) 1083 { 1084 is_olddn = 1; 1085 } 1086 1087 } 1088 1089 overlay_entry_release_ov( op, group, 0, on ); 1090 1091 } 1092 1093 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { 1094 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) { 1095 /* TODO: should retest filter as it could imply conditions on the dn */ 1096 is_newdn = 1; 1097 break; 1098 } 1099 } 1100 1101 1102 if ( is_value_refresh ) { 1103 if ( is_olddn != is_newdn ) { 1104 /* group refresh */ 1105 autogroup_delete_member_from_group( op, NULL, NULL, age) ; 1106 1107 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { 1108 autogroup_add_members_from_filter( op, NULL, age, agf, 1 ); 1109 } 1110 } 1111 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 1112 continue; 1113 } 1114 if ( is_olddn == 1 && is_newdn == 0 ) { 1115 if ( ea ) 1116 autogroup_delete_member_values_from_group( op, e, age, age->age_filter->agf_anlist[0].an_desc ); 1117 else 1118 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age ); 1119 } else 1120 if ( is_olddn == 0 && is_newdn == 1 ) { 1121 for ( agf = age->age_filter; agf; agf = agf->agf_next ) { 1122 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) { 1123 if ( ea ) 1124 autogroup_add_member_values_to_group( op, e, age, age->age_filter->agf_anlist[0].an_desc ); 1125 else 1126 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age ); 1127 break; 1128 } 1129 } 1130 } else 1131 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) { 1132 if ( ea ) { 1133 /* group refresh */ 1134 autogroup_delete_member_from_group( op, NULL, NULL, age) ; 1135 1136 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { 1137 autogroup_add_members_from_filter( op, NULL, age, agf, 1 ); 1138 } 1139 } 1140 else { 1141 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age ); 1142 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age ); 1143 } 1144 } 1145 1146 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 1147 } 1148 1149 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx ); 1150 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx ); 1151 1152 overlay_entry_release_ov( op, e, 0, on ); 1153 1154 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1155 } 1156 } 1157 1158 if ( op->o_tag == LDAP_REQ_MODIFY ) { 1159 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) { 1160 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0); 1161 1162 ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); 1163 1164 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != 1165 LDAP_SUCCESS || e == NULL ) { 1166 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0); 1167 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1168 return SLAP_CB_CONTINUE; 1169 } 1170 1171 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass ); 1172 1173 1174 if ( a == NULL ) { 1175 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0); 1176 overlay_entry_release_ov( op, e, 0, on ); 1177 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1178 return SLAP_CB_CONTINUE; 1179 } 1180 1181 /* If we modify a group's memberURL, we have to delete all of it's members, 1182 and add them anew, because we cannot tell from which memberURL a member was added. */ 1183 for ( ; agd; agd = agd->agd_next ) { 1184 1185 if ( value_find_ex( slap_schema.si_ad_objectClass, 1186 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 1187 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 1188 a->a_nvals, &agd->agd_oc->soc_cname, 1189 op->o_tmpmemctx ) == 0 ) 1190 { 1191 Modifications *m; 1192 int match = 1; 1193 1194 m = op->orm_modlist; 1195 1196 for ( age = agi->agi_entry ; age ; age = age->age_next ) { 1197 ldap_pvt_thread_mutex_lock( &age->age_mutex ); 1198 1199 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn ); 1200 1201 if ( match == 0 ) { 1202 for ( ; m ; m = m->sml_next ) { 1203 if ( m->sml_desc == age->age_def->agd_member_url_ad ) { 1204 autogroup_def_t *group_agd = age->age_def; 1205 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n", 1206 op->o_req_dn.bv_val, 0, 0); 1207 1208 overlay_entry_release_ov( op, e, 0, on ); 1209 1210 autogroup_delete_member_from_group( op, NULL, NULL, age ); 1211 autogroup_delete_group( agi, age ); 1212 1213 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1); 1214 1215 overlay_entry_release_ov( op, e, 0, on ); 1216 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1217 return SLAP_CB_CONTINUE; 1218 } 1219 } 1220 1221 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 1222 break; 1223 } 1224 1225 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 1226 } 1227 1228 overlay_entry_release_ov( op, e, 0, on ); 1229 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1230 return SLAP_CB_CONTINUE; 1231 } 1232 } 1233 1234 /* When modifing any of the attributes of an entry, we must 1235 check if the entry is in any of our groups, and if 1236 the modified entry maches any of the filters of that group. 1237 1238 If the entry exists in a group, but the modified attributes do 1239 not match any of the group's filters, we delete the entry from that group. 1240 If the entry doesn't exist in a group, but matches a filter, 1241 we add it to that group. 1242 */ 1243 for ( age = agi->agi_entry ; age ; age = age->age_next ) { 1244 is_olddn = 0; 1245 is_newdn = 0; 1246 1247 1248 ldap_pvt_thread_mutex_lock( &age->age_mutex ); 1249 1250 if ( age->age_filter && age->age_filter->agf_anlist ) { 1251 ea = attrs_find( e->e_attrs, age->age_filter->agf_anlist[0].an_desc ); 1252 } 1253 else { 1254 ea = NULL; 1255 } 1256 1257 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) != 1258 LDAP_SUCCESS || group == NULL ) { 1259 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", 1260 age->age_dn.bv_val, 0, 0); 1261 1262 overlay_entry_release_ov( op, e, 0, on ); 1263 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 1264 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1265 return SLAP_CB_CONTINUE; 1266 } 1267 1268 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad ); 1269 1270 if ( a != NULL ) { 1271 if ( value_find_ex( age->age_def->agd_member_ad, 1272 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 1273 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 1274 a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 ) 1275 { 1276 is_olddn = 1; 1277 } 1278 1279 } 1280 1281 overlay_entry_release_ov( op, group, 0, on ); 1282 1283 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { 1284 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { 1285 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) { 1286 is_newdn = 1; 1287 break; 1288 } 1289 } 1290 } 1291 1292 if ( is_olddn == 1 && is_newdn == 0 ) { 1293 if(ea) 1294 autogroup_delete_member_values_from_group( op, e, age, age->age_filter->agf_anlist[0].an_desc ); 1295 else 1296 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age ); 1297 } else 1298 if ( is_olddn == 0 && is_newdn == 1 ) { 1299 if(ea) 1300 autogroup_add_member_values_to_group( op, e, age, age->age_filter->agf_anlist[0].an_desc ); 1301 else 1302 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age ); 1303 } 1304 1305 ldap_pvt_thread_mutex_unlock( &age->age_mutex ); 1306 } 1307 1308 overlay_entry_release_ov( op, e, 0, on ); 1309 1310 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1311 } 1312 } 1313 1314 return SLAP_CB_CONTINUE; 1315} 1316 1317/* 1318** Detect if filter contains a memberOf check for dn 1319*/ 1320static int 1321autogroup_memberOf_filter( Filter *f, BerValue *dn, AttributeDescription *memberof_ad ) 1322{ 1323 int result = 0; 1324 if ( f == NULL ) return 0; 1325 1326 switch ( f->f_choice & SLAPD_FILTER_MASK ) { 1327 case LDAP_FILTER_AND: 1328 case LDAP_FILTER_OR: 1329 case LDAP_FILTER_NOT: 1330 for ( f = f->f_un.f_un_complex; f && !result; f = f->f_next ) { 1331 result = result || autogroup_memberOf_filter( f, dn, memberof_ad ); 1332 } 1333 break; 1334 case LDAP_FILTER_EQUALITY: 1335 result = ( f->f_ava->aa_desc == memberof_ad && 1336 ber_bvcmp( &f->f_ava->aa_value, dn ) == 0 ); 1337 break; 1338 default: 1339 break; 1340 } 1341 1342 return result; 1343} 1344 1345/* 1346** When modifing a group, we must deny any modifications to the member attribute, 1347** because the group would be inconsistent. 1348*/ 1349static int 1350autogroup_modify_entry( Operation *op, SlapReply *rs) 1351{ 1352 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1353 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; 1354 autogroup_def_t *agd = agi->agi_def; 1355 autogroup_entry_t *age; 1356 Entry *e; 1357 Attribute *a; 1358 1359 if ( get_manageDSAit( op ) ) { 1360 return SLAP_CB_CONTINUE; 1361 } 1362 1363 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0); 1364 ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); 1365 1366 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != 1367 LDAP_SUCCESS || e == NULL ) { 1368 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0); 1369 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1370 return SLAP_CB_CONTINUE; 1371 } 1372 1373 /* Must refresh groups if a matching member value is modified OR filter contains memberOf=DN */ 1374 for ( age = agi->agi_entry; age ; age = age->age_next ) { 1375 autogroup_filter_t *agf; 1376 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { 1377 if ( agf->agf_anlist ) { 1378 Modifications *m; 1379 for ( m = op->orm_modlist ; m ; m = m->sml_next ) { 1380 if ( m->sml_desc == agf->agf_anlist[0].an_desc ) { 1381 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { 1382 int rc = test_filter( op, e, agf->agf_filter ); 1383 if ( rc == LDAP_COMPARE_TRUE ) { 1384 age->age_mustrefresh = 1; 1385 } 1386 } 1387 } 1388 } 1389 } 1390 1391 if ( autogroup_memberOf_filter( agf->agf_filter, &op->o_req_ndn, agi->agi_memberof_ad ) ) { 1392 age->age_mustrefresh = 1; 1393 } 1394 } 1395 } 1396 1397 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass ); 1398 1399 if ( a == NULL ) { 1400 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0); 1401 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1402 return SLAP_CB_CONTINUE; 1403 } 1404 1405 1406 for ( ; agd; agd = agd->agd_next ) { 1407 1408 if ( value_find_ex( slap_schema.si_ad_objectClass, 1409 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 1410 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 1411 a->a_nvals, &agd->agd_oc->soc_cname, 1412 op->o_tmpmemctx ) == 0 ) 1413 { 1414 Modifications *m; 1415 int match = 1; 1416 1417 m = op->orm_modlist; 1418 1419 for ( age = agi->agi_entry ; age ; age = age->age_next ) { 1420 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn ); 1421 1422 if ( match == 0 ) { 1423 for ( ; m ; m = m->sml_next ) { 1424 if ( m->sml_desc == age->age_def->agd_member_ad ) { 1425 overlay_entry_release_ov( op, e, 0, on ); 1426 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1427 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0); 1428 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute"); 1429 return LDAP_CONSTRAINT_VIOLATION; 1430 } 1431 } 1432 break; 1433 } 1434 } 1435 1436 overlay_entry_release_ov( op, e, 0, on ); 1437 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1438 return SLAP_CB_CONTINUE; 1439 } 1440 } 1441 1442 overlay_entry_release_ov( op, e, 0, on ); 1443 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1444 return SLAP_CB_CONTINUE; 1445} 1446 1447/* 1448** Detect if the olddn is part of a group and so if the group should be refreshed 1449*/ 1450static int 1451autogroup_modrdn_entry( Operation *op, SlapReply *rs) 1452{ 1453 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1454 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; 1455 autogroup_entry_t *age; 1456 Entry *e; 1457 1458 if ( get_manageDSAit( op ) ) { 1459 return SLAP_CB_CONTINUE; 1460 } 1461 1462 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0); 1463 ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); 1464 1465 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != 1466 LDAP_SUCCESS || e == NULL ) { 1467 Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0); 1468 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1469 return SLAP_CB_CONTINUE; 1470 } 1471 1472 /* Must check if a dn is modified */ 1473 for ( age = agi->agi_entry; age ; age = age->age_next ) { 1474 autogroup_filter_t *agf; 1475 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { 1476 if ( agf->agf_anlist ) { 1477 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { 1478 int rc = test_filter( op, e, agf->agf_filter ); 1479 if ( rc == LDAP_COMPARE_TRUE ) { 1480 age->age_modrdn_olddnmodified = 1; 1481 } 1482 } 1483 } 1484 } 1485 } 1486 1487 overlay_entry_release_ov( op, e, 0, on ); 1488 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); 1489 return SLAP_CB_CONTINUE; 1490} 1491 1492/* 1493** Builds a filter for searching for the 1494** group entries, according to the objectClass. 1495*/ 1496static int 1497autogroup_build_def_filter( autogroup_def_t *agd, Operation *op ) 1498{ 1499 char *ptr; 1500 1501 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0); 1502 1503 op->ors_filterstr.bv_len = STRLENOF( "(=)" ) 1504 + slap_schema.si_ad_objectClass->ad_cname.bv_len 1505 + agd->agd_oc->soc_cname.bv_len; 1506 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); 1507 *ptr++ = '('; 1508 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val ); 1509 *ptr++ = '='; 1510 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val ); 1511 *ptr++ = ')'; 1512 *ptr = '\0'; 1513 1514 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val ); 1515 1516 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val ); 1517 1518 return 0; 1519} 1520 1521enum { 1522 AG_ATTRSET = 1, 1523 AG_MEMBER_OF_AD, 1524 AG_LAST 1525}; 1526 1527static ConfigDriver ag_cfgen; 1528 1529static ConfigTable agcfg[] = { 1530 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad", 1531 3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen, 1532 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' " 1533 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' " 1534 "EQUALITY caseIgnoreMatch " 1535 "SYNTAX OMsDirectoryString " 1536 "X-ORDERED 'VALUES' )", 1537 NULL, NULL }, 1538 1539 { "autogroup-memberof-ad", "memberOf attribute", 1540 2, 2, 0, ARG_MAGIC|AG_MEMBER_OF_AD, ag_cfgen, 1541 "( OLcfgCtAt:2.2 NAME 'olcAGmemberOfAd' " 1542 "DESC 'memberOf attribute' " 1543 "SYNTAX OMsDirectoryString SINGLE-VALUE )", 1544 NULL, NULL }, 1545 1546 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 1547}; 1548 1549static ConfigOCs agocs[] = { 1550 { "( OLcfgCtOc:2.1 " 1551 "NAME 'olcAutomaticGroups' " 1552 "DESC 'Automatic groups configuration' " 1553 "SUP olcOverlayConfig " 1554 "MAY ( " 1555 "olcAGattrSet " 1556 "$ olcAGmemberOfAd " 1557 ")" 1558 ")", 1559 Cft_Overlay, agcfg, NULL, NULL }, 1560 { NULL, 0, NULL } 1561}; 1562 1563 1564static int 1565ag_cfgen( ConfigArgs *c ) 1566{ 1567 slap_overinst *on = (slap_overinst *)c->bi; 1568 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; 1569 autogroup_def_t *agd; 1570 autogroup_entry_t *age; 1571 1572 int rc = 0, i; 1573 1574 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0); 1575 1576 if( agi == NULL ) { 1577 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) ); 1578 ldap_pvt_thread_mutex_init( &agi->agi_mutex ); 1579 agi->agi_def = NULL; 1580 agi->agi_entry = NULL; 1581 on->on_bi.bi_private = (void *)agi; 1582 } 1583 1584 agd = agi->agi_def; 1585 age = agi->agi_entry; 1586 1587 if ( c->op == SLAP_CONFIG_EMIT ) { 1588 1589 switch( c->type ){ 1590 case AG_ATTRSET: 1591 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) { 1592 struct berval bv; 1593 char *ptr = c->cr_msg; 1594 1595 assert(agd->agd_oc != NULL); 1596 assert(agd->agd_member_url_ad != NULL); 1597 assert(agd->agd_member_ad != NULL); 1598 1599 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ), 1600 SLAP_X_ORDERED_FMT "%s %s %s", i, 1601 agd->agd_oc->soc_cname.bv_val, 1602 agd->agd_member_url_ad->ad_cname.bv_val, 1603 agd->agd_member_ad->ad_cname.bv_val ); 1604 1605 bv.bv_val = c->cr_msg; 1606 bv.bv_len = ptr - bv.bv_val; 1607 value_add_one ( &c->rvalue_vals, &bv ); 1608 1609 } 1610 break; 1611 1612 case AG_MEMBER_OF_AD: 1613 if ( agi->agi_memberof_ad != NULL ){ 1614 value_add_one( &c->rvalue_vals, &agi->agi_memberof_ad->ad_cname ); 1615 } 1616 break; 1617 1618 default: 1619 assert( 0 ); 1620 return 1; 1621 } 1622 1623 return rc; 1624 1625 }else if ( c->op == LDAP_MOD_DELETE ) { 1626 if ( c->valx < 0) { 1627 autogroup_def_t *agd_next; 1628 autogroup_entry_t *age_next; 1629 autogroup_filter_t *agf = age->age_filter, 1630 *agf_next; 1631 1632 for ( agd_next = agd; agd_next; agd = agd_next ) { 1633 agd_next = agd->agd_next; 1634 1635 ch_free( agd ); 1636 } 1637 1638 for ( age_next = age ; age_next ; age = age_next ) { 1639 age_next = age->age_next; 1640 1641 ch_free( age->age_dn.bv_val ); 1642 ch_free( age->age_ndn.bv_val ); 1643 1644 for( agf_next = agf ; agf_next ; agf = agf_next ){ 1645 agf_next = agf->agf_next; 1646 1647 filter_free( agf->agf_filter ); 1648 ch_free( agf->agf_filterstr.bv_val ); 1649 ch_free( agf->agf_dn.bv_val ); 1650 ch_free( agf->agf_ndn.bv_val ); 1651 anlist_free( agf->agf_anlist, 1, NULL ); 1652 ch_free( agf ); 1653 } 1654 1655 ldap_pvt_thread_mutex_init( &age->age_mutex ); 1656 ch_free( age ); 1657 } 1658 1659 ch_free( agi ); 1660 on->on_bi.bi_private = NULL; 1661 1662 } else { 1663 autogroup_def_t **agdp; 1664 autogroup_entry_t *age_next, *age_prev; 1665 autogroup_filter_t *agf, 1666 *agf_next; 1667 1668 for ( i = 0, agdp = &agi->agi_def; 1669 i < c->valx; i++ ) 1670 { 1671 if ( *agdp == NULL) { 1672 return 1; 1673 } 1674 agdp = &(*agdp)->agd_next; 1675 } 1676 1677 agd = *agdp; 1678 *agdp = agd->agd_next; 1679 1680 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) { 1681 age_next = age->age_next; 1682 1683 if( age->age_def == agd ) { 1684 agf = age->age_filter; 1685 1686 ch_free( age->age_dn.bv_val ); 1687 ch_free( age->age_ndn.bv_val ); 1688 1689 for ( agf_next = agf; agf_next ; agf = agf_next ) { 1690 agf_next = agf->agf_next; 1691 filter_free( agf->agf_filter ); 1692 ch_free( agf->agf_filterstr.bv_val ); 1693 ch_free( agf->agf_dn.bv_val ); 1694 ch_free( agf->agf_ndn.bv_val ); 1695 anlist_free( agf->agf_anlist, 1, NULL ); 1696 ch_free( agf ); 1697 } 1698 1699 ldap_pvt_thread_mutex_destroy( &age->age_mutex ); 1700 ch_free( age ); 1701 1702 age = age_prev; 1703 1704 if( age_prev != NULL ) { 1705 age_prev->age_next = age_next; 1706 } 1707 } 1708 } 1709 1710 ch_free( agd ); 1711 agd = agi->agi_def; 1712 1713 } 1714 1715 return rc; 1716 } 1717 1718 switch(c->type){ 1719 case AG_ATTRSET: { 1720 autogroup_def_t **agdp, 1721 *agd_next = NULL; 1722 ObjectClass *oc = NULL; 1723 AttributeDescription *member_url_ad = NULL, 1724 *member_ad = NULL; 1725 const char *text; 1726 1727 1728 oc = oc_find( c->argv[ 1 ] ); 1729 if( oc == NULL ){ 1730 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1731 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " 1732 "unable to find ObjectClass \"%s\"", 1733 c->argv[ 1 ] ); 1734 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1735 c->log, c->cr_msg, 0 ); 1736 return 1; 1737 } 1738 1739 1740 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text ); 1741 if( rc != LDAP_SUCCESS ) { 1742 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1743 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " 1744 "unable to find AttributeDescription \"%s\"", 1745 c->argv[ 2 ] ); 1746 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1747 c->log, c->cr_msg, 0 ); 1748 return 1; 1749 } 1750 1751 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) { 1752 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1753 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " 1754 "AttributeDescription \"%s\" ", 1755 "must be of a subtype \"labeledURI\"", 1756 c->argv[ 2 ] ); 1757 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1758 c->log, c->cr_msg, 0 ); 1759 return 1; 1760 } 1761 1762 rc = slap_str2ad( c->argv[3], &member_ad, &text ); 1763 if( rc != LDAP_SUCCESS ) { 1764 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1765 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " 1766 "unable to find AttributeDescription \"%s\"", 1767 c->argv[ 3 ] ); 1768 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1769 c->log, c->cr_msg, 0 ); 1770 return 1; 1771 } 1772 1773 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) { 1774 /* The same URL attribute / member attribute pair 1775 * cannot be repeated */ 1776 1777 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) { 1778 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1779 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " 1780 "URL attributeDescription \"%s\" already mapped", 1781 member_ad->ad_cname.bv_val ); 1782 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1783 c->log, c->cr_msg, 0 ); 1784/* return 1; //warning*/ 1785 } 1786 } 1787 1788 if ( c->valx > 0 ) { 1789 int i; 1790 1791 for ( i = 0, agdp = &agi->agi_def ; 1792 i < c->valx; i++ ) 1793 { 1794 if ( *agdp == NULL ) { 1795 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1796 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " 1797 "invalid index {%d}", 1798 c->valx ); 1799 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1800 c->log, c->cr_msg, 0 ); 1801 1802 return 1; 1803 } 1804 agdp = &(*agdp)->agd_next; 1805 } 1806 agd_next = *agdp; 1807 1808 } else { 1809 for ( agdp = &agi->agi_def; *agdp; 1810 agdp = &(*agdp)->agd_next ) 1811 /* goto last */; 1812 } 1813 1814 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t)); 1815 1816 (*agdp)->agd_oc = oc; 1817 (*agdp)->agd_member_url_ad = member_url_ad; 1818 (*agdp)->agd_member_ad = member_ad; 1819 (*agdp)->agd_next = agd_next; 1820 1821 } break; 1822 1823 case AG_MEMBER_OF_AD: { 1824 AttributeDescription *memberof_ad = NULL; 1825 const char *text; 1826 1827 rc = slap_str2ad( c->argv[ 1 ], &memberof_ad, &text ); 1828 if( rc != LDAP_SUCCESS ) { 1829 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1830 "\"autogroup-memberof-ad <memberof-ad>\": " 1831 "unable to find AttributeDescription \"%s\"", 1832 c->argv[ 1 ] ); 1833 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1834 c->log, c->cr_msg, 0 ); 1835 return 1; 1836 } 1837 1838 if ( !is_at_syntax( memberof_ad->ad_type, SLAPD_DN_SYNTAX ) /* e.g. "member" */ 1839 && !is_at_syntax( memberof_ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */ 1840 { 1841 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1842 "memberof attribute=\"%s\" must either " 1843 "have DN (%s) or nameUID (%s) syntax", 1844 c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX ); 1845 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1846 c->log, c->cr_msg, 0 ); 1847 return 1; 1848 } 1849 1850 agi->agi_memberof_ad = memberof_ad; 1851 1852 } break; 1853 1854 default: 1855 rc = 1; 1856 break; 1857 } 1858 1859 return rc; 1860} 1861 1862extern int slapMode; 1863 1864/* 1865** Do a search for all the groups in the 1866** database, and add them to out internal list. 1867*/ 1868static int 1869autogroup_db_open( 1870 BackendDB *be, 1871 ConfigReply *cr ) 1872{ 1873 slap_overinst *on = (slap_overinst *) be->bd_info; 1874 autogroup_info_t *agi = on->on_bi.bi_private; 1875 autogroup_def_t *agd; 1876 autogroup_sc_t ags; 1877 Operation *op; 1878 slap_callback cb = { 0 }; 1879 1880 void *thrctx = ldap_pvt_thread_pool_context(); 1881 Connection conn = { 0 }; 1882 OperationBuffer opbuf; 1883 1884 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0); 1885 1886 if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) { 1887 return 0; 1888 } 1889 1890 connection_fake_init( &conn, &opbuf, thrctx ); 1891 op = &opbuf.ob_op; 1892 1893 op->ors_attrsonly = 0; 1894 op->o_tag = LDAP_REQ_SEARCH; 1895 op->o_dn = be->be_rootdn; 1896 op->o_ndn = be->be_rootndn; 1897 1898 op->o_req_dn = be->be_suffix[0]; 1899 op->o_req_ndn = be->be_nsuffix[0]; 1900 1901 op->ors_scope = LDAP_SCOPE_SUBTREE; 1902 op->ors_deref = LDAP_DEREF_NEVER; 1903 op->ors_limit = NULL; 1904 op->ors_tlimit = SLAP_NO_LIMIT; 1905 op->ors_slimit = SLAP_NO_LIMIT; 1906 op->ors_attrs = slap_anlist_no_attrs; 1907 1908 op->o_bd = be; 1909 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1910 1911 ags.ags_info = agi; 1912 cb.sc_private = &ags; 1913 cb.sc_response = autogroup_group_add_cb; 1914 cb.sc_cleanup = NULL; 1915 cb.sc_next = NULL; 1916 1917 op->o_callback = &cb; 1918 1919 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) { 1920 SlapReply rs = { REP_RESULT }; 1921 1922 autogroup_build_def_filter(agd, op); 1923 1924 ags.ags_def = agd; 1925 1926 op->o_bd->be_search( op, &rs ); 1927 1928 filter_free_x( op, op->ors_filter, 1 ); 1929 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 1930 } 1931 1932 if( ! agi->agi_memberof_ad ){ 1933 int rc; 1934 const char *text = NULL; 1935 1936 rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &agi->agi_memberof_ad, &text ); 1937 if ( rc != LDAP_SUCCESS ) { 1938 Debug( LDAP_DEBUG_ANY, "autogroup_db_open: " 1939 "unable to find attribute=\"%s\": %s (%d)\n", 1940 SLAPD_MEMBEROF_ATTR, text, rc ); 1941 return rc; 1942 } 1943 } 1944 1945 return 0; 1946} 1947 1948static int 1949autogroup_db_close( 1950 BackendDB *be, 1951 ConfigReply *cr ) 1952{ 1953 slap_overinst *on = (slap_overinst *) be->bd_info; 1954 1955 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0); 1956 1957 if ( on->on_bi.bi_private ) { 1958 autogroup_info_t *agi = on->on_bi.bi_private; 1959 autogroup_entry_t *age = agi->agi_entry, 1960 *age_next; 1961 autogroup_filter_t *agf, *agf_next; 1962 1963 for ( age_next = age; age_next; age = age_next ) { 1964 age_next = age->age_next; 1965 1966 ch_free( age->age_dn.bv_val ); 1967 ch_free( age->age_ndn.bv_val ); 1968 1969 agf = age->age_filter; 1970 1971 for ( agf_next = agf; agf_next; agf = agf_next ) { 1972 agf_next = agf->agf_next; 1973 1974 filter_free( agf->agf_filter ); 1975 ch_free( agf->agf_filterstr.bv_val ); 1976 ch_free( agf->agf_dn.bv_val ); 1977 ch_free( agf->agf_ndn.bv_val ); 1978 anlist_free( agf->agf_anlist, 1, NULL ); 1979 ch_free( agf ); 1980 } 1981 1982 ldap_pvt_thread_mutex_destroy( &age->age_mutex ); 1983 ch_free( age ); 1984 } 1985 } 1986 1987 return 0; 1988} 1989 1990static int 1991autogroup_db_destroy( 1992 BackendDB *be, 1993 ConfigReply *cr ) 1994{ 1995 slap_overinst *on = (slap_overinst *) be->bd_info; 1996 1997 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0); 1998 1999 if ( on->on_bi.bi_private ) { 2000 autogroup_info_t *agi = on->on_bi.bi_private; 2001 autogroup_def_t *agd = agi->agi_def, 2002 *agd_next; 2003 2004 for ( agd_next = agd; agd_next; agd = agd_next ) { 2005 agd_next = agd->agd_next; 2006 2007 ch_free( agd ); 2008 } 2009 2010 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex ); 2011 ch_free( agi ); 2012 } 2013 2014 return 0; 2015} 2016 2017static slap_overinst autogroup = { { NULL } }; 2018 2019static 2020int 2021autogroup_initialize(void) 2022{ 2023 int rc = 0; 2024 autogroup.on_bi.bi_type = "autogroup"; 2025 2026 autogroup.on_bi.bi_db_open = autogroup_db_open; 2027 autogroup.on_bi.bi_db_close = autogroup_db_close; 2028 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy; 2029 2030 autogroup.on_bi.bi_op_add = autogroup_add_entry; 2031 autogroup.on_bi.bi_op_delete = autogroup_delete_entry; 2032 autogroup.on_bi.bi_op_modify = autogroup_modify_entry; 2033 autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry; 2034 2035 autogroup.on_response = autogroup_response; 2036 2037 autogroup.on_bi.bi_cf_ocs = agocs; 2038 2039 rc = config_register_schema( agcfg, agocs ); 2040 if ( rc ) { 2041 return rc; 2042 } 2043 2044 return overlay_register( &autogroup ); 2045} 2046 2047int 2048init_module( int argc, char *argv[] ) 2049{ 2050 return autogroup_initialize(); 2051} 2052