#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) \
static BerVarray
memberof_saved_member_get( Operation *op, void *keyp )
{
- BerVarray vals;
+ void *vals;
BerVarray *key = (BerVarray *)keyp;
assert( op != NULL );
*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 );
+ key, NULL, 0, &vals, NULL );
}
return vals;
*key = saved_vals;
} else {
+ void *old_vals = NULL;
+
ldap_pvt_thread_pool_setkey( op->o_threadctx, key,
- saved_vals, memberof_saved_member_free );
+ saved_vals, memberof_saved_member_free, &old_vals, NULL );
+ if ( old_vals != NULL ) {
+ ber_bvarray_free( old_vals );
+ }
}
}
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_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_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 = 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_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[ 1 ];
+ ml = &mod[ mcnt ];
ml->sml_op = LDAP_MOD_ADD;
ml->sml_values[ 0 ] = *new_dn;
if ( rs2.sr_err != LDAP_SUCCESS ) {
char buf[ SLAP_TEXT_BUFLEN ];
snprintf( buf, sizeof( buf ),
- "memberof_value_modify %s=\"%s\" failed err=%d",
- 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 );
+ "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[ 1 ];
+ ml = &mod[ mcnt ];
ml->sml_op = LDAP_MOD_DELETE;
ml->sml_values[ 0 ] = *old_dn;
if ( rs2.sr_err != LDAP_SUCCESS ) {
char buf[ SLAP_TEXT_BUFLEN ];
snprintf( buf, sizeof( buf ),
- "memberof_value_modify %s=\"%s\" failed err=%d",
- 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 );
+ "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 );
}
&& 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; ) {
}
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 );
BerVarray vals = NULL;
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;
rc = backend_attribute( op, NULL, &op->o_req_ndn,
mo->mo_ad_member, &vals, ACL_READ );
&& !get_relax( op ) )
{
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;
assert( op->orm_modlist != NULL );
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 */
}
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 = "deleting non-existing object "
"as memberof";
send_ldap_result( op, rs );
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 );
NULL, NULL );
}
+ memberof_saved_member_set( op, &saved_memberof_vals, NULL );
ber_bvarray_free( vals );
}
NULL, NULL );
}
+ memberof_saved_member_set( op, &saved_member_vals, NULL );
ber_bvarray_free( vals );
}
}
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 */
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 */
ConfigReply *cr )
{
slap_overinst *on = (slap_overinst *)be->bd_info;
- memberof_t tmp_mo = { 0 }, *mo;
+ memberof_t *mo;
mo = (memberof_t *)ch_calloc( 1, sizeof( memberof_t ) );
+
+ /* safe default */
+ mo->mo_dangling_err = LDAP_CONSTRAINT_VIOLATION;
+
on->on_bi.bi_private = (void *)mo;
return 0;
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 "
}
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;
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;
}
}
- if( ! mo->mo_oc_group ){
+ if( ! mo->mo_oc_group ){
mo->mo_oc_group = oc_find( SLAPD_GROUP_CLASS );
if ( mo->mo_oc_group == NULL ) {
Debug( LDAP_DEBUG_ANY,
}
}
- if ( BER_BVISNULL( &mo->mo_dn ) ) {
+ 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 );
}