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