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