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