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