#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) \
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 )
{
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 ) {
+ if ( a && attr_find( a->a_next, mc->ad ) != NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: memberof_saveMember_cb(\"%s\"): "
"more than one occurrence of \"%s\" "
* 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 ) {
op2.ors_slimit = 1;
op2.ors_tlimit = SLAP_NO_LIMIT;
- if ( *iswhatp & MEMBEROF_IS_GROUP ) {
+ if ( mci->what & MEMBEROF_IS_GROUP ) {
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;
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 ) {
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;
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;
}
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;
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;
+
+ 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 ];
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 ) {
assert( !BER_BVISNULL( new_dn ) );
assert( !BER_BVISNULL( new_ndn ) );
+ ml = &mod[ mcnt ];
ml->sml_op = LDAP_MOD_ADD;
ml->sml_values[ 0 ] = *new_dn;
ml->sml_nvalues[ 0 ] = *new_ndn;
(void)op->o_bd->be_modify( &op2, &rs2 );
+ if ( rs2.sr_err != LDAP_SUCCESS ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+ snprintf( buf, sizeof( buf ),
+ "memberof_value_modify %s=\"%s\" failed err=%d text=%s",
+ ad->ad_cname.bv_val, new_dn->bv_val, rs2.sr_err,
+ rs2.sr_text ? rs2.sr_text : "" );
+ 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 ) {
assert( !BER_BVISNULL( old_dn ) );
assert( !BER_BVISNULL( old_ndn ) );
+ ml = &mod[ mcnt ];
ml->sml_op = LDAP_MOD_DELETE;
ml->sml_values[ 0 ] = *old_dn;
ml->sml_nvalues[ 0 ] = *old_ndn;
(void)op->o_bd->be_modify( &op2, &rs2 );
+ if ( rs2.sr_err != LDAP_SUCCESS ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+ snprintf( buf, sizeof( buf ),
+ "memberof_value_modify %s=\"%s\" failed err=%d text=%s",
+ ad->ad_cname.bv_val, old_dn->bv_val, rs2.sr_err,
+ rs2.sr_text ? rs2.sr_text : "" );
+ 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 );
}
* 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 )
{
int rc = SLAP_CB_CONTINUE;
int i;
struct berval save_dn, save_ndn;
+ slap_callback *sc;
+ memberof_cbinfo_t *mci;
if ( op->ora_e->e_attrs == NULL ) {
/* FIXME: global overlay; need to deal with */
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; ) {
assert( a->a_nvals != NULL );
for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
- Entry *e;
-
- /* FIXME: entry_get_rw does not pass
- * thru overlays yet; when it does, we
- * might need to make a copy of the DN */
+ Entry *e = NULL;
rc = be_entry_get_rw( op, &a->a_nvals[ i ],
NULL, NULL, 0, &e );
}
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 );
}
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 );
}
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;
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;
+
+ 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;
}
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;
if ( MEMBEROF_REVERSE( mo ) ) {
for ( mlp = &op->orm_modlist; *mlp; mlp = &(*mlp)->sml_next ) {
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;
+
+ 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;
}
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 );
ber_memfree( ml->sml_nvalues[ i ].bv_val );
BER_BVZERO( &ml->sml_nvalues[ i ] );
}
+ ml->sml_numvals--;
if ( j - i == 1 ) {
break;
}
goto done2;
}
- if ( ml->sml_op == LDAP_MOD_DELETE ) {
+ if ( ml->sml_op == LDAP_MOD_DELETE || !ml->sml_values ) {
break;
}
/* fall thru */
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 );
ber_memfree( ml->sml_nvalues[ i ].bv_val );
BER_BVZERO( &ml->sml_nvalues[ i ] );
}
+ ml->sml_numvals--;
if ( j - i == 1 ) {
break;
}
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:;
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;
+
+ 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 };
+ char relax = op->o_relax;
/* 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++ ) {
/* the modification is attempted
* with the original identity */
- (void)memberof_value_modify( &op2, &rs2,
+ (void)memberof_value_modify( op, rs,
&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 );
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,
&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,
&op->o_req_dn, &op->o_req_ndn,
NULL, NULL );
}
-
- ber_bvarray_free( vals );
}
}
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 ) {
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 */
}
}
- 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 ) {
/* 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,
&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 */
/*
* 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;
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 ) {
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;
}
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 );
}
}
- 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 );
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(
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;
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;
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 }
};
"MAY ( "
"olcMemberOfDN "
"$ olcMemberOfDangling "
+ "$ olcMemberOfDanglingError"
"$ olcMemberOfRefInt "
"$ olcMemberOfGroupOC "
"$ olcMemberOfMemberAD "
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:
}
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;
#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:
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;
{
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 );
}
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;