177943Sdfr/* $NetBSD: memberof.c,v 1.2 2021/08/14 16:15:02 christos Exp $ */ 277943Sdfr 377943Sdfr/* memberof.c - back-reference for group membership */ 477943Sdfr/* $OpenLDAP$ */ 577943Sdfr/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 677943Sdfr * 7163898Smarcel * Copyright 2005-2007 Pierangelo Masarati <ando@sys-net.it> 8163898Smarcel * All rights reserved. 9163898Smarcel * 10163898Smarcel * Redistribution and use in source and binary forms, with or without 11163898Smarcel * modification, are permitted only as authorized by the OpenLDAP 12163898Smarcel * Public License. 13163898Smarcel * 14163898Smarcel * A copy of this license is available in the file LICENSE in the 1577943Sdfr * top-level directory of the distribution or, alternatively, at 1677943Sdfr * <http://www.OpenLDAP.org/license.html>. 1777943Sdfr */ 1877943Sdfr/* ACKNOWLEDGMENTS: 1977943Sdfr * This work was initially developed by Pierangelo Masarati for inclusion 2077943Sdfr * in OpenLDAP Software, sponsored by SysNet s.r.l. 2177943Sdfr */ 2277943Sdfr 2377943Sdfr#include <sys/cdefs.h> 2477943Sdfr__RCSID("$NetBSD: memberof.c,v 1.2 2021/08/14 16:15:02 christos Exp $"); 2577943Sdfr 2677943Sdfr#include "portable.h" 2777943Sdfr 2877943Sdfr#ifdef SLAPD_OVER_MEMBEROF 2977943Sdfr 3077943Sdfr#include <stdio.h> 3177943Sdfr 3277943Sdfr#include "ac/string.h" 3377943Sdfr#include "ac/socket.h" 3477943Sdfr 3577943Sdfr#include "slap.h" 3677943Sdfr#include "slap-config.h" 3777943Sdfr#include "lutil.h" 3877943Sdfr 3977943Sdfr/* 4077943Sdfr * Glossary: 4177943Sdfr * 4277943Sdfr * GROUP a group object (an entry with GROUP_OC 4377943Sdfr * objectClass) 4477943Sdfr * MEMBER a member object (an entry whose DN is 4577943Sdfr * listed as MEMBER_AT value of a GROUP) 4677943Sdfr * GROUP_OC the objectClass of the group object 4777943Sdfr * (default: groupOfNames) 4877943Sdfr * MEMBER_AT the membership attribute, DN-valued; 4977943Sdfr * note: nameAndOptionalUID is tolerated 5077943Sdfr * as soon as the optionalUID is absent 5177943Sdfr * (default: member) 5277943Sdfr * MEMBER_OF reverse membership attribute 5377943Sdfr * (default: memberOf) 54163898Smarcel * 55163898Smarcel * - add: 56163898Smarcel * - if the entry that is being added is a GROUP, 57163898Smarcel * the MEMBER_AT defined as values of the add operation 58163898Smarcel * get the MEMBER_OF value directly from the request. 59163898Smarcel * 60163898Smarcel * if configured to do so, the MEMBER objects do not exist, 61163898Smarcel * and no relax control is issued, either: 62163898Smarcel * - fail 63163898Smarcel * - drop non-existing members 64163898Smarcel * (by default: don't muck with values) 65163898Smarcel * 66163898Smarcel * - if (configured to do so,) the referenced GROUP exists, 67163898Smarcel * the relax control is set and the user has 68163898Smarcel * "manage" privileges, allow to add MEMBER_OF values to 69163898Smarcel * generic entries. 70163898Smarcel * 7177943Sdfr * - modify: 72163898Smarcel * - if the entry being modified is a GROUP_OC and the 7377943Sdfr * MEMBER_AT attribute is modified, the MEMBER_OF value 74163898Smarcel * of the (existing) MEMBER_AT entries that are affected 75163898Smarcel * is modified according to the request: 76163898Smarcel * - if a MEMBER is removed from the group, 77163898Smarcel * delete the corresponding MEMBER_OF 78163898Smarcel * - if a MEMBER is added to a group, 79163898Smarcel * add the corresponding MEMBER_OF 8077943Sdfr * 8177943Sdfr * We need to determine, from the database, if it is 82163898Smarcel * a GROUP_OC, and we need to check, from the 83163898Smarcel * modification list, if the MEMBER_AT attribute is being 84163898Smarcel * affected, and what MEMBER_AT values are affected. 85163898Smarcel * 8677943Sdfr * if configured to do so, the entries corresponding to 8777943Sdfr * the MEMBER_AT values do not exist, and no relax control 8877943Sdfr * is issued, either: 8977943Sdfr * - fail 9077943Sdfr * - drop non-existing members 9177943Sdfr * (by default: don't muck with values) 9277943Sdfr * 9377943Sdfr * - if configured to do so, the referenced GROUP exists, 9477943Sdfr * (the relax control is set) and the user has 9577943Sdfr * "manage" privileges, allow to add MEMBER_OF values to 9677943Sdfr * generic entries; the change is NOT automatically reflected 9777943Sdfr * in the MEMBER attribute of the GROUP referenced 9877943Sdfr * by the value of MEMBER_OF; a separate modification, 9977943Sdfr * with or without relax control, needs to be performed. 100163898Smarcel * 101163898Smarcel * - modrdn: 102163898Smarcel * - if the entry being renamed is a GROUP, the MEMBER_OF 10377943Sdfr * value of the (existing) MEMBER objects is modified 10477943Sdfr * accordingly based on the newDN of the GROUP. 10577943Sdfr * 10677943Sdfr * We need to determine, from the database, if it is 10777943Sdfr * a GROUP; the list of MEMBER objects is obtained from 10877943Sdfr * the database. 10977943Sdfr * 11077943Sdfr * Non-existing MEMBER objects are ignored, since the 11177943Sdfr * MEMBER_AT is not being addressed by the operation. 11277943Sdfr * 11377943Sdfr * - if the entry being renamed has the MEMBER_OF attribute, 11477943Sdfr * the corresponding MEMBER value must be modified in the 11577943Sdfr * respective group entries. 11677943Sdfr * 11777943Sdfr * 11877943Sdfr * - delete: 119 * - if the entry being deleted is a GROUP, the (existing) 120 * MEMBER objects are modified accordingly; a copy of the 121 * values of the MEMBER_AT is saved and, if the delete 122 * succeeds, the MEMBER_OF value of the (existing) MEMBER 123 * objects is deleted. 124 * 125 * We need to determine, from the database, if it is 126 * a GROUP. 127 * 128 * Non-existing MEMBER objects are ignored, since the entry 129 * is being deleted. 130 * 131 * - if the entry being deleted has the MEMBER_OF attribute, 132 * the corresponding value of the MEMBER_AT must be deleted 133 * from the respective GROUP entries. 134 */ 135 136#define SLAPD_MEMBEROF_ATTR "memberOf" 137 138static AttributeDescription *ad_member; 139static AttributeDescription *ad_memberOf; 140 141static ObjectClass *oc_group; 142 143static slap_overinst memberof; 144 145typedef struct memberof_t { 146 struct berval mo_dn; 147 struct berval mo_ndn; 148 149 ObjectClass *mo_oc_group; 150 AttributeDescription *mo_ad_member; 151 AttributeDescription *mo_ad_memberof; 152 153 struct berval mo_groupFilterstr; 154 AttributeAssertion mo_groupAVA; 155 Filter mo_groupFilter; 156 157 struct berval mo_memberFilterstr; 158 Filter mo_memberFilter; 159 160 unsigned mo_flags; 161#define MEMBEROF_NONE 0x00U 162#define MEMBEROF_FDANGLING_DROP 0x01U 163#define MEMBEROF_FDANGLING_ERROR 0x02U 164#define MEMBEROF_FDANGLING_MASK (MEMBEROF_FDANGLING_DROP|MEMBEROF_FDANGLING_ERROR) 165#define MEMBEROF_FREFINT 0x04U 166#define MEMBEROF_FREVERSE 0x08U 167 168 ber_int_t mo_dangling_err; 169 170#define MEMBEROF_CHK(mo,f) \ 171 (((mo)->mo_flags & (f)) == (f)) 172#define MEMBEROF_DANGLING_CHECK(mo) \ 173 ((mo)->mo_flags & MEMBEROF_FDANGLING_MASK) 174#define MEMBEROF_DANGLING_DROP(mo) \ 175 MEMBEROF_CHK((mo),MEMBEROF_FDANGLING_DROP) 176#define MEMBEROF_DANGLING_ERROR(mo) \ 177 MEMBEROF_CHK((mo),MEMBEROF_FDANGLING_ERROR) 178#define MEMBEROF_REFINT(mo) \ 179 MEMBEROF_CHK((mo),MEMBEROF_FREFINT) 180#define MEMBEROF_REVERSE(mo) \ 181 MEMBEROF_CHK((mo),MEMBEROF_FREVERSE) 182} memberof_t; 183 184typedef enum memberof_is_t { 185 MEMBEROF_IS_NONE = 0x00, 186 MEMBEROF_IS_GROUP = 0x01, 187 MEMBEROF_IS_MEMBER = 0x02, 188 MEMBEROF_IS_BOTH = (MEMBEROF_IS_GROUP|MEMBEROF_IS_MEMBER) 189} memberof_is_t; 190 191typedef struct memberof_cookie_t { 192 AttributeDescription *ad; 193 BerVarray vals; 194 int foundit; 195} memberof_cookie_t; 196 197typedef struct memberof_cbinfo_t { 198 slap_overinst *on; 199 BerVarray member; 200 BerVarray memberof; 201 memberof_is_t what; 202} memberof_cbinfo_t; 203 204static void 205memberof_set_backend( Operation *op_target, Operation *op, slap_overinst *on ) 206{ 207 BackendInfo *bi = op->o_bd->bd_info; 208 209 if ( bi->bi_type == memberof.on_bi.bi_type ) 210 op_target->o_bd->bd_info = (BackendInfo *)on->on_info; 211} 212 213static int 214memberof_isGroupOrMember_cb( Operation *op, SlapReply *rs ) 215{ 216 if ( rs->sr_type == REP_SEARCH ) { 217 memberof_cookie_t *mc; 218 219 mc = (memberof_cookie_t *)op->o_callback->sc_private; 220 mc->foundit = 1; 221 } 222 223 return 0; 224} 225 226/* 227 * callback for internal search that saves the member attribute values 228 * of groups being deleted. 229 */ 230static int 231memberof_saveMember_cb( Operation *op, SlapReply *rs ) 232{ 233 if ( rs->sr_type == REP_SEARCH ) { 234 memberof_cookie_t *mc; 235 Attribute *a; 236 237 mc = (memberof_cookie_t *)op->o_callback->sc_private; 238 mc->foundit = 1; 239 240 assert( rs->sr_entry != NULL ); 241 assert( rs->sr_entry->e_attrs != NULL ); 242 243 a = attr_find( rs->sr_entry->e_attrs, mc->ad ); 244 if ( a != NULL ) { 245 ber_bvarray_dup_x( &mc->vals, a->a_nvals, op->o_tmpmemctx ); 246 247 assert( attr_find( a->a_next, mc->ad ) == NULL ); 248 } 249 } 250 251 return 0; 252} 253 254/* 255 * the delete hook performs an internal search that saves the member 256 * attribute values of groups being deleted. 257 */ 258static int 259memberof_isGroupOrMember( Operation *op, memberof_cbinfo_t *mci ) 260{ 261 slap_overinst *on = mci->on; 262 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 263 264 Operation op2 = *op; 265 slap_callback cb = { 0 }; 266 BackendInfo *bi = op->o_bd->bd_info; 267 AttributeName an[ 2 ]; 268 269 memberof_is_t iswhat = MEMBEROF_IS_NONE; 270 memberof_cookie_t mc; 271 272 assert( mci->what != MEMBEROF_IS_NONE ); 273 274 cb.sc_private = &mc; 275 if ( op->o_tag == LDAP_REQ_DELETE ) { 276 cb.sc_response = memberof_saveMember_cb; 277 278 } else { 279 cb.sc_response = memberof_isGroupOrMember_cb; 280 } 281 282 op2.o_tag = LDAP_REQ_SEARCH; 283 op2.o_callback = &cb; 284 op2.o_dn = op->o_bd->be_rootdn; 285 op2.o_ndn = op->o_bd->be_rootndn; 286 287 op2.ors_scope = LDAP_SCOPE_BASE; 288 op2.ors_deref = LDAP_DEREF_NEVER; 289 BER_BVZERO( &an[ 1 ].an_name ); 290 op2.ors_attrs = an; 291 op2.ors_attrsonly = 0; 292 op2.ors_limit = NULL; 293 op2.ors_slimit = 1; 294 op2.ors_tlimit = SLAP_NO_LIMIT; 295 296 if ( mci->what & MEMBEROF_IS_GROUP ) { 297 SlapReply rs2 = { REP_RESULT }; 298 299 mc.ad = mo->mo_ad_member; 300 mc.foundit = 0; 301 mc.vals = NULL; 302 an[ 0 ].an_desc = mo->mo_ad_member; 303 an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname; 304 op2.ors_filterstr = mo->mo_groupFilterstr; 305 op2.ors_filter = &mo->mo_groupFilter; 306 op2.o_do_not_cache = 1; /* internal search, don't log */ 307 308 memberof_set_backend( &op2, op, on ); 309 (void)op->o_bd->be_search( &op2, &rs2 ); 310 op2.o_bd->bd_info = bi; 311 312 if ( mc.foundit ) { 313 iswhat |= MEMBEROF_IS_GROUP; 314 if ( mc.vals ) mci->member = mc.vals; 315 316 } 317 } 318 319 if ( mci->what & MEMBEROF_IS_MEMBER ) { 320 SlapReply rs2 = { REP_RESULT }; 321 322 mc.ad = mo->mo_ad_memberof; 323 mc.foundit = 0; 324 mc.vals = NULL; 325 an[ 0 ].an_desc = mo->mo_ad_memberof; 326 an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname; 327 op2.ors_filterstr = mo->mo_memberFilterstr; 328 op2.ors_filter = &mo->mo_memberFilter; 329 op2.o_do_not_cache = 1; /* internal search, don't log */ 330 331 memberof_set_backend( &op2, op, on ); 332 (void)op->o_bd->be_search( &op2, &rs2 ); 333 op2.o_bd->bd_info = bi; 334 335 if ( mc.foundit ) { 336 iswhat |= MEMBEROF_IS_MEMBER; 337 if ( mc.vals ) mci->memberof = mc.vals; 338 339 } 340 } 341 342 mci->what = iswhat; 343 344 return LDAP_SUCCESS; 345} 346 347/* 348 * response callback that adds memberof values when a group is modified. 349 */ 350static void 351memberof_value_modify( 352 Operation *op, 353 struct berval *ndn, 354 AttributeDescription *ad, 355 struct berval *old_dn, 356 struct berval *old_ndn, 357 struct berval *new_dn, 358 struct berval *new_ndn ) 359{ 360 memberof_cbinfo_t *mci = op->o_callback->sc_private; 361 slap_overinst *on = mci->on; 362 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 363 364 Operation op2 = *op; 365 unsigned long opid = op->o_opid; 366 SlapReply rs2 = { REP_RESULT }; 367 slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; 368 Modifications mod[ 2 ] = { { { 0 } } }, *ml; 369 struct berval values[ 4 ], nvalues[ 4 ]; 370 int mcnt = 0; 371 372 if ( old_ndn != NULL && new_ndn != NULL && 373 ber_bvcmp( old_ndn, new_ndn ) == 0 ) { 374 /* DNs compare equal, it's a noop */ 375 return; 376 } 377 378 op2.o_tag = LDAP_REQ_MODIFY; 379 380 op2.o_req_dn = *ndn; 381 op2.o_req_ndn = *ndn; 382 383 op2.o_callback = &cb; 384 op2.o_dn = op->o_bd->be_rootdn; 385 op2.o_ndn = op->o_bd->be_rootndn; 386 op2.orm_modlist = NULL; 387 388 /* Internal ops, never replicate these */ 389 op2.o_opid = 0; /* shared with op, saved above */ 390 op2.orm_no_opattrs = 1; 391 op2.o_dont_replicate = 1; 392 393 if ( !BER_BVISNULL( &mo->mo_ndn ) ) { 394 ml = &mod[ mcnt ]; 395 ml->sml_numvals = 1; 396 ml->sml_values = &values[ 0 ]; 397 ml->sml_values[ 0 ] = mo->mo_dn; 398 BER_BVZERO( &ml->sml_values[ 1 ] ); 399 ml->sml_nvalues = &nvalues[ 0 ]; 400 ml->sml_nvalues[ 0 ] = mo->mo_ndn; 401 BER_BVZERO( &ml->sml_nvalues[ 1 ] ); 402 ml->sml_desc = slap_schema.si_ad_modifiersName; 403 ml->sml_type = ml->sml_desc->ad_cname; 404 ml->sml_op = LDAP_MOD_REPLACE; 405 ml->sml_flags = SLAP_MOD_INTERNAL; 406 ml->sml_next = op2.orm_modlist; 407 op2.orm_modlist = ml; 408 409 mcnt++; 410 } 411 412 ml = &mod[ mcnt ]; 413 ml->sml_numvals = 1; 414 ml->sml_values = &values[ 2 ]; 415 BER_BVZERO( &ml->sml_values[ 1 ] ); 416 ml->sml_nvalues = &nvalues[ 2 ]; 417 BER_BVZERO( &ml->sml_nvalues[ 1 ] ); 418 ml->sml_desc = ad; 419 ml->sml_type = ml->sml_desc->ad_cname; 420 ml->sml_flags = SLAP_MOD_INTERNAL; 421 ml->sml_next = op2.orm_modlist; 422 op2.orm_modlist = ml; 423 424 if ( new_ndn != NULL ) { 425 BackendInfo *bi = op2.o_bd->bd_info; 426 OpExtra oex; 427 428 assert( !BER_BVISNULL( new_dn ) ); 429 assert( !BER_BVISNULL( new_ndn ) ); 430 431 ml = &mod[ mcnt ]; 432 ml->sml_op = LDAP_MOD_ADD; 433 434 ml->sml_values[ 0 ] = *new_dn; 435 ml->sml_nvalues[ 0 ] = *new_ndn; 436 437 oex.oe_key = (void *)&memberof; 438 LDAP_SLIST_INSERT_HEAD(&op2.o_extra, &oex, oe_next); 439 memberof_set_backend( &op2, op, on ); 440 (void)op->o_bd->be_modify( &op2, &rs2 ); 441 op2.o_bd->bd_info = bi; 442 LDAP_SLIST_REMOVE(&op2.o_extra, &oex, OpExtra, oe_next); 443 if ( rs2.sr_err != LDAP_SUCCESS ) { 444 Debug(LDAP_DEBUG_ANY, 445 "%s: memberof_value_modify DN=\"%s\" add %s=\"%s\" failed err=%d\n", 446 op->o_log_prefix, op2.o_req_dn.bv_val, 447 ad->ad_cname.bv_val, new_dn->bv_val, rs2.sr_err ); 448 } 449 450 assert( op2.orm_modlist == &mod[ mcnt ] ); 451 assert( mcnt == 0 || op2.orm_modlist->sml_next == &mod[ 0 ] ); 452 ml = op2.orm_modlist->sml_next; 453 if ( mcnt == 1 ) { 454 assert( ml == &mod[ 0 ] ); 455 ml = ml->sml_next; 456 } 457 if ( ml != NULL ) { 458 slap_mods_free( ml, 1 ); 459 } 460 461 mod[ 0 ].sml_next = NULL; 462 } 463 464 if ( old_ndn != NULL ) { 465 BackendInfo *bi = op2.o_bd->bd_info; 466 OpExtra oex; 467 468 assert( !BER_BVISNULL( old_dn ) ); 469 assert( !BER_BVISNULL( old_ndn ) ); 470 471 ml = &mod[ mcnt ]; 472 ml->sml_op = LDAP_MOD_DELETE; 473 474 ml->sml_values[ 0 ] = *old_dn; 475 ml->sml_nvalues[ 0 ] = *old_ndn; 476 477 oex.oe_key = (void *)&memberof; 478 LDAP_SLIST_INSERT_HEAD(&op2.o_extra, &oex, oe_next); 479 memberof_set_backend( &op2, op, on ); 480 (void)op->o_bd->be_modify( &op2, &rs2 ); 481 op2.o_bd->bd_info = bi; 482 LDAP_SLIST_REMOVE(&op2.o_extra, &oex, OpExtra, oe_next); 483 if ( rs2.sr_err != LDAP_SUCCESS ) { 484 Debug(LDAP_DEBUG_ANY, 485 "%s: memberof_value_modify DN=\"%s\" delete %s=\"%s\" failed err=%d\n", 486 op->o_log_prefix, op2.o_req_dn.bv_val, 487 ad->ad_cname.bv_val, old_dn->bv_val, rs2.sr_err ); 488 } 489 490 assert( op2.orm_modlist == &mod[ mcnt ] ); 491 ml = op2.orm_modlist->sml_next; 492 if ( mcnt == 1 ) { 493 assert( ml == &mod[ 0 ] ); 494 ml = ml->sml_next; 495 } 496 if ( ml != NULL ) { 497 slap_mods_free( ml, 1 ); 498 } 499 } 500 /* restore original opid */ 501 op->o_opid = opid; 502 503 /* FIXME: if old_group_ndn doesn't exist, both delete __and__ 504 * add will fail; better split in two operations, although 505 * not optimal in terms of performance. At least it would 506 * move towards self-repairing capabilities. */ 507} 508 509static int 510memberof_cleanup( Operation *op, SlapReply *rs ) 511{ 512 slap_callback *sc = op->o_callback; 513 memberof_cbinfo_t *mci = sc->sc_private; 514 515 op->o_callback = sc->sc_next; 516 if ( mci->memberof ) 517 ber_bvarray_free_x( mci->memberof, op->o_tmpmemctx ); 518 if ( mci->member ) 519 ber_bvarray_free_x( mci->member, op->o_tmpmemctx ); 520 op->o_tmpfree( sc, op->o_tmpmemctx ); 521 return 0; 522} 523 524static int memberof_res_add( Operation *op, SlapReply *rs ); 525static int memberof_res_delete( Operation *op, SlapReply *rs ); 526static int memberof_res_modify( Operation *op, SlapReply *rs ); 527static int memberof_res_modrdn( Operation *op, SlapReply *rs ); 528 529static int 530memberof_op_add( Operation *op, SlapReply *rs ) 531{ 532 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 533 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 534 535 Attribute **ap, **map = NULL; 536 int rc = SLAP_CB_CONTINUE; 537 int i; 538 struct berval save_dn, save_ndn; 539 slap_callback *sc; 540 memberof_cbinfo_t *mci; 541 OpExtra *oex; 542 543 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { 544 if ( oex->oe_key == (void *)&memberof ) 545 return SLAP_CB_CONTINUE; 546 } 547 548 if ( op->ora_e->e_attrs == NULL ) { 549 /* FIXME: global overlay; need to deal with */ 550 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): " 551 "consistency checks not implemented when overlay " 552 "is instantiated as global.\n", 553 op->o_log_prefix, op->o_req_dn.bv_val ); 554 return SLAP_CB_CONTINUE; 555 } 556 557 if ( MEMBEROF_REVERSE( mo ) ) { 558 for ( ap = &op->ora_e->e_attrs; *ap; ap = &(*ap)->a_next ) { 559 Attribute *a = *ap; 560 561 if ( a->a_desc == mo->mo_ad_memberof ) { 562 map = ap; 563 break; 564 } 565 } 566 } 567 568 save_dn = op->o_dn; 569 save_ndn = op->o_ndn; 570 571 if ( MEMBEROF_DANGLING_CHECK( mo ) 572 && !get_relax( op ) 573 && is_entry_objectclass_or_sub( op->ora_e, mo->mo_oc_group ) ) 574 { 575 op->o_dn = op->o_bd->be_rootdn; 576 op->o_ndn = op->o_bd->be_rootndn; 577 op->o_bd->bd_info = (BackendInfo *)on->on_info; 578 579 for ( ap = &op->ora_e->e_attrs; *ap; ) { 580 Attribute *a = *ap; 581 582 if ( !is_ad_subtype( a->a_desc, mo->mo_ad_member ) ) { 583 ap = &a->a_next; 584 continue; 585 } 586 587 assert( a->a_nvals != NULL ); 588 589 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { 590 Entry *e = NULL; 591 592 /* ITS#6670 Ignore member pointing to this entry */ 593 if ( dn_match( &a->a_nvals[i], &save_ndn )) 594 continue; 595 596 rc = be_entry_get_rw( op, &a->a_nvals[ i ], 597 NULL, NULL, 0, &e ); 598 if ( rc == LDAP_SUCCESS ) { 599 be_entry_release_r( op, e ); 600 continue; 601 } 602 603 if ( MEMBEROF_DANGLING_ERROR( mo ) ) { 604 rc = rs->sr_err = mo->mo_dangling_err; 605 rs->sr_text = "adding non-existing object " 606 "as group member"; 607 send_ldap_result( op, rs ); 608 goto done; 609 } 610 611 if ( MEMBEROF_DANGLING_DROP( mo ) ) { 612 int j; 613 614 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): " 615 "member=\"%s\" does not exist (stripping...)\n", 616 op->o_log_prefix, op->ora_e->e_name.bv_val, 617 a->a_vals[ i ].bv_val ); 618 619 for ( j = i + 1; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ); 620 ber_memfree( a->a_vals[ i ].bv_val ); 621 BER_BVZERO( &a->a_vals[ i ] ); 622 if ( a->a_nvals != a->a_vals ) { 623 ber_memfree( a->a_nvals[ i ].bv_val ); 624 BER_BVZERO( &a->a_nvals[ i ] ); 625 } 626 a->a_numvals--; 627 if ( j - i == 1 ) { 628 break; 629 } 630 631 AC_MEMCPY( &a->a_vals[ i ], &a->a_vals[ i + 1 ], 632 sizeof( struct berval ) * ( j - i ) ); 633 if ( a->a_nvals != a->a_vals ) { 634 AC_MEMCPY( &a->a_nvals[ i ], &a->a_nvals[ i + 1 ], 635 sizeof( struct berval ) * ( j - i ) ); 636 } 637 i--; 638 } 639 } 640 641 /* If all values have been removed, 642 * remove the attribute itself. */ 643 if ( BER_BVISNULL( &a->a_nvals[ 0 ] ) ) { 644 *ap = a->a_next; 645 attr_free( a ); 646 647 } else { 648 ap = &a->a_next; 649 } 650 } 651 op->o_dn = save_dn; 652 op->o_ndn = save_ndn; 653 op->o_bd->bd_info = (BackendInfo *)on; 654 } 655 656 if ( map != NULL ) { 657 Attribute *a = *map; 658 AccessControlState acl_state = ACL_STATE_INIT; 659 660 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { 661 Entry *e; 662 663 op->o_bd->bd_info = (BackendInfo *)on->on_info; 664 /* access is checked with the original identity */ 665 rc = access_allowed( op, op->ora_e, mo->mo_ad_memberof, 666 &a->a_nvals[ i ], ACL_WADD, 667 &acl_state ); 668 if ( rc == 0 ) { 669 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 670 rs->sr_text = NULL; 671 send_ldap_result( op, rs ); 672 goto done; 673 } 674 /* ITS#6670 Ignore member pointing to this entry */ 675 if ( dn_match( &a->a_nvals[i], &save_ndn )) 676 continue; 677 678 rc = be_entry_get_rw( op, &a->a_nvals[ i ], 679 NULL, NULL, 0, &e ); 680 op->o_bd->bd_info = (BackendInfo *)on; 681 if ( rc != LDAP_SUCCESS ) { 682 if ( get_relax( op ) ) { 683 continue; 684 } 685 686 if ( MEMBEROF_DANGLING_ERROR( mo ) ) { 687 rc = rs->sr_err = mo->mo_dangling_err; 688 rs->sr_text = "adding non-existing object " 689 "as memberof"; 690 send_ldap_result( op, rs ); 691 goto done; 692 } 693 694 if ( MEMBEROF_DANGLING_DROP( mo ) ) { 695 int j; 696 697 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): " 698 "memberof=\"%s\" does not exist (stripping...)\n", 699 op->o_log_prefix, op->ora_e->e_name.bv_val, 700 a->a_nvals[ i ].bv_val ); 701 702 for ( j = i + 1; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ); 703 ber_memfree( a->a_vals[ i ].bv_val ); 704 BER_BVZERO( &a->a_vals[ i ] ); 705 if ( a->a_nvals != a->a_vals ) { 706 ber_memfree( a->a_nvals[ i ].bv_val ); 707 BER_BVZERO( &a->a_nvals[ i ] ); 708 } 709 if ( j - i == 1 ) { 710 break; 711 } 712 713 AC_MEMCPY( &a->a_vals[ i ], &a->a_vals[ i + 1 ], 714 sizeof( struct berval ) * ( j - i ) ); 715 if ( a->a_nvals != a->a_vals ) { 716 AC_MEMCPY( &a->a_nvals[ i ], &a->a_nvals[ i + 1 ], 717 sizeof( struct berval ) * ( j - i ) ); 718 } 719 i--; 720 } 721 722 continue; 723 } 724 725 /* access is checked with the original identity */ 726 op->o_bd->bd_info = (BackendInfo *)on->on_info; 727 rc = access_allowed( op, e, mo->mo_ad_member, 728 &op->o_req_ndn, ACL_WADD, NULL ); 729 be_entry_release_r( op, e ); 730 op->o_bd->bd_info = (BackendInfo *)on; 731 732 if ( !rc ) { 733 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 734 rs->sr_text = "insufficient access to object referenced by memberof"; 735 send_ldap_result( op, rs ); 736 goto done; 737 } 738 } 739 740 if ( BER_BVISNULL( &a->a_nvals[ 0 ] ) ) { 741 *map = a->a_next; 742 attr_free( a ); 743 } 744 } 745 746 rc = SLAP_CB_CONTINUE; 747 748 sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx ); 749 sc->sc_private = sc+1; 750 sc->sc_response = memberof_res_add; 751 sc->sc_cleanup = memberof_cleanup; 752 sc->sc_writewait = 0; 753 mci = sc->sc_private; 754 mci->on = on; 755 mci->member = NULL; 756 mci->memberof = NULL; 757 sc->sc_next = op->o_callback; 758 op->o_callback = sc; 759 760done:; 761 op->o_dn = save_dn; 762 op->o_ndn = save_ndn; 763 op->o_bd->bd_info = (BackendInfo *)on; 764 765 return rc; 766} 767 768static int 769memberof_op_delete( Operation *op, SlapReply *rs ) 770{ 771 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 772 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 773 774 slap_callback *sc; 775 memberof_cbinfo_t *mci; 776 OpExtra *oex; 777 778 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { 779 if ( oex->oe_key == (void *)&memberof ) 780 return SLAP_CB_CONTINUE; 781 } 782 783 sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx ); 784 sc->sc_private = sc+1; 785 sc->sc_response = memberof_res_delete; 786 sc->sc_cleanup = memberof_cleanup; 787 sc->sc_writewait = 0; 788 mci = sc->sc_private; 789 mci->on = on; 790 mci->member = NULL; 791 mci->memberof = NULL; 792 mci->what = MEMBEROF_IS_GROUP; 793 if ( MEMBEROF_REFINT( mo ) ) { 794 mci->what = MEMBEROF_IS_BOTH; 795 } 796 797 memberof_isGroupOrMember( op, mci ); 798 799 sc->sc_next = op->o_callback; 800 op->o_callback = sc; 801 802 return SLAP_CB_CONTINUE; 803} 804 805static int 806memberof_op_modify( Operation *op, SlapReply *rs ) 807{ 808 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 809 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 810 811 Modifications **mlp, **mmlp = NULL; 812 int rc = SLAP_CB_CONTINUE, save_member = 0; 813 struct berval save_dn, save_ndn; 814 slap_callback *sc; 815 memberof_cbinfo_t *mci, mcis; 816 OpExtra *oex; 817 818 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { 819 if ( oex->oe_key == (void *)&memberof ) 820 return SLAP_CB_CONTINUE; 821 } 822 823 if ( MEMBEROF_REVERSE( mo ) ) { 824 for ( mlp = &op->orm_modlist; *mlp; mlp = &(*mlp)->sml_next ) { 825 Modifications *ml = *mlp; 826 827 if ( ml->sml_desc == mo->mo_ad_memberof ) { 828 mmlp = mlp; 829 break; 830 } 831 } 832 } 833 834 save_dn = op->o_dn; 835 save_ndn = op->o_ndn; 836 mcis.on = on; 837 mcis.what = MEMBEROF_IS_GROUP; 838 839 if ( memberof_isGroupOrMember( op, &mcis ) == LDAP_SUCCESS 840 && ( mcis.what & MEMBEROF_IS_GROUP ) ) 841 { 842 Modifications *ml; 843 844 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { 845 if ( ml->sml_desc == mo->mo_ad_member ) { 846 switch ( ml->sml_op ) { 847 case LDAP_MOD_DELETE: 848 case LDAP_MOD_REPLACE: 849 case SLAP_MOD_SOFTDEL: /* ITS#7487: can be used by syncrepl (in mirror mode?) */ 850 save_member = 1; 851 break; 852 } 853 } 854 } 855 856 857 if ( MEMBEROF_DANGLING_CHECK( mo ) 858 && !get_relax( op ) ) 859 { 860 op->o_dn = op->o_bd->be_rootdn; 861 op->o_ndn = op->o_bd->be_rootndn; 862 op->o_bd->bd_info = (BackendInfo *)on->on_info; 863 864 assert( op->orm_modlist != NULL ); 865 866 for ( mlp = &op->orm_modlist; *mlp; ) { 867 Modifications *ml = *mlp; 868 int i; 869 870 if ( !is_ad_subtype( ml->sml_desc, mo->mo_ad_member ) ) { 871 mlp = &ml->sml_next; 872 continue; 873 } 874 875 switch ( ml->sml_op ) { 876 case LDAP_MOD_DELETE: 877 case SLAP_MOD_SOFTDEL: /* ITS#7487: can be used by syncrepl (in mirror mode?) */ 878 /* we don't care about cancellations: if the value 879 * exists, fine; if it doesn't, we let the underlying 880 * database fail as appropriate; */ 881 mlp = &ml->sml_next; 882 break; 883 884 case LDAP_MOD_REPLACE: 885 /* Handle this just like a delete (see above) */ 886 if ( !ml->sml_values ) { 887 mlp = &ml->sml_next; 888 break; 889 } 890 891 case LDAP_MOD_ADD: 892 case SLAP_MOD_SOFTADD: /* ITS#7487 */ 893 case SLAP_MOD_ADD_IF_NOT_PRESENT: /* ITS#7487 */ 894 /* NOTE: right now, the attributeType we use 895 * for member must have a normalized value */ 896 assert( ml->sml_nvalues != NULL ); 897 898 for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) { 899 Entry *e; 900 901 /* ITS#6670 Ignore member pointing to this entry */ 902 if ( dn_match( &ml->sml_nvalues[i], &save_ndn )) 903 continue; 904 905 if ( be_entry_get_rw( op, &ml->sml_nvalues[ i ], 906 NULL, NULL, 0, &e ) == LDAP_SUCCESS ) 907 { 908 be_entry_release_r( op, e ); 909 continue; 910 } 911 912 if ( MEMBEROF_DANGLING_ERROR( mo ) ) { 913 rc = rs->sr_err = mo->mo_dangling_err; 914 rs->sr_text = "adding non-existing object " 915 "as group member"; 916 send_ldap_result( op, rs ); 917 goto done; 918 } 919 920 if ( MEMBEROF_DANGLING_DROP( mo ) ) { 921 int j; 922 923 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): " 924 "member=\"%s\" does not exist (stripping...)\n", 925 op->o_log_prefix, op->o_req_dn.bv_val, 926 ml->sml_nvalues[ i ].bv_val ); 927 928 for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ ); 929 ber_memfree( ml->sml_values[ i ].bv_val ); 930 BER_BVZERO( &ml->sml_values[ i ] ); 931 ber_memfree( ml->sml_nvalues[ i ].bv_val ); 932 BER_BVZERO( &ml->sml_nvalues[ i ] ); 933 ml->sml_numvals--; 934 if ( j - i == 1 ) { 935 break; 936 } 937 938 AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ], 939 sizeof( struct berval ) * ( j - i ) ); 940 AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ], 941 sizeof( struct berval ) * ( j - i ) ); 942 i--; 943 } 944 } 945 946 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) { 947 *mlp = ml->sml_next; 948 slap_mod_free( &ml->sml_mod, 0 ); 949 free( ml ); 950 951 } else { 952 mlp = &ml->sml_next; 953 } 954 955 break; 956 957 default: 958 assert( 0 ); 959 } 960 } 961 } 962 } 963 964 if ( mmlp != NULL ) { 965 Modifications *ml = *mmlp; 966 int i; 967 Entry *target; 968 969 op->o_bd->bd_info = (BackendInfo *)on->on_info; 970 rc = be_entry_get_rw( op, &op->o_req_ndn, 971 NULL, NULL, 0, &target ); 972 op->o_bd->bd_info = (BackendInfo *)on; 973 if ( rc != LDAP_SUCCESS ) { 974 rc = rs->sr_err = LDAP_NO_SUCH_OBJECT; 975 send_ldap_result( op, rs ); 976 goto done; 977 } 978 979 switch ( ml->sml_op ) { 980 case LDAP_MOD_DELETE: 981 case SLAP_MOD_SOFTDEL: /* ITS#7487: can be used by syncrepl (in mirror mode?) */ 982 if ( ml->sml_nvalues != NULL ) { 983 AccessControlState acl_state = ACL_STATE_INIT; 984 985 for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) { 986 Entry *e; 987 988 op->o_bd->bd_info = (BackendInfo *)on->on_info; 989 /* access is checked with the original identity */ 990 rc = access_allowed( op, target, 991 mo->mo_ad_memberof, 992 &ml->sml_nvalues[ i ], 993 ACL_WDEL, 994 &acl_state ); 995 if ( rc == 0 ) { 996 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 997 rs->sr_text = NULL; 998 send_ldap_result( op, rs ); 999 goto done2; 1000 } 1001 1002 rc = be_entry_get_rw( op, &ml->sml_nvalues[ i ], 1003 NULL, NULL, 0, &e ); 1004 op->o_bd->bd_info = (BackendInfo *)on; 1005 if ( rc != LDAP_SUCCESS ) { 1006 if ( get_relax( op ) ) { 1007 continue; 1008 } 1009 1010 if ( MEMBEROF_DANGLING_ERROR( mo ) ) { 1011 rc = rs->sr_err = mo->mo_dangling_err; 1012 rs->sr_text = "deleting non-existing object " 1013 "as memberof"; 1014 send_ldap_result( op, rs ); 1015 goto done2; 1016 } 1017 1018 if ( MEMBEROF_DANGLING_DROP( mo ) ) { 1019 int j; 1020 1021 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): " 1022 "memberof=\"%s\" does not exist (stripping...)\n", 1023 op->o_log_prefix, op->o_req_ndn.bv_val, 1024 ml->sml_nvalues[ i ].bv_val ); 1025 1026 for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ ); 1027 ber_memfree( ml->sml_values[ i ].bv_val ); 1028 BER_BVZERO( &ml->sml_values[ i ] ); 1029 if ( ml->sml_nvalues != ml->sml_values ) { 1030 ber_memfree( ml->sml_nvalues[ i ].bv_val ); 1031 BER_BVZERO( &ml->sml_nvalues[ i ] ); 1032 } 1033 ml->sml_numvals--; 1034 if ( j - i == 1 ) { 1035 break; 1036 } 1037 1038 AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ], 1039 sizeof( struct berval ) * ( j - i ) ); 1040 if ( ml->sml_nvalues != ml->sml_values ) { 1041 AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ], 1042 sizeof( struct berval ) * ( j - i ) ); 1043 } 1044 i--; 1045 } 1046 1047 continue; 1048 } 1049 1050 /* access is checked with the original identity */ 1051 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1052 rc = access_allowed( op, e, mo->mo_ad_member, 1053 &op->o_req_ndn, 1054 ACL_WDEL, NULL ); 1055 be_entry_release_r( op, e ); 1056 op->o_bd->bd_info = (BackendInfo *)on; 1057 1058 if ( !rc ) { 1059 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1060 rs->sr_text = "insufficient access to object referenced by memberof"; 1061 send_ldap_result( op, rs ); 1062 goto done; 1063 } 1064 } 1065 1066 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) { 1067 *mmlp = ml->sml_next; 1068 slap_mod_free( &ml->sml_mod, 0 ); 1069 free( ml ); 1070 } 1071 1072 break; 1073 } 1074 /* fall thru */ 1075 1076 case LDAP_MOD_REPLACE: 1077 1078 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1079 /* access is checked with the original identity */ 1080 rc = access_allowed( op, target, 1081 mo->mo_ad_memberof, 1082 NULL, 1083 ACL_WDEL, NULL ); 1084 op->o_bd->bd_info = (BackendInfo *)on; 1085 if ( rc == 0 ) { 1086 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1087 rs->sr_text = NULL; 1088 send_ldap_result( op, rs ); 1089 goto done2; 1090 } 1091 1092 if ( ml->sml_op == LDAP_MOD_DELETE || ml->sml_op == SLAP_MOD_SOFTDEL || !ml->sml_values ) { 1093 break; 1094 } 1095 /* fall thru */ 1096 1097 case LDAP_MOD_ADD: 1098 case SLAP_MOD_SOFTADD: /* ITS#7487 */ 1099 case SLAP_MOD_ADD_IF_NOT_PRESENT: /* ITS#7487 */ 1100 { 1101 AccessControlState acl_state = ACL_STATE_INIT; 1102 1103 for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) { 1104 Entry *e; 1105 1106 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1107 /* access is checked with the original identity */ 1108 rc = access_allowed( op, target, 1109 mo->mo_ad_memberof, 1110 &ml->sml_nvalues[ i ], 1111 ACL_WADD, 1112 &acl_state ); 1113 if ( rc == 0 ) { 1114 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1115 rs->sr_text = NULL; 1116 send_ldap_result( op, rs ); 1117 goto done2; 1118 } 1119 1120 /* ITS#6670 Ignore member pointing to this entry */ 1121 if ( dn_match( &ml->sml_nvalues[i], &save_ndn )) 1122 continue; 1123 1124 rc = be_entry_get_rw( op, &ml->sml_nvalues[ i ], 1125 NULL, NULL, 0, &e ); 1126 op->o_bd->bd_info = (BackendInfo *)on; 1127 if ( rc != LDAP_SUCCESS ) { 1128 if ( MEMBEROF_DANGLING_ERROR( mo ) ) { 1129 rc = rs->sr_err = mo->mo_dangling_err; 1130 rs->sr_text = "adding non-existing object " 1131 "as memberof"; 1132 send_ldap_result( op, rs ); 1133 goto done2; 1134 } 1135 1136 if ( MEMBEROF_DANGLING_DROP( mo ) ) { 1137 int j; 1138 1139 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): " 1140 "memberof=\"%s\" does not exist (stripping...)\n", 1141 op->o_log_prefix, op->o_req_ndn.bv_val, 1142 ml->sml_nvalues[ i ].bv_val ); 1143 1144 for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ ); 1145 ber_memfree( ml->sml_values[ i ].bv_val ); 1146 BER_BVZERO( &ml->sml_values[ i ] ); 1147 if ( ml->sml_nvalues != ml->sml_values ) { 1148 ber_memfree( ml->sml_nvalues[ i ].bv_val ); 1149 BER_BVZERO( &ml->sml_nvalues[ i ] ); 1150 } 1151 ml->sml_numvals--; 1152 if ( j - i == 1 ) { 1153 break; 1154 } 1155 1156 AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ], 1157 sizeof( struct berval ) * ( j - i ) ); 1158 if ( ml->sml_nvalues != ml->sml_values ) { 1159 AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ], 1160 sizeof( struct berval ) * ( j - i ) ); 1161 } 1162 i--; 1163 } 1164 1165 continue; 1166 } 1167 1168 /* access is checked with the original identity */ 1169 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1170 rc = access_allowed( op, e, mo->mo_ad_member, 1171 &op->o_req_ndn, 1172 ACL_WDEL, NULL ); 1173 be_entry_release_r( op, e ); 1174 op->o_bd->bd_info = (BackendInfo *)on; 1175 1176 if ( !rc ) { 1177 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1178 rs->sr_text = "insufficient access to object referenced by memberof"; 1179 send_ldap_result( op, rs ); 1180 goto done; 1181 } 1182 } 1183 1184 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) { 1185 *mmlp = ml->sml_next; 1186 slap_mod_free( &ml->sml_mod, 0 ); 1187 free( ml ); 1188 } 1189 1190 } break; 1191 1192 default: 1193 assert( 0 ); 1194 } 1195 1196done2:; 1197 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1198 be_entry_release_r( op, target ); 1199 op->o_bd->bd_info = (BackendInfo *)on; 1200 } 1201 1202 sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx ); 1203 sc->sc_private = sc+1; 1204 sc->sc_response = memberof_res_modify; 1205 sc->sc_cleanup = memberof_cleanup; 1206 sc->sc_writewait = 0; 1207 mci = sc->sc_private; 1208 mci->on = on; 1209 mci->member = NULL; 1210 mci->memberof = NULL; 1211 mci->what = mcis.what; 1212 1213 if ( save_member ) { 1214 op->o_dn = op->o_bd->be_rootdn; 1215 op->o_ndn = op->o_bd->be_rootndn; 1216 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1217 rc = backend_attribute( op, NULL, &op->o_req_ndn, 1218 mo->mo_ad_member, &mci->member, ACL_READ ); 1219 op->o_bd->bd_info = (BackendInfo *)on; 1220 } 1221 1222 sc->sc_next = op->o_callback; 1223 op->o_callback = sc; 1224 1225 rc = SLAP_CB_CONTINUE; 1226 1227done:; 1228 op->o_dn = save_dn; 1229 op->o_ndn = save_ndn; 1230 op->o_bd->bd_info = (BackendInfo *)on; 1231 1232 return rc; 1233} 1234 1235static int 1236memberof_op_modrdn( Operation *op, SlapReply *rs ) 1237{ 1238 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1239 slap_callback *sc; 1240 memberof_cbinfo_t *mci; 1241 OpExtra *oex; 1242 1243 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { 1244 if ( oex->oe_key == (void *)&memberof ) 1245 return SLAP_CB_CONTINUE; 1246 } 1247 1248 sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx ); 1249 sc->sc_private = sc+1; 1250 sc->sc_response = memberof_res_modrdn; 1251 sc->sc_cleanup = memberof_cleanup; 1252 sc->sc_writewait = 0; 1253 mci = sc->sc_private; 1254 mci->on = on; 1255 mci->member = NULL; 1256 mci->memberof = NULL; 1257 1258 sc->sc_next = op->o_callback; 1259 op->o_callback = sc; 1260 1261 return SLAP_CB_CONTINUE; 1262} 1263 1264/* 1265 * response callback that adds memberof values when a group is added. 1266 */ 1267static int 1268memberof_res_add( Operation *op, SlapReply *rs ) 1269{ 1270 memberof_cbinfo_t *mci = op->o_callback->sc_private; 1271 slap_overinst *on = mci->on; 1272 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 1273 1274 int i; 1275 1276 if ( rs->sr_err != LDAP_SUCCESS ) { 1277 return SLAP_CB_CONTINUE; 1278 } 1279 1280 if ( MEMBEROF_REVERSE( mo ) ) { 1281 Attribute *ma; 1282 1283 ma = attr_find( op->ora_e->e_attrs, mo->mo_ad_memberof ); 1284 if ( ma != NULL ) { 1285 /* relax is required to allow to add 1286 * a non-existing member */ 1287 op->o_relax = SLAP_CONTROL_CRITICAL; 1288 1289 for ( i = 0; !BER_BVISNULL( &ma->a_nvals[ i ] ); i++ ) { 1290 1291 /* ITS#6670 Ignore member pointing to this entry */ 1292 if ( dn_match( &ma->a_nvals[i], &op->o_req_ndn )) 1293 continue; 1294 1295 /* the modification is attempted 1296 * with the original identity */ 1297 memberof_value_modify( op, 1298 &ma->a_nvals[ i ], mo->mo_ad_member, 1299 NULL, NULL, &op->o_req_dn, &op->o_req_ndn ); 1300 } 1301 } 1302 } 1303 1304 if ( is_entry_objectclass_or_sub( op->ora_e, mo->mo_oc_group ) ) { 1305 Attribute *a; 1306 1307 for ( a = attrs_find( op->ora_e->e_attrs, mo->mo_ad_member ); 1308 a != NULL; 1309 a = attrs_find( a->a_next, mo->mo_ad_member ) ) 1310 { 1311 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { 1312 /* ITS#6670 Ignore member pointing to this entry */ 1313 if ( dn_match( &a->a_nvals[i], &op->o_req_ndn )) 1314 continue; 1315 1316 memberof_value_modify( op, 1317 &a->a_nvals[ i ], 1318 mo->mo_ad_memberof, 1319 NULL, NULL, 1320 &op->o_req_dn, 1321 &op->o_req_ndn ); 1322 } 1323 } 1324 } 1325 1326 return SLAP_CB_CONTINUE; 1327} 1328 1329/* 1330 * response callback that deletes memberof values when a group is deleted. 1331 */ 1332static int 1333memberof_res_delete( Operation *op, SlapReply *rs ) 1334{ 1335 memberof_cbinfo_t *mci = op->o_callback->sc_private; 1336 slap_overinst *on = mci->on; 1337 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 1338 1339 BerVarray vals; 1340 int i; 1341 1342 if ( rs->sr_err != LDAP_SUCCESS ) { 1343 return SLAP_CB_CONTINUE; 1344 } 1345 1346 vals = mci->member; 1347 if ( vals != NULL ) { 1348 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { 1349 memberof_value_modify( op, 1350 &vals[ i ], mo->mo_ad_memberof, 1351 &op->o_req_dn, &op->o_req_ndn, 1352 NULL, NULL ); 1353 } 1354 } 1355 1356 if ( MEMBEROF_REFINT( mo ) ) { 1357 vals = mci->memberof; 1358 if ( vals != NULL ) { 1359 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { 1360 memberof_value_modify( op, 1361 &vals[ i ], mo->mo_ad_member, 1362 &op->o_req_dn, &op->o_req_ndn, 1363 NULL, NULL ); 1364 } 1365 } 1366 } 1367 1368 return SLAP_CB_CONTINUE; 1369} 1370 1371/* 1372 * response callback that adds/deletes memberof values when a group 1373 * is modified. 1374 */ 1375static int 1376memberof_res_modify( Operation *op, SlapReply *rs ) 1377{ 1378 memberof_cbinfo_t *mci = op->o_callback->sc_private; 1379 slap_overinst *on = mci->on; 1380 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 1381 1382 int i, rc; 1383 Modifications *ml, *mml = NULL; 1384 BerVarray vals; 1385 1386 if ( rs->sr_err != LDAP_SUCCESS ) { 1387 return SLAP_CB_CONTINUE; 1388 } 1389 1390 if ( MEMBEROF_REVERSE( mo ) ) { 1391 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { 1392 if ( ml->sml_desc == mo->mo_ad_memberof ) { 1393 mml = ml; 1394 break; 1395 } 1396 } 1397 } 1398 1399 if ( mml != NULL ) { 1400 BerVarray vals = mml->sml_nvalues; 1401 1402 switch ( mml->sml_op ) { 1403 case LDAP_MOD_DELETE: 1404 case SLAP_MOD_SOFTDEL: /* ITS#7487: can be used by syncrepl (in mirror mode?) */ 1405 if ( vals != NULL ) { 1406 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { 1407 memberof_value_modify( op, 1408 &vals[ i ], mo->mo_ad_member, 1409 &op->o_req_dn, &op->o_req_ndn, 1410 NULL, NULL ); 1411 } 1412 break; 1413 } 1414 /* fall thru */ 1415 1416 case LDAP_MOD_REPLACE: 1417 /* delete all ... */ 1418 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1419 rc = backend_attribute( op, NULL, &op->o_req_ndn, 1420 mo->mo_ad_memberof, &vals, ACL_READ ); 1421 op->o_bd->bd_info = (BackendInfo *)on; 1422 if ( rc == LDAP_SUCCESS ) { 1423 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { 1424 memberof_value_modify( op, 1425 &vals[ i ], mo->mo_ad_member, 1426 &op->o_req_dn, &op->o_req_ndn, 1427 NULL, NULL ); 1428 } 1429 ber_bvarray_free_x( vals, op->o_tmpmemctx ); 1430 } 1431 1432 if ( ml->sml_op == LDAP_MOD_DELETE || !mml->sml_values ) { 1433 break; 1434 } 1435 /* fall thru */ 1436 1437 case LDAP_MOD_ADD: 1438 case SLAP_MOD_SOFTADD: /* ITS#7487 */ 1439 case SLAP_MOD_ADD_IF_NOT_PRESENT: /* ITS#7487 */ 1440 assert( vals != NULL ); 1441 1442 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { 1443 memberof_value_modify( op, 1444 &vals[ i ], mo->mo_ad_member, 1445 NULL, NULL, 1446 &op->o_req_dn, &op->o_req_ndn ); 1447 } 1448 break; 1449 1450 default: 1451 assert( 0 ); 1452 } 1453 } 1454 1455 if ( mci->what & MEMBEROF_IS_GROUP ) 1456 { 1457 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { 1458 if ( ml->sml_desc != mo->mo_ad_member ) { 1459 continue; 1460 } 1461 1462 switch ( ml->sml_op ) { 1463 case LDAP_MOD_DELETE: 1464 case SLAP_MOD_SOFTDEL: /* ITS#7487: can be used by syncrepl (in mirror mode?) */ 1465 vals = ml->sml_nvalues; 1466 if ( vals != NULL ) { 1467 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { 1468 memberof_value_modify( op, 1469 &vals[ i ], mo->mo_ad_memberof, 1470 &op->o_req_dn, &op->o_req_ndn, 1471 NULL, NULL ); 1472 } 1473 break; 1474 } 1475 /* fall thru */ 1476 1477 case LDAP_MOD_REPLACE: 1478 vals = mci->member; 1479 1480 /* delete all ... */ 1481 if ( vals != NULL ) { 1482 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { 1483 memberof_value_modify( op, 1484 &vals[ i ], mo->mo_ad_memberof, 1485 &op->o_req_dn, &op->o_req_ndn, 1486 NULL, NULL ); 1487 } 1488 } 1489 1490 if ( ml->sml_op == LDAP_MOD_DELETE || ml->sml_op == SLAP_MOD_SOFTDEL || !ml->sml_values ) { 1491 break; 1492 } 1493 /* fall thru */ 1494 1495 case LDAP_MOD_ADD: 1496 case SLAP_MOD_SOFTADD: /* ITS#7487 */ 1497 case SLAP_MOD_ADD_IF_NOT_PRESENT : /* ITS#7487 */ 1498 assert( ml->sml_nvalues != NULL ); 1499 vals = ml->sml_nvalues; 1500 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { 1501 memberof_value_modify( op, 1502 &vals[ i ], mo->mo_ad_memberof, 1503 NULL, NULL, 1504 &op->o_req_dn, &op->o_req_ndn ); 1505 } 1506 break; 1507 1508 default: 1509 assert( 0 ); 1510 } 1511 } 1512 } 1513 1514 return SLAP_CB_CONTINUE; 1515} 1516 1517/* 1518 * response callback that adds/deletes member values when a group member 1519 * is renamed. 1520 */ 1521static int 1522memberof_res_modrdn( Operation *op, SlapReply *rs ) 1523{ 1524 memberof_cbinfo_t *mci = op->o_callback->sc_private; 1525 slap_overinst *on = mci->on; 1526 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 1527 1528 struct berval newPDN, newDN = BER_BVNULL, newPNDN, newNDN; 1529 int i, rc; 1530 BerVarray vals; 1531 1532 struct berval save_dn, save_ndn; 1533 1534 if ( rs->sr_err != LDAP_SUCCESS ) { 1535 return SLAP_CB_CONTINUE; 1536 } 1537 1538 mci->what = MEMBEROF_IS_GROUP; 1539 if ( MEMBEROF_REFINT( mo ) ) { 1540 mci->what |= MEMBEROF_IS_MEMBER; 1541 } 1542 1543 if ( op->orr_nnewSup ) { 1544 newPNDN = *op->orr_nnewSup; 1545 1546 } else { 1547 dnParent( &op->o_req_ndn, &newPNDN ); 1548 } 1549 1550 build_new_dn( &newNDN, &newPNDN, &op->orr_nnewrdn, op->o_tmpmemctx ); 1551 1552 save_dn = op->o_req_dn; 1553 save_ndn = op->o_req_ndn; 1554 1555 op->o_req_dn = newNDN; 1556 op->o_req_ndn = newNDN; 1557 rc = memberof_isGroupOrMember( op, mci ); 1558 op->o_req_dn = save_dn; 1559 op->o_req_ndn = save_ndn; 1560 1561 if ( rc != LDAP_SUCCESS || mci->what == MEMBEROF_IS_NONE ) { 1562 goto done; 1563 } 1564 1565 if ( op->orr_newSup ) { 1566 newPDN = *op->orr_newSup; 1567 1568 } else { 1569 dnParent( &op->o_req_dn, &newPDN ); 1570 } 1571 1572 build_new_dn( &newDN, &newPDN, &op->orr_newrdn, op->o_tmpmemctx ); 1573 1574 if ( mci->what & MEMBEROF_IS_GROUP ) { 1575 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1576 rc = backend_attribute( op, NULL, &newNDN, 1577 mo->mo_ad_member, &vals, ACL_READ ); 1578 op->o_bd->bd_info = (BackendInfo *)on; 1579 1580 if ( rc == LDAP_SUCCESS ) { 1581 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { 1582 memberof_value_modify( op, 1583 &vals[ i ], mo->mo_ad_memberof, 1584 &op->o_req_dn, &op->o_req_ndn, 1585 &newDN, &newNDN ); 1586 } 1587 ber_bvarray_free_x( vals, op->o_tmpmemctx ); 1588 } 1589 } 1590 1591 if ( MEMBEROF_REFINT( mo ) && ( mci->what & MEMBEROF_IS_MEMBER ) ) { 1592 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1593 rc = backend_attribute( op, NULL, &newNDN, 1594 mo->mo_ad_memberof, &vals, ACL_READ ); 1595 op->o_bd->bd_info = (BackendInfo *)on; 1596 1597 if ( rc == LDAP_SUCCESS ) { 1598 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { 1599 memberof_value_modify( op, 1600 &vals[ i ], mo->mo_ad_member, 1601 &op->o_req_dn, &op->o_req_ndn, 1602 &newDN, &newNDN ); 1603 } 1604 ber_bvarray_free_x( vals, op->o_tmpmemctx ); 1605 } 1606 } 1607 1608done:; 1609 if ( !BER_BVISNULL( &newDN ) ) { 1610 op->o_tmpfree( newDN.bv_val, op->o_tmpmemctx ); 1611 } 1612 op->o_tmpfree( newNDN.bv_val, op->o_tmpmemctx ); 1613 1614 return SLAP_CB_CONTINUE; 1615} 1616 1617 1618static int 1619memberof_db_init( 1620 BackendDB *be, 1621 ConfigReply *cr ) 1622{ 1623 slap_overinst *on = (slap_overinst *)be->bd_info; 1624 memberof_t *mo; 1625 const char *text = NULL; 1626 int rc; 1627 1628 mo = (memberof_t *)ch_calloc( 1, sizeof( memberof_t ) ); 1629 1630 /* safe default */ 1631 mo->mo_dangling_err = LDAP_CONSTRAINT_VIOLATION; 1632 1633 if ( !ad_memberOf ) { 1634 rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &ad_memberOf, &text ); 1635 if ( rc != LDAP_SUCCESS ) { 1636 Debug( LDAP_DEBUG_ANY, "memberof_db_init: " 1637 "unable to find attribute=\"%s\": %s (%d)\n", 1638 SLAPD_MEMBEROF_ATTR, text, rc ); 1639 return rc; 1640 } 1641 } 1642 1643 if ( !ad_member ) { 1644 rc = slap_str2ad( SLAPD_GROUP_ATTR, &ad_member, &text ); 1645 if ( rc != LDAP_SUCCESS ) { 1646 Debug( LDAP_DEBUG_ANY, "memberof_db_init: " 1647 "unable to find attribute=\"%s\": %s (%d)\n", 1648 SLAPD_GROUP_ATTR, text, rc ); 1649 return rc; 1650 } 1651 } 1652 1653 if ( !oc_group ) { 1654 oc_group = oc_find( SLAPD_GROUP_CLASS ); 1655 if ( oc_group == NULL ) { 1656 Debug( LDAP_DEBUG_ANY, 1657 "memberof_db_init: " 1658 "unable to find objectClass=\"%s\"\n", 1659 SLAPD_GROUP_CLASS ); 1660 return 1; 1661 } 1662 } 1663 1664 on->on_bi.bi_private = (void *)mo; 1665 1666 return 0; 1667} 1668 1669enum { 1670 MO_DN = 1, 1671 MO_DANGLING, 1672 MO_REFINT, 1673 MO_GROUP_OC, 1674 MO_MEMBER_AD, 1675 MO_MEMBER_OF_AD, 1676#if 0 1677 MO_REVERSE, 1678#endif 1679 1680 MO_DANGLING_ERROR, 1681 1682 MO_LAST 1683}; 1684 1685static ConfigDriver mo_cf_gen; 1686 1687#define OID "1.3.6.1.4.1.7136.2.666.4" 1688#define OIDAT OID ".1.1" 1689#define OIDCFGAT OID ".1.2" 1690#define OIDOC OID ".2.1" 1691#define OIDCFGOC OID ".2.2" 1692 1693 1694static ConfigTable mo_cfg[] = { 1695 { "memberof-dn", "modifiersName", 1696 2, 2, 0, ARG_MAGIC|ARG_QUOTE|ARG_DN|MO_DN, mo_cf_gen, 1697 "( OLcfgOvAt:18.0 NAME 'olcMemberOfDN' " 1698 "DESC 'DN to be used as modifiersName' " 1699 "EQUALITY distinguishedNameMatch " 1700 "SYNTAX OMsDN SINGLE-VALUE )", 1701 NULL, NULL }, 1702 1703 { "memberof-dangling", "ignore|drop|error", 1704 2, 2, 0, ARG_MAGIC|MO_DANGLING, mo_cf_gen, 1705 "( OLcfgOvAt:18.1 NAME 'olcMemberOfDangling' " 1706 "DESC 'Behavior with respect to dangling members, " 1707 "constrained to ignore, drop, error' " 1708 "EQUALITY caseIgnoreMatch " 1709 "SYNTAX OMsDirectoryString SINGLE-VALUE )", 1710 NULL, NULL }, 1711 1712 { "memberof-refint", "true|FALSE", 1713 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|MO_REFINT, mo_cf_gen, 1714 "( OLcfgOvAt:18.2 NAME 'olcMemberOfRefInt' " 1715 "DESC 'Take care of referential integrity' " 1716 "EQUALITY booleanMatch " 1717 "SYNTAX OMsBoolean SINGLE-VALUE )", 1718 NULL, NULL }, 1719 1720 { "memberof-group-oc", "objectClass", 1721 2, 2, 0, ARG_MAGIC|MO_GROUP_OC, mo_cf_gen, 1722 "( OLcfgOvAt:18.3 NAME 'olcMemberOfGroupOC' " 1723 "DESC 'Group objectClass' " 1724 "EQUALITY caseIgnoreMatch " 1725 "SYNTAX OMsDirectoryString SINGLE-VALUE )", 1726 NULL, NULL }, 1727 1728 { "memberof-member-ad", "member attribute", 1729 2, 2, 0, ARG_MAGIC|ARG_ATDESC|MO_MEMBER_AD, mo_cf_gen, 1730 "( OLcfgOvAt:18.4 NAME 'olcMemberOfMemberAD' " 1731 "DESC 'member attribute' " 1732 "EQUALITY caseIgnoreMatch " 1733 "SYNTAX OMsDirectoryString SINGLE-VALUE )", 1734 NULL, NULL }, 1735 1736 { "memberof-memberof-ad", "memberOf attribute", 1737 2, 2, 0, ARG_MAGIC|ARG_ATDESC|MO_MEMBER_OF_AD, mo_cf_gen, 1738 "( OLcfgOvAt:18.5 NAME 'olcMemberOfMemberOfAD' " 1739 "DESC 'memberOf attribute' " 1740 "EQUALITY caseIgnoreMatch " 1741 "SYNTAX OMsDirectoryString SINGLE-VALUE )", 1742 NULL, NULL }, 1743 1744#if 0 1745 { "memberof-reverse", "true|FALSE", 1746 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|MO_REVERSE, mo_cf_gen, 1747 "( OLcfgOvAt:18.6 NAME 'olcMemberOfReverse' " 1748 "DESC 'Take care of referential integrity " 1749 "also when directly modifying memberOf' " 1750 "SYNTAX OMsBoolean SINGLE-VALUE )", 1751 NULL, NULL }, 1752#endif 1753 1754 { "memberof-dangling-error", "error code", 1755 2, 2, 0, ARG_MAGIC|MO_DANGLING_ERROR, mo_cf_gen, 1756 "( OLcfgOvAt:18.7 NAME 'olcMemberOfDanglingError' " 1757 "DESC 'Error code returned in case of dangling back reference' " 1758 "EQUALITY caseIgnoreMatch " 1759 "SYNTAX OMsDirectoryString SINGLE-VALUE )", 1760 NULL, NULL }, 1761 1762 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 1763}; 1764 1765static ConfigOCs mo_ocs[] = { 1766 { "( OLcfgOvOc:18.1 " 1767 "NAME ( 'olcMemberOfConfig' 'olcMemberOf' ) " 1768 "DESC 'Member-of configuration' " 1769 "SUP olcOverlayConfig " 1770 "MAY ( " 1771 "olcMemberOfDN " 1772 "$ olcMemberOfDangling " 1773 "$ olcMemberOfDanglingError" 1774 "$ olcMemberOfRefInt " 1775 "$ olcMemberOfGroupOC " 1776 "$ olcMemberOfMemberAD " 1777 "$ olcMemberOfMemberOfAD " 1778#if 0 1779 "$ olcMemberOfReverse " 1780#endif 1781 ") " 1782 ")", 1783 Cft_Overlay, mo_cfg, NULL, NULL }, 1784 { NULL, 0, NULL } 1785}; 1786 1787static slap_verbmasks dangling_mode[] = { 1788 { BER_BVC( "ignore" ), MEMBEROF_NONE }, 1789 { BER_BVC( "drop" ), MEMBEROF_FDANGLING_DROP }, 1790 { BER_BVC( "error" ), MEMBEROF_FDANGLING_ERROR }, 1791 { BER_BVNULL, 0 } 1792}; 1793 1794static int 1795memberof_make_group_filter( memberof_t *mo ) 1796{ 1797 char *ptr; 1798 1799 if ( !BER_BVISNULL( &mo->mo_groupFilterstr ) ) { 1800 ch_free( mo->mo_groupFilterstr.bv_val ); 1801 } 1802 1803 mo->mo_groupFilter.f_choice = LDAP_FILTER_EQUALITY; 1804 mo->mo_groupFilter.f_ava = &mo->mo_groupAVA; 1805 1806 mo->mo_groupFilter.f_av_desc = slap_schema.si_ad_objectClass; 1807 mo->mo_groupFilter.f_av_value = mo->mo_oc_group->soc_cname; 1808 1809 mo->mo_groupFilterstr.bv_len = STRLENOF( "(=)" ) 1810 + slap_schema.si_ad_objectClass->ad_cname.bv_len 1811 + mo->mo_oc_group->soc_cname.bv_len; 1812 ptr = mo->mo_groupFilterstr.bv_val = ch_malloc( mo->mo_groupFilterstr.bv_len + 1 ); 1813 *ptr++ = '('; 1814 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val ); 1815 *ptr++ = '='; 1816 ptr = lutil_strcopy( ptr, mo->mo_oc_group->soc_cname.bv_val ); 1817 *ptr++ = ')'; 1818 *ptr = '\0'; 1819 1820 return 0; 1821} 1822 1823static int 1824memberof_make_member_filter( memberof_t *mo ) 1825{ 1826 char *ptr; 1827 1828 if ( !BER_BVISNULL( &mo->mo_memberFilterstr ) ) { 1829 ch_free( mo->mo_memberFilterstr.bv_val ); 1830 } 1831 1832 mo->mo_memberFilter.f_choice = LDAP_FILTER_PRESENT; 1833 mo->mo_memberFilter.f_desc = mo->mo_ad_memberof; 1834 1835 mo->mo_memberFilterstr.bv_len = STRLENOF( "(=*)" ) 1836 + mo->mo_ad_memberof->ad_cname.bv_len; 1837 ptr = mo->mo_memberFilterstr.bv_val = ch_malloc( mo->mo_memberFilterstr.bv_len + 1 ); 1838 *ptr++ = '('; 1839 ptr = lutil_strcopy( ptr, mo->mo_ad_memberof->ad_cname.bv_val ); 1840 ptr = lutil_strcopy( ptr, "=*)" ); 1841 1842 return 0; 1843} 1844 1845static int 1846mo_cf_gen( ConfigArgs *c ) 1847{ 1848 slap_overinst *on = (slap_overinst *)c->bi; 1849 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 1850 1851 int i, rc = 0; 1852 1853 if ( c->op == SLAP_CONFIG_EMIT ) { 1854 struct berval bv = BER_BVNULL; 1855 1856 switch( c->type ) { 1857 case MO_DN: 1858 if ( mo->mo_dn.bv_val != NULL) { 1859 value_add_one( &c->rvalue_vals, &mo->mo_dn ); 1860 value_add_one( &c->rvalue_nvals, &mo->mo_ndn ); 1861 } 1862 break; 1863 1864 case MO_DANGLING: 1865 enum_to_verb( dangling_mode, (mo->mo_flags & MEMBEROF_FDANGLING_MASK), &bv ); 1866 if ( BER_BVISNULL( &bv ) ) { 1867 /* there's something wrong... */ 1868 assert( 0 ); 1869 rc = 1; 1870 1871 } else { 1872 value_add_one( &c->rvalue_vals, &bv ); 1873 } 1874 break; 1875 1876 case MO_DANGLING_ERROR: 1877 if ( mo->mo_flags & MEMBEROF_FDANGLING_ERROR ) { 1878 char buf[ SLAP_TEXT_BUFLEN ]; 1879 enum_to_verb( slap_ldap_response_code, mo->mo_dangling_err, &bv ); 1880 if ( BER_BVISNULL( &bv ) ) { 1881 bv.bv_len = snprintf( buf, sizeof( buf ), "0x%x", mo->mo_dangling_err ); 1882 if ( bv.bv_len < sizeof( buf ) ) { 1883 bv.bv_val = buf; 1884 } else { 1885 rc = 1; 1886 break; 1887 } 1888 } 1889 value_add_one( &c->rvalue_vals, &bv ); 1890 } else { 1891 rc = 1; 1892 } 1893 break; 1894 1895 case MO_REFINT: 1896 c->value_int = MEMBEROF_REFINT( mo ); 1897 break; 1898 1899#if 0 1900 case MO_REVERSE: 1901 c->value_int = MEMBEROF_REVERSE( mo ); 1902 break; 1903#endif 1904 1905 case MO_GROUP_OC: 1906 if ( mo->mo_oc_group != NULL ){ 1907 value_add_one( &c->rvalue_vals, &mo->mo_oc_group->soc_cname ); 1908 } 1909 break; 1910 1911 case MO_MEMBER_AD: 1912 c->value_ad = mo->mo_ad_member; 1913 break; 1914 1915 case MO_MEMBER_OF_AD: 1916 c->value_ad = mo->mo_ad_memberof; 1917 break; 1918 1919 default: 1920 assert( 0 ); 1921 return 1; 1922 } 1923 1924 return rc; 1925 1926 } else if ( c->op == LDAP_MOD_DELETE ) { 1927 switch( c->type ) { 1928 case MO_DN: 1929 if ( !BER_BVISNULL( &mo->mo_dn ) ) { 1930 ber_memfree( mo->mo_dn.bv_val ); 1931 ber_memfree( mo->mo_ndn.bv_val ); 1932 BER_BVZERO( &mo->mo_dn ); 1933 BER_BVZERO( &mo->mo_ndn ); 1934 } 1935 break; 1936 1937 case MO_DANGLING: 1938 mo->mo_flags &= ~MEMBEROF_FDANGLING_MASK; 1939 break; 1940 1941 case MO_DANGLING_ERROR: 1942 mo->mo_dangling_err = LDAP_CONSTRAINT_VIOLATION; 1943 break; 1944 1945 case MO_REFINT: 1946 mo->mo_flags &= ~MEMBEROF_FREFINT; 1947 break; 1948 1949#if 0 1950 case MO_REVERSE: 1951 mo->mo_flags &= ~MEMBEROF_FREVERSE; 1952 break; 1953#endif 1954 1955 case MO_GROUP_OC: 1956 mo->mo_oc_group = oc_group; 1957 memberof_make_group_filter( mo ); 1958 break; 1959 1960 case MO_MEMBER_AD: 1961 mo->mo_ad_member = ad_member; 1962 break; 1963 1964 case MO_MEMBER_OF_AD: 1965 mo->mo_ad_memberof = ad_memberOf; 1966 memberof_make_member_filter( mo ); 1967 break; 1968 1969 default: 1970 assert( 0 ); 1971 return 1; 1972 } 1973 1974 } else { 1975 switch( c->type ) { 1976 case MO_DN: 1977 if ( !BER_BVISNULL( &mo->mo_dn ) ) { 1978 ber_memfree( mo->mo_dn.bv_val ); 1979 ber_memfree( mo->mo_ndn.bv_val ); 1980 } 1981 mo->mo_dn = c->value_dn; 1982 mo->mo_ndn = c->value_ndn; 1983 break; 1984 1985 case MO_DANGLING: 1986 i = verb_to_mask( c->argv[ 1 ], dangling_mode ); 1987 if ( BER_BVISNULL( &dangling_mode[ i ].word ) ) { 1988 return 1; 1989 } 1990 1991 mo->mo_flags &= ~MEMBEROF_FDANGLING_MASK; 1992 mo->mo_flags |= dangling_mode[ i ].mask; 1993 break; 1994 1995 case MO_DANGLING_ERROR: 1996 i = verb_to_mask( c->argv[ 1 ], slap_ldap_response_code ); 1997 if ( !BER_BVISNULL( &slap_ldap_response_code[ i ].word ) ) { 1998 mo->mo_dangling_err = slap_ldap_response_code[ i ].mask; 1999 } else if ( lutil_atoix( &mo->mo_dangling_err, c->argv[ 1 ], 0 ) ) { 2000 return 1; 2001 } 2002 break; 2003 2004 case MO_REFINT: 2005 if ( c->value_int ) { 2006 mo->mo_flags |= MEMBEROF_FREFINT; 2007 2008 } else { 2009 mo->mo_flags &= ~MEMBEROF_FREFINT; 2010 } 2011 break; 2012 2013#if 0 2014 case MO_REVERSE: 2015 if ( c->value_int ) { 2016 mo->mo_flags |= MEMBEROF_FREVERSE; 2017 2018 } else { 2019 mo->mo_flags &= ~MEMBEROF_FREVERSE; 2020 } 2021 break; 2022#endif 2023 2024 case MO_GROUP_OC: { 2025 ObjectClass *oc = NULL; 2026 2027 oc = oc_find( c->argv[ 1 ] ); 2028 if ( oc == NULL ) { 2029 snprintf( c->cr_msg, sizeof( c->cr_msg ), 2030 "unable to find group objectClass=\"%s\"", 2031 c->argv[ 1 ] ); 2032 Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", 2033 c->log, c->cr_msg ); 2034 return 1; 2035 } 2036 2037 mo->mo_oc_group = oc; 2038 memberof_make_group_filter( mo ); 2039 } break; 2040 2041 case MO_MEMBER_AD: { 2042 AttributeDescription *ad = c->value_ad; 2043 2044 if ( !is_at_syntax( ad->ad_type, SLAPD_DN_SYNTAX ) /* e.g. "member" */ 2045 && !is_at_syntax( ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */ 2046 { 2047 snprintf( c->cr_msg, sizeof( c->cr_msg ), 2048 "member attribute=\"%s\" must either " 2049 "have DN (%s) or nameUID (%s) syntax", 2050 c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX ); 2051 Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", 2052 c->log, c->cr_msg ); 2053 return 1; 2054 } 2055 2056 mo->mo_ad_member = ad; 2057 } break; 2058 2059 case MO_MEMBER_OF_AD: { 2060 AttributeDescription *ad = c->value_ad; 2061 2062 if ( !is_at_syntax( ad->ad_type, SLAPD_DN_SYNTAX ) /* e.g. "member" */ 2063 && !is_at_syntax( ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */ 2064 { 2065 snprintf( c->cr_msg, sizeof( c->cr_msg ), 2066 "memberof attribute=\"%s\" must either " 2067 "have DN (%s) or nameUID (%s) syntax", 2068 c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX ); 2069 Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", 2070 c->log, c->cr_msg ); 2071 return 1; 2072 } 2073 2074 mo->mo_ad_memberof = ad; 2075 memberof_make_member_filter( mo ); 2076 } break; 2077 2078 default: 2079 assert( 0 ); 2080 return 1; 2081 } 2082 } 2083 2084 return 0; 2085} 2086 2087static int 2088memberof_db_open( 2089 BackendDB *be, 2090 ConfigReply *cr ) 2091{ 2092 slap_overinst *on = (slap_overinst *)be->bd_info; 2093 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 2094 2095 int rc; 2096 2097 if ( !mo->mo_ad_memberof ) { 2098 mo->mo_ad_memberof = ad_memberOf; 2099 } 2100 2101 if ( ! mo->mo_ad_member ) { 2102 mo->mo_ad_member = ad_member; 2103 } 2104 2105 if ( ! mo->mo_oc_group ) { 2106 mo->mo_oc_group = oc_group; 2107 } 2108 2109 if ( BER_BVISNULL( &mo->mo_dn ) && !BER_BVISNULL( &be->be_rootdn ) ) { 2110 ber_dupbv( &mo->mo_dn, &be->be_rootdn ); 2111 ber_dupbv( &mo->mo_ndn, &be->be_rootndn ); 2112 } 2113 2114 if ( BER_BVISNULL( &mo->mo_groupFilterstr ) ) { 2115 memberof_make_group_filter( mo ); 2116 } 2117 2118 if ( BER_BVISNULL( &mo->mo_memberFilterstr ) ) { 2119 memberof_make_member_filter( mo ); 2120 } 2121 2122 return 0; 2123} 2124 2125static int 2126memberof_db_destroy( 2127 BackendDB *be, 2128 ConfigReply *cr ) 2129{ 2130 slap_overinst *on = (slap_overinst *)be->bd_info; 2131 memberof_t *mo = (memberof_t *)on->on_bi.bi_private; 2132 2133 if ( mo ) { 2134 if ( !BER_BVISNULL( &mo->mo_dn ) ) { 2135 ber_memfree( mo->mo_dn.bv_val ); 2136 ber_memfree( mo->mo_ndn.bv_val ); 2137 } 2138 2139 if ( !BER_BVISNULL( &mo->mo_groupFilterstr ) ) { 2140 ber_memfree( mo->mo_groupFilterstr.bv_val ); 2141 } 2142 2143 if ( !BER_BVISNULL( &mo->mo_memberFilterstr ) ) { 2144 ber_memfree( mo->mo_memberFilterstr.bv_val ); 2145 } 2146 2147 ber_memfree( mo ); 2148 } 2149 2150 return 0; 2151} 2152 2153static struct { 2154 char *desc; 2155 AttributeDescription **adp; 2156} as[] = { 2157 { "( 1.2.840.113556.1.2.102 " 2158 "NAME 'memberOf' " 2159 "DESC 'Group that the entry belongs to' " 2160 "SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' " 2161 "EQUALITY distinguishedNameMatch " /* added */ 2162 "USAGE dSAOperation " /* added; questioned */ 2163 "NO-USER-MODIFICATION " /* added */ 2164 "X-ORIGIN 'iPlanet Delegated Administrator' )", 2165 &ad_memberOf }, 2166 { NULL } 2167}; 2168 2169#if SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC 2170static 2171#endif /* SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC */ 2172int 2173memberof_initialize( void ) 2174{ 2175 int code, i; 2176 2177 for ( i = 0; as[ i ].desc != NULL; i++ ) { 2178 code = register_at( as[ i ].desc, as[ i ].adp, 1 ); 2179 if ( code && code != SLAP_SCHERR_ATTR_DUP ) { 2180 Debug( LDAP_DEBUG_ANY, 2181 "memberof_initialize: register_at #%d failed\n", 2182 i ); 2183 return code; 2184 } 2185 } 2186 2187 memberof.on_bi.bi_type = "memberof"; 2188 2189 memberof.on_bi.bi_db_init = memberof_db_init; 2190 memberof.on_bi.bi_db_open = memberof_db_open; 2191 memberof.on_bi.bi_db_destroy = memberof_db_destroy; 2192 2193 memberof.on_bi.bi_op_add = memberof_op_add; 2194 memberof.on_bi.bi_op_delete = memberof_op_delete; 2195 memberof.on_bi.bi_op_modify = memberof_op_modify; 2196 memberof.on_bi.bi_op_modrdn = memberof_op_modrdn; 2197 2198 memberof.on_bi.bi_cf_ocs = mo_ocs; 2199 2200 code = config_register_schema( mo_cfg, mo_ocs ); 2201 if ( code ) return code; 2202 2203 return overlay_register( &memberof ); 2204} 2205 2206#if SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC 2207int 2208init_module( int argc, char *argv[] ) 2209{ 2210 return memberof_initialize(); 2211} 2212#endif /* SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC */ 2213 2214#endif /* SLAPD_OVER_MEMBEROF */ 2215