X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Foverlays%2Fmemberof.c;h=502cb46fc1bd4f8037fe32dd158d21b4437bf918;hb=f1ad87e649ec7b80f6a2561eee9a222e79feaeb8;hp=48b7f1a2363d4665f6dad5be2f5c152b99300a7c;hpb=4f44b77ea5b6d63259fe34b872da8832046761f3;p=openldap diff --git a/servers/slapd/overlays/memberof.c b/servers/slapd/overlays/memberof.c index 48b7f1a236..502cb46fc1 100644 --- a/servers/slapd/overlays/memberof.c +++ b/servers/slapd/overlays/memberof.c @@ -155,6 +155,8 @@ typedef struct memberof_t { #define MEMBEROF_FREFINT 0x04U #define MEMBEROF_FREVERSE 0x08U + ber_int_t mo_dangling_err; + #define MEMBEROF_CHK(mo,f) \ (((mo)->mo_flags & (f)) == (f)) #define MEMBEROF_DANGLING_CHECK(mo) \ @@ -176,71 +178,19 @@ typedef enum memberof_is_t { MEMBEROF_IS_BOTH = (MEMBEROF_IS_GROUP|MEMBEROF_IS_MEMBER) } memberof_is_t; -/* - * failover storage for member attribute values of groups being deleted - * handles [no]thread cases. - */ -static BerVarray saved_member_vals; -static BerVarray saved_memberof_vals; - -static void -memberof_saved_member_free( void *key, void *data ) -{ - ber_bvarray_free( (BerVarray)data ); -} - -static BerVarray -memberof_saved_member_get( Operation *op, void *keyp ) -{ - BerVarray vals; - BerVarray *key = (BerVarray *)keyp; - - assert( op ); - - if ( op->o_threadctx == NULL ) { - vals = *key; - *key = NULL; - - } else { - ldap_pvt_thread_pool_getkey( op->o_threadctx, - key, (void **)&vals, NULL ); - ldap_pvt_thread_pool_setkey( op->o_threadctx, - key, NULL, NULL ); - } - - return vals; -} - -static void -memberof_saved_member_set( Operation *op, void *keyp, BerVarray vals ) -{ - BerVarray saved_vals = NULL; - BerVarray *key = (BerVarray*)keyp; - - assert( op ); - - if ( vals ) { - ber_bvarray_dup_x( &saved_vals, vals, NULL ); - } - - if ( op->o_threadctx == NULL ) { - if ( *key ) { - ber_bvarray_free( *key ); - } - *key = saved_vals; - - } else { - ldap_pvt_thread_pool_setkey( op->o_threadctx, key, - saved_vals, memberof_saved_member_free ); - } -} - typedef struct memberof_cookie_t { AttributeDescription *ad; - void *key; + BerVarray vals; int foundit; } memberof_cookie_t; +typedef struct memberof_cbinfo_t { + slap_overinst *on; + BerVarray member; + BerVarray memberof; + memberof_is_t what; +} memberof_cbinfo_t; + static int memberof_isGroupOrMember_cb( Operation *op, SlapReply *rs ) { @@ -268,23 +218,14 @@ memberof_saveMember_cb( Operation *op, SlapReply *rs ) mc = (memberof_cookie_t *)op->o_callback->sc_private; mc->foundit = 1; - assert( rs->sr_entry ); - assert( rs->sr_entry->e_attrs ); + assert( rs->sr_entry != NULL ); + assert( rs->sr_entry->e_attrs != NULL ); a = attr_find( rs->sr_entry->e_attrs, mc->ad ); + if ( a != NULL ) { + ber_bvarray_dup_x( &mc->vals, a->a_nvals, op->o_tmpmemctx ); - assert( a != NULL ); - - memberof_saved_member_set( op, mc->key, a->a_nvals ); - - if ( attr_find( a->a_next, mc->ad ) != NULL ) { - Debug( LDAP_DEBUG_ANY, - "%s: memberof_saveMember_cb(\"%s\"): " - "more than one occurrence of \"%s\" " - "attribute.\n", - op->o_log_prefix, - rs->sr_entry->e_name.bv_val, - mc->ad->ad_cname.bv_val ); + assert( attr_find( a->a_next, mc->ad ) == NULL ); } } @@ -296,21 +237,20 @@ memberof_saveMember_cb( Operation *op, SlapReply *rs ) * attribute values of groups being deleted. */ static int -memberof_isGroupOrMember( Operation *op, memberof_is_t *iswhatp ) +memberof_isGroupOrMember( Operation *op, memberof_cbinfo_t *mci ) { - slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + slap_overinst *on = mci->on; memberof_t *mo = (memberof_t *)on->on_bi.bi_private; Operation op2 = *op; - SlapReply rs2 = { REP_RESULT }; slap_callback cb = { 0 }; - memberof_cookie_t mc; + BackendInfo *bi = op->o_bd->bd_info; AttributeName an[ 2 ]; memberof_is_t iswhat = MEMBEROF_IS_NONE; + memberof_cookie_t mc; - assert( iswhatp != NULL ); - assert( *iswhatp != MEMBEROF_IS_NONE ); + assert( mci->what != MEMBEROF_IS_NONE ); cb.sc_private = &mc; if ( op->o_tag == LDAP_REQ_DELETE ) { @@ -334,10 +274,12 @@ memberof_isGroupOrMember( Operation *op, memberof_is_t *iswhatp ) op2.ors_slimit = 1; op2.ors_tlimit = SLAP_NO_LIMIT; - if ( *iswhatp & MEMBEROF_IS_GROUP ) { + if ( mci->what & MEMBEROF_IS_GROUP ) { + SlapReply rs2 = { REP_RESULT }; + mc.ad = mo->mo_ad_member; - mc.key = &saved_member_vals; mc.foundit = 0; + mc.vals = NULL; an[ 0 ].an_desc = mo->mo_ad_member; an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname; op2.ors_filterstr = mo->mo_groupFilterstr; @@ -345,20 +287,21 @@ memberof_isGroupOrMember( Operation *op, memberof_is_t *iswhatp ) op2.o_bd->bd_info = (BackendInfo *)on->on_info; (void)op->o_bd->be_search( &op2, &rs2 ); - op2.o_bd->bd_info = (BackendInfo *)on; + op2.o_bd->bd_info = bi; if ( mc.foundit ) { iswhat |= MEMBEROF_IS_GROUP; + if ( mc.vals ) mci->member = mc.vals; - } else { - memberof_saved_member_set( op, mc.key, NULL ); } } - if ( *iswhatp & MEMBEROF_IS_MEMBER ) { + if ( mci->what & MEMBEROF_IS_MEMBER ) { + SlapReply rs2 = { REP_RESULT }; + mc.ad = mo->mo_ad_memberof; - mc.key = &saved_memberof_vals; mc.foundit = 0; + mc.vals = NULL; an[ 0 ].an_desc = mo->mo_ad_memberof; an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname; op2.ors_filterstr = mo->mo_memberFilterstr; @@ -366,17 +309,16 @@ memberof_isGroupOrMember( Operation *op, memberof_is_t *iswhatp ) op2.o_bd->bd_info = (BackendInfo *)on->on_info; (void)op->o_bd->be_search( &op2, &rs2 ); - op2.o_bd->bd_info = (BackendInfo *)on; + op2.o_bd->bd_info = bi; if ( mc.foundit ) { iswhat |= MEMBEROF_IS_MEMBER; + if ( mc.vals ) mci->memberof = mc.vals; - } else { - memberof_saved_member_set( op, mc.key, NULL ); } } - *iswhatp = iswhat; + mci->what = iswhat; return LDAP_SUCCESS; } @@ -384,10 +326,9 @@ memberof_isGroupOrMember( Operation *op, memberof_is_t *iswhatp ) /* * response callback that adds memberof values when a group is modified. */ -static int +static void memberof_value_modify( Operation *op, - SlapReply *rs, struct berval *ndn, AttributeDescription *ad, struct berval *old_dn, @@ -395,7 +336,8 @@ memberof_value_modify( struct berval *new_dn, struct berval *new_ndn ) { - slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_cbinfo_t *mci = op->o_callback->sc_private; + slap_overinst *on = mci->on; memberof_t *mo = (memberof_t *)on->on_bi.bi_private; Operation op2 = *op; @@ -403,33 +345,43 @@ memberof_value_modify( slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; Modifications mod[ 2 ] = { { { 0 } } }, *ml; struct berval values[ 4 ], nvalues[ 4 ]; + int mcnt = 0; op2.o_tag = LDAP_REQ_MODIFY; op2.o_req_dn = *ndn; op2.o_req_ndn = *ndn; - op2.o_bd->bd_info = (BackendInfo *)on->on_info; - op2.o_callback = &cb; op2.o_dn = op->o_bd->be_rootdn; op2.o_ndn = op->o_bd->be_rootndn; + op2.orm_modlist = NULL; + + /* Internal ops, never replicate these */ + op2.orm_no_opattrs = 1; + op2.o_dont_replicate = 1; + + if ( !BER_BVISNULL( &mo->mo_ndn ) ) { + ml = &mod[ mcnt ]; + ml->sml_numvals = 1; + ml->sml_values = &values[ 0 ]; + ml->sml_values[ 0 ] = mo->mo_dn; + BER_BVZERO( &ml->sml_values[ 1 ] ); + ml->sml_nvalues = &nvalues[ 0 ]; + ml->sml_nvalues[ 0 ] = mo->mo_ndn; + BER_BVZERO( &ml->sml_nvalues[ 1 ] ); + ml->sml_desc = slap_schema.si_ad_modifiersName; + ml->sml_type = ml->sml_desc->ad_cname; + ml->sml_op = LDAP_MOD_REPLACE; + ml->sml_flags = SLAP_MOD_INTERNAL; + ml->sml_next = op2.orm_modlist; + op2.orm_modlist = ml; + + mcnt++; + } - ml = &mod[ 0 ]; - ml->sml_values = &values[ 0 ]; - ml->sml_values[ 0 ] = mo->mo_dn; - BER_BVZERO( &ml->sml_values[ 1 ] ); - ml->sml_nvalues = &nvalues[ 0 ]; - ml->sml_nvalues[ 0 ] = mo->mo_ndn; - BER_BVZERO( &ml->sml_nvalues[ 1 ] ); - ml->sml_desc = slap_schema.si_ad_modifiersName; - ml->sml_type = ml->sml_desc->ad_cname; - ml->sml_op = LDAP_MOD_REPLACE; - ml->sml_flags = SLAP_MOD_INTERNAL; - ml->sml_next = NULL; - op2.orm_modlist = ml; - - ml = &mod[ 1 ]; + ml = &mod[ mcnt ]; + ml->sml_numvals = 1; ml->sml_values = &values[ 2 ]; BER_BVZERO( &ml->sml_values[ 1 ] ); ml->sml_nvalues = &nvalues[ 2 ]; @@ -437,44 +389,85 @@ memberof_value_modify( ml->sml_desc = ad; ml->sml_type = ml->sml_desc->ad_cname; ml->sml_flags = SLAP_MOD_INTERNAL; - ml->sml_next = NULL; - op2.orm_modlist->sml_next = ml; + ml->sml_next = op2.orm_modlist; + op2.orm_modlist = ml; if ( new_ndn != NULL ) { + BackendInfo *bi = op2.o_bd->bd_info; + OpExtra oex; + assert( !BER_BVISNULL( new_dn ) ); assert( !BER_BVISNULL( new_ndn ) ); - ml = &mod[ 1 ]; + ml = &mod[ mcnt ]; ml->sml_op = LDAP_MOD_ADD; ml->sml_values[ 0 ] = *new_dn; ml->sml_nvalues[ 0 ] = *new_ndn; + oex.oe_key = (void *)&memberof; + LDAP_SLIST_INSERT_HEAD(&op2.o_extra, &oex, oe_next); + op2.o_bd->bd_info = (BackendInfo *)on->on_info; (void)op->o_bd->be_modify( &op2, &rs2 ); + op2.o_bd->bd_info = bi; + LDAP_SLIST_REMOVE(&op2.o_extra, &oex, OpExtra, oe_next); + if ( rs2.sr_err != LDAP_SUCCESS ) { + char buf[ SLAP_TEXT_BUFLEN ]; + snprintf( buf, sizeof( buf ), + "memberof_value_modify DN=\"%s\" add %s=\"%s\" failed err=%d", + op2.o_req_dn.bv_val, ad->ad_cname.bv_val, new_dn->bv_val, rs2.sr_err ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", + op->o_log_prefix, buf, 0 ); + } - assert( op2.orm_modlist == &mod[ 0 ] ); - assert( op2.orm_modlist->sml_next == &mod[ 1 ] ); - ml = op2.orm_modlist->sml_next->sml_next; + assert( op2.orm_modlist == &mod[ mcnt ] ); + assert( mcnt == 0 || op2.orm_modlist->sml_next == &mod[ 0 ] ); + ml = op2.orm_modlist->sml_next; + if ( mcnt == 1 ) { + assert( ml == &mod[ 0 ] ); + ml = ml->sml_next; + } if ( ml != NULL ) { slap_mods_free( ml, 1 ); } + + mod[ 0 ].sml_next = NULL; } if ( old_ndn != NULL ) { + BackendInfo *bi = op2.o_bd->bd_info; + OpExtra oex; + assert( !BER_BVISNULL( old_dn ) ); assert( !BER_BVISNULL( old_ndn ) ); - ml = &mod[ 1 ]; + ml = &mod[ mcnt ]; ml->sml_op = LDAP_MOD_DELETE; ml->sml_values[ 0 ] = *old_dn; ml->sml_nvalues[ 0 ] = *old_ndn; + oex.oe_key = (void *)&memberof; + LDAP_SLIST_INSERT_HEAD(&op2.o_extra, &oex, oe_next); + op2.o_bd->bd_info = (BackendInfo *)on->on_info; (void)op->o_bd->be_modify( &op2, &rs2 ); + op2.o_bd->bd_info = bi; + LDAP_SLIST_REMOVE(&op2.o_extra, &oex, OpExtra, oe_next); + if ( rs2.sr_err != LDAP_SUCCESS ) { + char buf[ SLAP_TEXT_BUFLEN ]; + snprintf( buf, sizeof( buf ), + "memberof_value_modify DN=\"%s\" delete %s=\"%s\" failed err=%d", + op2.o_req_dn.bv_val, ad->ad_cname.bv_val, old_dn->bv_val, rs2.sr_err ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", + op->o_log_prefix, buf, 0 ); + } - assert( op2.orm_modlist == &mod[ 0 ] ); - assert( op2.orm_modlist->sml_next == &mod[ 1 ] ); - ml = op2.orm_modlist->sml_next->sml_next; + assert( op2.orm_modlist == &mod[ mcnt ] ); + ml = op2.orm_modlist->sml_next; + if ( mcnt == 1 ) { + assert( ml == &mod[ 0 ] ); + ml = ml->sml_next; + } if ( ml != NULL ) { slap_mods_free( ml, 1 ); } @@ -484,12 +477,28 @@ memberof_value_modify( * add will fail; better split in two operations, although * not optimal in terms of performance. At least it would * move towards self-repairing capabilities. */ +} - op2.o_bd->bd_info = (BackendInfo *)on; - - return rs2.sr_err; +static int +memberof_cleanup( Operation *op, SlapReply *rs ) +{ + slap_callback *sc = op->o_callback; + memberof_cbinfo_t *mci = sc->sc_private; + + op->o_callback = sc->sc_next; + if ( mci->memberof ) + ber_bvarray_free_x( mci->memberof, op->o_tmpmemctx ); + if ( mci->member ) + ber_bvarray_free_x( mci->member, op->o_tmpmemctx ); + op->o_tmpfree( sc, op->o_tmpmemctx ); + return 0; } +static int memberof_res_add( Operation *op, SlapReply *rs ); +static int memberof_res_delete( Operation *op, SlapReply *rs ); +static int memberof_res_modify( Operation *op, SlapReply *rs ); +static int memberof_res_modrdn( Operation *op, SlapReply *rs ); + static int memberof_op_add( Operation *op, SlapReply *rs ) { @@ -500,6 +509,14 @@ memberof_op_add( Operation *op, SlapReply *rs ) int rc = SLAP_CB_CONTINUE; int i; struct berval save_dn, save_ndn; + slap_callback *sc; + memberof_cbinfo_t *mci; + OpExtra *oex; + + LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { + if ( oex->oe_key == (void *)&memberof ) + return SLAP_CB_CONTINUE; + } if ( op->ora_e->e_attrs == NULL ) { /* FIXME: global overlay; need to deal with */ @@ -526,10 +543,10 @@ memberof_op_add( Operation *op, SlapReply *rs ) if ( MEMBEROF_DANGLING_CHECK( mo ) && !get_relax( op ) - && is_entry_objectclass( op->ora_e, mo->mo_oc_group, 0 ) ) + && is_entry_objectclass_or_sub( op->ora_e, mo->mo_oc_group ) ) { op->o_dn = op->o_bd->be_rootdn; - op->o_dn = op->o_bd->be_rootndn; + op->o_ndn = op->o_bd->be_rootndn; op->o_bd->bd_info = (BackendInfo *)on->on_info; for ( ap = &op->ora_e->e_attrs; *ap; ) { @@ -543,11 +560,11 @@ memberof_op_add( Operation *op, SlapReply *rs ) assert( a->a_nvals != NULL ); for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { - Entry *e; + Entry *e = NULL; - /* FIXME: entry_get_rw does not pass - * thru overlays yet; when it does, we - * might need to make a copy of the DN */ + /* ITS#6670 Ignore member pointing to this entry */ + if ( dn_match( &a->a_nvals[i], &save_ndn )) + continue; rc = be_entry_get_rw( op, &a->a_nvals[ i ], NULL, NULL, 0, &e ); @@ -557,7 +574,7 @@ memberof_op_add( Operation *op, SlapReply *rs ) } if ( MEMBEROF_DANGLING_ERROR( mo ) ) { - rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; + rc = rs->sr_err = mo->mo_dangling_err; rs->sr_text = "adding non-existing object " "as group member"; send_ldap_result( op, rs ); @@ -590,6 +607,7 @@ memberof_op_add( Operation *op, SlapReply *rs ) sizeof( struct berval ) * ( j - i ) ); } i--; + a->a_numvals--; } } @@ -626,6 +644,10 @@ memberof_op_add( Operation *op, SlapReply *rs ) send_ldap_result( op, rs ); goto done; } + /* ITS#6670 Ignore member pointing to this entry */ + if ( dn_match( &a->a_nvals[i], &save_ndn )) + continue; + rc = be_entry_get_rw( op, &a->a_nvals[ i ], NULL, NULL, 0, &e ); op->o_bd->bd_info = (BackendInfo *)on; @@ -635,7 +657,7 @@ memberof_op_add( Operation *op, SlapReply *rs ) } if ( MEMBEROF_DANGLING_ERROR( mo ) ) { - rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; + rc = rs->sr_err = mo->mo_dangling_err; rs->sr_text = "adding non-existing object " "as memberof"; send_ldap_result( op, rs ); @@ -695,7 +717,18 @@ memberof_op_add( Operation *op, SlapReply *rs ) } rc = SLAP_CB_CONTINUE; - + + sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx ); + sc->sc_private = sc+1; + sc->sc_response = memberof_res_add; + sc->sc_cleanup = memberof_cleanup; + mci = sc->sc_private; + mci->on = on; + mci->member = NULL; + mci->memberof = NULL; + sc->sc_next = op->o_callback; + op->o_callback = sc; + done:; op->o_dn = save_dn; op->o_ndn = save_ndn; @@ -710,13 +743,32 @@ memberof_op_delete( Operation *op, SlapReply *rs ) slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; memberof_t *mo = (memberof_t *)on->on_bi.bi_private; - memberof_is_t iswhat = MEMBEROF_IS_GROUP; + slap_callback *sc; + memberof_cbinfo_t *mci; + OpExtra *oex; + LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { + if ( oex->oe_key == (void *)&memberof ) + return SLAP_CB_CONTINUE; + } + + sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx ); + sc->sc_private = sc+1; + sc->sc_response = memberof_res_delete; + sc->sc_cleanup = memberof_cleanup; + mci = sc->sc_private; + mci->on = on; + mci->member = NULL; + mci->memberof = NULL; + mci->what = MEMBEROF_IS_GROUP; if ( MEMBEROF_REFINT( mo ) ) { - iswhat = MEMBEROF_IS_BOTH; + mci->what = MEMBEROF_IS_BOTH; } - memberof_isGroupOrMember( op, &iswhat ); + memberof_isGroupOrMember( op, mci ); + + sc->sc_next = op->o_callback; + op->o_callback = sc; return SLAP_CB_CONTINUE; } @@ -728,9 +780,16 @@ memberof_op_modify( Operation *op, SlapReply *rs ) memberof_t *mo = (memberof_t *)on->on_bi.bi_private; Modifications **mlp, **mmlp = NULL; - int rc = SLAP_CB_CONTINUE; + int rc = SLAP_CB_CONTINUE, save_member = 0; struct berval save_dn, save_ndn; - memberof_is_t iswhat = MEMBEROF_IS_GROUP; + slap_callback *sc; + memberof_cbinfo_t *mci, mcis; + OpExtra *oex; + + LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { + if ( oex->oe_key == (void *)&memberof ) + return SLAP_CB_CONTINUE; + } if ( MEMBEROF_REVERSE( mo ) ) { for ( mlp = &op->orm_modlist; *mlp; mlp = &(*mlp)->sml_next ) { @@ -745,102 +804,131 @@ memberof_op_modify( Operation *op, SlapReply *rs ) save_dn = op->o_dn; save_ndn = op->o_ndn; + mcis.on = on; + mcis.what = MEMBEROF_IS_GROUP; - if ( MEMBEROF_DANGLING_CHECK( mo ) - && !get_relax( op ) - && memberof_isGroupOrMember( op, &iswhat ) == LDAP_SUCCESS - && ( iswhat & MEMBEROF_IS_GROUP ) ) + if ( memberof_isGroupOrMember( op, &mcis ) == LDAP_SUCCESS + && ( mcis.what & MEMBEROF_IS_GROUP ) ) { - op->o_dn = op->o_bd->be_rootdn; - op->o_dn = op->o_bd->be_rootndn; - op->o_bd->bd_info = (BackendInfo *)on->on_info; - - assert( op->orm_modlist != NULL ); - - for ( mlp = &op->orm_modlist; *mlp; ) { - Modifications *ml = *mlp; - int i; - - if ( !is_ad_subtype( ml->sml_desc, mo->mo_ad_member ) ) { - mlp = &ml->sml_next; - continue; + Modifications *ml; + + for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { + if ( ml->sml_desc == mo->mo_ad_member ) { + switch ( ml->sml_op ) { + case LDAP_MOD_DELETE: + case LDAP_MOD_REPLACE: + save_member = 1; + break; + } } - - switch ( ml->sml_op ) { - case LDAP_MOD_DELETE: - /* we don't care about cancellations: if the value - * exists, fine; if it doesn't, we let the underlying - * database fail as appropriate; */ - mlp = &ml->sml_next; - break; - - case LDAP_MOD_REPLACE: - case LDAP_MOD_ADD: - /* NOTE: right now, the attributeType we use - * for member must have a normalized value */ - assert( ml->sml_nvalues ); - - for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) { - int rc; - Entry *e; - - if ( be_entry_get_rw( op, &ml->sml_nvalues[ i ], - NULL, NULL, 0, &e ) == LDAP_SUCCESS ) - { - be_entry_release_r( op, e ); - continue; - } - - if ( MEMBEROF_DANGLING_ERROR( mo ) ) { - rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; - rs->sr_text = "adding non-existing object " - "as group member"; - send_ldap_result( op, rs ); - goto done; - } - - if ( MEMBEROF_DANGLING_DROP( mo ) ) { - int j; - - Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): " - "member=\"%s\" does not exist (stripping...)\n", - op->o_log_prefix, op->o_req_dn.bv_val, - ml->sml_nvalues[ i ].bv_val ); - - for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ ); - ber_memfree( ml->sml_values[ i ].bv_val ); - BER_BVZERO( &ml->sml_values[ i ] ); - ber_memfree( ml->sml_nvalues[ i ].bv_val ); - BER_BVZERO( &ml->sml_nvalues[ i ] ); - if ( j - i == 1 ) { - break; - } - - AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ], - sizeof( struct berval ) * ( j - i ) ); - AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ], - sizeof( struct berval ) * ( j - i ) ); - i--; - } + } + + + if ( MEMBEROF_DANGLING_CHECK( mo ) + && !get_relax( op ) ) + { + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + op->o_bd->bd_info = (BackendInfo *)on->on_info; + + assert( op->orm_modlist != NULL ); + + for ( mlp = &op->orm_modlist; *mlp; ) { + Modifications *ml = *mlp; + int i; + + if ( !is_ad_subtype( ml->sml_desc, mo->mo_ad_member ) ) { + mlp = &ml->sml_next; + continue; } - - if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) { - *mlp = ml->sml_next; - slap_mod_free( &ml->sml_mod, 0 ); - free( ml ); - - } else { + + switch ( ml->sml_op ) { + case LDAP_MOD_DELETE: + /* we don't care about cancellations: if the value + * exists, fine; if it doesn't, we let the underlying + * database fail as appropriate; */ mlp = &ml->sml_next; + break; + + case LDAP_MOD_REPLACE: + /* Handle this just like a delete (see above) */ + if ( !ml->sml_values ) { + mlp = &ml->sml_next; + break; + } + + case LDAP_MOD_ADD: + /* NOTE: right now, the attributeType we use + * for member must have a normalized value */ + assert( ml->sml_nvalues != NULL ); + + for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) { + int rc; + Entry *e; + + /* ITS#6670 Ignore member pointing to this entry */ + if ( dn_match( &ml->sml_nvalues[i], &save_ndn )) + continue; + + if ( be_entry_get_rw( op, &ml->sml_nvalues[ i ], + NULL, NULL, 0, &e ) == LDAP_SUCCESS ) + { + be_entry_release_r( op, e ); + continue; + } + + if ( MEMBEROF_DANGLING_ERROR( mo ) ) { + rc = rs->sr_err = mo->mo_dangling_err; + rs->sr_text = "adding non-existing object " + "as group member"; + send_ldap_result( op, rs ); + goto done; + } + + if ( MEMBEROF_DANGLING_DROP( mo ) ) { + int j; + + Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): " + "member=\"%s\" does not exist (stripping...)\n", + op->o_log_prefix, op->o_req_dn.bv_val, + ml->sml_nvalues[ i ].bv_val ); + + for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ ); + ber_memfree( ml->sml_values[ i ].bv_val ); + BER_BVZERO( &ml->sml_values[ i ] ); + ber_memfree( ml->sml_nvalues[ i ].bv_val ); + BER_BVZERO( &ml->sml_nvalues[ i ] ); + ml->sml_numvals--; + if ( j - i == 1 ) { + break; + } + + AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + i--; + } + } + + if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) { + *mlp = ml->sml_next; + slap_mod_free( &ml->sml_mod, 0 ); + free( ml ); + + } else { + mlp = &ml->sml_next; + } + + break; + + default: + assert( 0 ); } - - break; - - default: - assert( 0 ); } } } - + if ( mmlp != NULL ) { Modifications *ml = *mmlp; int i; @@ -887,7 +975,7 @@ memberof_op_modify( Operation *op, SlapReply *rs ) } if ( MEMBEROF_DANGLING_ERROR( mo ) ) { - rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; + rc = rs->sr_err = mo->mo_dangling_err; rs->sr_text = "deleting non-existing object " "as memberof"; send_ldap_result( op, rs ); @@ -909,6 +997,7 @@ memberof_op_modify( Operation *op, SlapReply *rs ) ber_memfree( ml->sml_nvalues[ i ].bv_val ); BER_BVZERO( &ml->sml_nvalues[ i ] ); } + ml->sml_numvals--; if ( j - i == 1 ) { break; } @@ -967,7 +1056,7 @@ memberof_op_modify( Operation *op, SlapReply *rs ) goto done2; } - if ( ml->sml_op == LDAP_MOD_DELETE ) { + if ( ml->sml_op == LDAP_MOD_DELETE || !ml->sml_values ) { break; } /* fall thru */ @@ -992,12 +1081,16 @@ memberof_op_modify( Operation *op, SlapReply *rs ) goto done2; } + /* ITS#6670 Ignore member pointing to this entry */ + if ( dn_match( &ml->sml_nvalues[i], &save_ndn )) + continue; + rc = be_entry_get_rw( op, &ml->sml_nvalues[ i ], NULL, NULL, 0, &e ); op->o_bd->bd_info = (BackendInfo *)on; if ( rc != LDAP_SUCCESS ) { if ( MEMBEROF_DANGLING_ERROR( mo ) ) { - rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; + rc = rs->sr_err = mo->mo_dangling_err; rs->sr_text = "adding non-existing object " "as memberof"; send_ldap_result( op, rs ); @@ -1019,6 +1112,7 @@ memberof_op_modify( Operation *op, SlapReply *rs ) ber_memfree( ml->sml_nvalues[ i ].bv_val ); BER_BVZERO( &ml->sml_nvalues[ i ] ); } + ml->sml_numvals--; if ( j - i == 1 ) { break; } @@ -1069,6 +1163,28 @@ done2:; op->o_bd->bd_info = (BackendInfo *)on; } + sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx ); + sc->sc_private = sc+1; + sc->sc_response = memberof_res_modify; + sc->sc_cleanup = memberof_cleanup; + mci = sc->sc_private; + mci->on = on; + mci->member = NULL; + mci->memberof = NULL; + mci->what = mcis.what; + + if ( save_member ) { + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rc = backend_attribute( op, NULL, &op->o_req_ndn, + mo->mo_ad_member, &mci->member, ACL_READ ); + op->o_bd->bd_info = (BackendInfo *)on; + } + + sc->sc_next = op->o_callback; + op->o_callback = sc; + rc = SLAP_CB_CONTINUE; done:; @@ -1079,41 +1195,75 @@ done:; return rc; } +static int +memberof_op_modrdn( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + slap_callback *sc; + memberof_cbinfo_t *mci; + OpExtra *oex; + + LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { + if ( oex->oe_key == (void *)&memberof ) + return SLAP_CB_CONTINUE; + } + + sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx ); + sc->sc_private = sc+1; + sc->sc_response = memberof_res_modrdn; + sc->sc_cleanup = memberof_cleanup; + mci = sc->sc_private; + mci->on = on; + mci->member = NULL; + mci->memberof = NULL; + + sc->sc_next = op->o_callback; + op->o_callback = sc; + + return SLAP_CB_CONTINUE; +} + /* * response callback that adds memberof values when a group is added. */ static int memberof_res_add( Operation *op, SlapReply *rs ) { - slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_cbinfo_t *mci = op->o_callback->sc_private; + slap_overinst *on = mci->on; memberof_t *mo = (memberof_t *)on->on_bi.bi_private; int i; + if ( rs->sr_err != LDAP_SUCCESS ) { + return SLAP_CB_CONTINUE; + } + if ( MEMBEROF_REVERSE( mo ) ) { Attribute *ma; ma = attr_find( op->ora_e->e_attrs, mo->mo_ad_memberof ); if ( ma != NULL ) { - Operation op2 = *op; - SlapReply rs2 = { 0 }; - /* relax is required to allow to add * a non-existing member */ - op2.o_relax = SLAP_CONTROL_CRITICAL; + op->o_relax = SLAP_CONTROL_CRITICAL; for ( i = 0; !BER_BVISNULL( &ma->a_nvals[ i ] ); i++ ) { + /* ITS#6670 Ignore member pointing to this entry */ + if ( dn_match( &ma->a_nvals[i], &op->o_req_ndn )) + continue; + /* the modification is attempted * with the original identity */ - (void)memberof_value_modify( &op2, &rs2, + memberof_value_modify( op, &ma->a_nvals[ i ], mo->mo_ad_member, NULL, NULL, &op->o_req_dn, &op->o_req_ndn ); } } } - if ( is_entry_objectclass( op->ora_e, mo->mo_oc_group, 0 ) ) { + if ( is_entry_objectclass_or_sub( op->ora_e, mo->mo_oc_group ) ) { Attribute *a; for ( a = attrs_find( op->ora_e->e_attrs, mo->mo_ad_member ); @@ -1121,7 +1271,11 @@ memberof_res_add( Operation *op, SlapReply *rs ) a = attrs_find( a->a_next, mo->mo_ad_member ) ) { for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { - (void)memberof_value_modify( op, rs, + /* ITS#6670 Ignore member pointing to this entry */ + if ( dn_match( &a->a_nvals[i], &op->o_req_ndn )) + continue; + + memberof_value_modify( op, &a->a_nvals[ i ], mo->mo_ad_memberof, NULL, NULL, @@ -1140,35 +1294,36 @@ memberof_res_add( Operation *op, SlapReply *rs ) static int memberof_res_delete( Operation *op, SlapReply *rs ) { - slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_cbinfo_t *mci = op->o_callback->sc_private; + slap_overinst *on = mci->on; memberof_t *mo = (memberof_t *)on->on_bi.bi_private; BerVarray vals; int i; - vals = memberof_saved_member_get( op, &saved_member_vals ); + if ( rs->sr_err != LDAP_SUCCESS ) { + return SLAP_CB_CONTINUE; + } + + vals = mci->member; if ( vals != NULL ) { for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { - (void)memberof_value_modify( op, rs, + memberof_value_modify( op, &vals[ i ], mo->mo_ad_memberof, &op->o_req_dn, &op->o_req_ndn, NULL, NULL ); } - - ber_bvarray_free( vals ); } if ( MEMBEROF_REFINT( mo ) ) { - vals = memberof_saved_member_get( op, &saved_memberof_vals ); + vals = mci->memberof; if ( vals != NULL ) { for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { - (void)memberof_value_modify( op, rs, + memberof_value_modify( op, &vals[ i ], mo->mo_ad_member, &op->o_req_dn, &op->o_req_ndn, NULL, NULL ); } - - ber_bvarray_free( vals ); } } @@ -1182,13 +1337,17 @@ memberof_res_delete( Operation *op, SlapReply *rs ) static int memberof_res_modify( Operation *op, SlapReply *rs ) { - slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_cbinfo_t *mci = op->o_callback->sc_private; + slap_overinst *on = mci->on; memberof_t *mo = (memberof_t *)on->on_bi.bi_private; int i, rc; Modifications *ml, *mml = NULL; BerVarray vals; - memberof_is_t iswhat = MEMBEROF_IS_GROUP; + + if ( rs->sr_err != LDAP_SUCCESS ) { + return SLAP_CB_CONTINUE; + } if ( MEMBEROF_REVERSE( mo ) ) { for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { @@ -1206,7 +1365,7 @@ memberof_res_modify( Operation *op, SlapReply *rs ) case LDAP_MOD_DELETE: if ( vals != NULL ) { for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { - memberof_value_modify( op, rs, + memberof_value_modify( op, &vals[ i ], mo->mo_ad_member, &op->o_req_dn, &op->o_req_ndn, NULL, NULL ); @@ -1223,7 +1382,7 @@ memberof_res_modify( Operation *op, SlapReply *rs ) op->o_bd->bd_info = (BackendInfo *)on; if ( rc == LDAP_SUCCESS ) { for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { - (void)memberof_value_modify( op, rs, + memberof_value_modify( op, &vals[ i ], mo->mo_ad_member, &op->o_req_dn, &op->o_req_ndn, NULL, NULL ); @@ -1231,7 +1390,7 @@ memberof_res_modify( Operation *op, SlapReply *rs ) ber_bvarray_free_x( vals, op->o_tmpmemctx ); } - if ( ml->sml_op == LDAP_MOD_DELETE ) { + if ( ml->sml_op == LDAP_MOD_DELETE || !mml->sml_values ) { break; } /* fall thru */ @@ -1240,7 +1399,7 @@ memberof_res_modify( Operation *op, SlapReply *rs ) assert( vals != NULL ); for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { - memberof_value_modify( op, rs, + memberof_value_modify( op, &vals[ i ], mo->mo_ad_member, NULL, NULL, &op->o_req_dn, &op->o_req_ndn ); @@ -1252,8 +1411,7 @@ memberof_res_modify( Operation *op, SlapReply *rs ) } } - if ( memberof_isGroupOrMember( op, &iswhat ) == LDAP_SUCCESS - && ( iswhat & MEMBEROF_IS_GROUP ) ) + if ( mci->what & MEMBEROF_IS_GROUP ) { for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { if ( ml->sml_desc != mo->mo_ad_member ) { @@ -1265,7 +1423,7 @@ memberof_res_modify( Operation *op, SlapReply *rs ) vals = ml->sml_nvalues; if ( vals != NULL ) { for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { - memberof_value_modify( op, rs, + memberof_value_modify( op, &vals[ i ], mo->mo_ad_memberof, &op->o_req_dn, &op->o_req_ndn, NULL, NULL ); @@ -1275,22 +1433,19 @@ memberof_res_modify( Operation *op, SlapReply *rs ) /* fall thru */ case LDAP_MOD_REPLACE: + vals = mci->member; + /* delete all ... */ - op->o_bd->bd_info = (BackendInfo *)on->on_info; - rc = backend_attribute( op, NULL, &op->o_req_ndn, - mo->mo_ad_member, &vals, ACL_READ ); - op->o_bd->bd_info = (BackendInfo *)on; - if ( rc == LDAP_SUCCESS ) { + if ( vals != NULL ) { for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { - (void)memberof_value_modify( op, rs, + memberof_value_modify( op, &vals[ i ], mo->mo_ad_memberof, &op->o_req_dn, &op->o_req_ndn, NULL, NULL ); } - ber_bvarray_free_x( vals, op->o_tmpmemctx ); } - if ( ml->sml_op == LDAP_MOD_DELETE ) { + if ( ml->sml_op == LDAP_MOD_DELETE || !ml->sml_values ) { break; } /* fall thru */ @@ -1299,7 +1454,7 @@ memberof_res_modify( Operation *op, SlapReply *rs ) assert( ml->sml_nvalues != NULL ); vals = ml->sml_nvalues; for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { - memberof_value_modify( op, rs, + memberof_value_modify( op, &vals[ i ], mo->mo_ad_memberof, NULL, NULL, &op->o_req_dn, &op->o_req_ndn ); @@ -1317,12 +1472,13 @@ memberof_res_modify( Operation *op, SlapReply *rs ) /* * response callback that adds/deletes member values when a group member - * is modified. + * is renamed. */ static int -memberof_res_rename( Operation *op, SlapReply *rs ) +memberof_res_modrdn( Operation *op, SlapReply *rs ) { - slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_cbinfo_t *mci = op->o_callback->sc_private; + slap_overinst *on = mci->on; memberof_t *mo = (memberof_t *)on->on_bi.bi_private; struct berval newPDN, newDN = BER_BVNULL, newPNDN, newNDN; @@ -1330,10 +1486,14 @@ memberof_res_rename( Operation *op, SlapReply *rs ) BerVarray vals; struct berval save_dn, save_ndn; - memberof_is_t iswhat = MEMBEROF_IS_GROUP; + if ( rs->sr_err != LDAP_SUCCESS ) { + return SLAP_CB_CONTINUE; + } + + mci->what = MEMBEROF_IS_GROUP; if ( MEMBEROF_REFINT( mo ) ) { - iswhat |= MEMBEROF_IS_MEMBER; + mci->what |= MEMBEROF_IS_MEMBER; } if ( op->orr_nnewSup ) { @@ -1350,11 +1510,11 @@ memberof_res_rename( Operation *op, SlapReply *rs ) op->o_req_dn = newNDN; op->o_req_ndn = newNDN; - rc = memberof_isGroupOrMember( op, &iswhat ); + rc = memberof_isGroupOrMember( op, mci ); op->o_req_dn = save_dn; op->o_req_ndn = save_ndn; - if ( rc != LDAP_SUCCESS || iswhat == MEMBEROF_IS_NONE ) { + if ( rc != LDAP_SUCCESS || mci->what == MEMBEROF_IS_NONE ) { goto done; } @@ -1367,7 +1527,7 @@ memberof_res_rename( Operation *op, SlapReply *rs ) build_new_dn( &newDN, &newPDN, &op->orr_newrdn, op->o_tmpmemctx ); - if ( iswhat & MEMBEROF_IS_GROUP ) { + if ( mci->what & MEMBEROF_IS_GROUP ) { op->o_bd->bd_info = (BackendInfo *)on->on_info; rc = backend_attribute( op, NULL, &newNDN, mo->mo_ad_member, &vals, ACL_READ ); @@ -1375,7 +1535,7 @@ memberof_res_rename( Operation *op, SlapReply *rs ) if ( rc == LDAP_SUCCESS ) { for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { - (void)memberof_value_modify( op, rs, + memberof_value_modify( op, &vals[ i ], mo->mo_ad_memberof, &op->o_req_dn, &op->o_req_ndn, &newDN, &newNDN ); @@ -1384,7 +1544,7 @@ memberof_res_rename( Operation *op, SlapReply *rs ) } } - if ( MEMBEROF_REFINT( mo ) && ( iswhat & MEMBEROF_IS_MEMBER ) ) { + if ( MEMBEROF_REFINT( mo ) && ( mci->what & MEMBEROF_IS_MEMBER ) ) { op->o_bd->bd_info = (BackendInfo *)on->on_info; rc = backend_attribute( op, NULL, &newNDN, mo->mo_ad_memberof, &vals, ACL_READ ); @@ -1392,7 +1552,7 @@ memberof_res_rename( Operation *op, SlapReply *rs ) if ( rc == LDAP_SUCCESS ) { for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { - (void)memberof_value_modify( op, rs, + memberof_value_modify( op, &vals[ i ], mo->mo_ad_member, &op->o_req_dn, &op->o_req_ndn, &newDN, &newNDN ); @@ -1410,30 +1570,6 @@ done:; return SLAP_CB_CONTINUE; } -static int -memberof_response( Operation *op, SlapReply *rs ) -{ - if ( rs->sr_err != LDAP_SUCCESS ) { - return SLAP_CB_CONTINUE; - } - - switch ( op->o_tag ) { - case LDAP_REQ_ADD: - return memberof_res_add( op, rs ); - - case LDAP_REQ_DELETE: - return memberof_res_delete( op, rs ); - - case LDAP_REQ_MODIFY: - return memberof_res_modify( op, rs ); - - case LDAP_REQ_MODDN: - return memberof_res_rename( op, rs ); - - default: - return SLAP_CB_CONTINUE; - } -} static int memberof_db_init( @@ -1441,39 +1577,12 @@ memberof_db_init( ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; - memberof_t *mo; - - int rc; - const char *text = NULL; + memberof_t *mo; mo = (memberof_t *)ch_calloc( 1, sizeof( memberof_t ) ); - rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &mo->mo_ad_memberof, &text ); - if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "memberof_db_init: " - "unable to find attribute=\"%s\": %s (%d)\n", - SLAPD_MEMBEROF_ATTR, text, rc ); - return rc; - } - - rc = slap_str2ad( SLAPD_GROUP_ATTR, &mo->mo_ad_member, &text ); - if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "memberof_db_init: " - "unable to find attribute=\"%s\": %s (%d)\n", - SLAPD_GROUP_ATTR, text, rc ); - return rc; - } - - mo->mo_oc_group = oc_find( SLAPD_GROUP_CLASS ); - if ( mo->mo_oc_group == NULL ) { - Debug( LDAP_DEBUG_ANY, - "memberof_db_init: " - "unable to find objectClass=\"%s\"\n", - SLAPD_GROUP_CLASS, 0, 0 ); - return 1; - } + /* safe default */ + mo->mo_dangling_err = LDAP_CONSTRAINT_VIOLATION; on->on_bi.bi_private = (void *)mo; @@ -1484,12 +1593,16 @@ enum { MO_DN = 1, MO_DANGLING, MO_REFINT, + MO_GROUP_OC, + MO_MEMBER_AD, + MO_MEMBER_OF_AD, #if 0 MO_REVERSE, #endif - MO_GROUP_OC, - MO_MEMBER_AD, - MO_MEMBER_OF_AD + + MO_DANGLING_ERROR, + + MO_LAST }; static ConfigDriver mo_cf_gen; @@ -1555,6 +1668,13 @@ static ConfigTable mo_cfg[] = { NULL, NULL }, #endif + { "memberof-dangling-error", "error code", + 2, 2, 0, ARG_MAGIC|MO_DANGLING_ERROR, mo_cf_gen, + "( OLcfgOvAt:18.7 NAME 'olcMemberOfDanglingError' " + "DESC 'Error code returned in case of dangling back reference' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", + NULL, NULL }, + { NULL, NULL, 0, 0, 0, ARG_IGNORED } }; @@ -1566,6 +1686,7 @@ static ConfigOCs mo_ocs[] = { "MAY ( " "olcMemberOfDN " "$ olcMemberOfDangling " + "$ olcMemberOfDanglingError" "$ olcMemberOfRefInt " "$ olcMemberOfGroupOC " "$ olcMemberOfMemberAD " @@ -1650,8 +1771,10 @@ mo_cf_gen( ConfigArgs *c ) switch( c->type ) { case MO_DN: - value_add_one( &c->rvalue_vals, &mo->mo_dn ); - value_add_one( &c->rvalue_nvals, &mo->mo_ndn ); + if ( mo->mo_dn.bv_val != NULL) { + value_add_one( &c->rvalue_vals, &mo->mo_dn ); + value_add_one( &c->rvalue_nvals, &mo->mo_ndn ); + } break; case MO_DANGLING: @@ -1666,6 +1789,25 @@ mo_cf_gen( ConfigArgs *c ) } break; + case MO_DANGLING_ERROR: + if ( mo->mo_flags & MEMBEROF_FDANGLING_ERROR ) { + char buf[ SLAP_TEXT_BUFLEN ]; + enum_to_verb( slap_ldap_response_code, mo->mo_dangling_err, &bv ); + if ( BER_BVISNULL( &bv ) ) { + bv.bv_len = snprintf( buf, sizeof( buf ), "0x%x", mo->mo_dangling_err ); + if ( bv.bv_len < sizeof( buf ) ) { + bv.bv_val = buf; + } else { + rc = 1; + break; + } + } + value_add_one( &c->rvalue_vals, &bv ); + } else { + rc = 1; + } + break; + case MO_REFINT: c->value_int = MEMBEROF_REFINT( mo ); break; @@ -1677,18 +1819,21 @@ mo_cf_gen( ConfigArgs *c ) #endif case MO_GROUP_OC: - assert( mo->mo_oc_group != NULL ); - value_add_one( &c->rvalue_vals, &mo->mo_oc_group->soc_cname ); + if ( mo->mo_oc_group != NULL ){ + value_add_one( &c->rvalue_vals, &mo->mo_oc_group->soc_cname ); + } break; case MO_MEMBER_AD: - assert( mo->mo_ad_member != NULL ); - value_add_one( &c->rvalue_vals, &mo->mo_ad_member->ad_cname ); + if ( mo->mo_ad_member != NULL ){ + value_add_one( &c->rvalue_vals, &mo->mo_ad_member->ad_cname ); + } break; case MO_MEMBER_OF_AD: - assert( mo->mo_ad_memberof != NULL ); - value_add_one( &c->rvalue_vals, &mo->mo_ad_memberof->ad_cname ); + if ( mo->mo_ad_memberof != NULL ){ + value_add_one( &c->rvalue_vals, &mo->mo_ad_memberof->ad_cname ); + } break; default: @@ -1722,6 +1867,15 @@ mo_cf_gen( ConfigArgs *c ) mo->mo_flags |= dangling_mode[ i ].mask; break; + case MO_DANGLING_ERROR: + i = verb_to_mask( c->argv[ 1 ], slap_ldap_response_code ); + if ( !BER_BVISNULL( &slap_ldap_response_code[ i ].word ) ) { + mo->mo_dangling_err = slap_ldap_response_code[ i ].mask; + } else if ( lutil_atoix( &mo->mo_dangling_err, c->argv[ 1 ], 0 ) ) { + return 1; + } + break; + case MO_REFINT: if ( c->value_int ) { mo->mo_flags |= MEMBEROF_FREFINT; @@ -1836,8 +1990,42 @@ memberof_db_open( { slap_overinst *on = (slap_overinst *)be->bd_info; memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + int rc; + const char *text = NULL; - if ( BER_BVISNULL( &mo->mo_dn ) ) { + if( ! mo->mo_ad_memberof ){ + rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &mo->mo_ad_memberof, &text ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "memberof_db_open: " + "unable to find attribute=\"%s\": %s (%d)\n", + SLAPD_MEMBEROF_ATTR, text, rc ); + return rc; + } + } + + if( ! mo->mo_ad_member ){ + rc = slap_str2ad( SLAPD_GROUP_ATTR, &mo->mo_ad_member, &text ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "memberof_db_open: " + "unable to find attribute=\"%s\": %s (%d)\n", + SLAPD_GROUP_ATTR, text, rc ); + return rc; + } + } + + if( ! mo->mo_oc_group ){ + mo->mo_oc_group = oc_find( SLAPD_GROUP_CLASS ); + if ( mo->mo_oc_group == NULL ) { + Debug( LDAP_DEBUG_ANY, + "memberof_db_open: " + "unable to find objectClass=\"%s\"\n", + SLAPD_GROUP_CLASS, 0, 0 ); + return 1; + } + } + + if ( BER_BVISNULL( &mo->mo_dn ) && !BER_BVISNULL( &be->be_rootdn ) ) { ber_dupbv( &mo->mo_dn, &be->be_rootdn ); ber_dupbv( &mo->mo_ndn, &be->be_rootndn ); } @@ -1927,8 +2115,7 @@ memberof_initialize( void ) memberof.on_bi.bi_op_add = memberof_op_add; memberof.on_bi.bi_op_delete = memberof_op_delete; memberof.on_bi.bi_op_modify = memberof_op_modify; - - memberof.on_response = memberof_response; + memberof.on_bi.bi_op_modrdn = memberof_op_modrdn; memberof.on_bi.bi_cf_ocs = mo_ocs;