]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/memberof.c
ITS#5484,ITS#5451
[openldap] / servers / slapd / overlays / memberof.c
index 45c388650d4f8ac67dae28b47df751bd651709f6..09edce82b7f6f662703849bf90c0132c9c61f8a2 100644 (file)
@@ -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) \
@@ -192,7 +194,7 @@ memberof_saved_member_free( void *key, void *data )
 static BerVarray
 memberof_saved_member_get( Operation *op, void *keyp )
 {
-       BerVarray       vals;
+       void            *vals;
        BerVarray       *key = (BerVarray *)keyp;
 
        assert( op != NULL );
@@ -202,10 +204,8 @@ memberof_saved_member_get( Operation *op, void *keyp )
                *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;
@@ -230,8 +230,13 @@ memberof_saved_member_set( Operation *op, void *keyp, BerVarray 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 );
+               }
        }
 }
 
@@ -405,6 +410,7 @@ 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;
 
@@ -416,23 +422,28 @@ memberof_value_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 ] );
@@ -441,14 +452,14 @@ 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 ) {
                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;
@@ -458,24 +469,32 @@ memberof_value_modify(
                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;
@@ -485,14 +504,19 @@ memberof_value_modify(
                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 );
                }
@@ -571,7 +595,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 );
@@ -649,7 +673,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 );
@@ -836,7 +860,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 = "adding non-existing object "
                                                                "as group member";
                                                        send_ldap_result( op, rs );
@@ -933,7 +957,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 );
@@ -1044,7 +1068,7 @@ memberof_op_modify( Operation *op, SlapReply *rs )
                                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 );
@@ -1203,6 +1227,7 @@ memberof_res_delete( Operation *op, SlapReply *rs )
                                        NULL, NULL );
                }
 
+               memberof_saved_member_set( op, &saved_memberof_vals, NULL );
                ber_bvarray_free( vals );
        }
 
@@ -1216,6 +1241,7 @@ memberof_res_delete( Operation *op, SlapReply *rs )
                                                NULL, NULL );
                        }
 
+                       memberof_saved_member_set( op, &saved_member_vals, NULL );
                        ber_bvarray_free( vals );
                }
        }
@@ -1487,9 +1513,13 @@ memberof_db_init(
        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;
@@ -1499,12 +1529,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;
@@ -1570,6 +1604,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 }
 };
 
@@ -1581,6 +1622,7 @@ static ConfigOCs mo_ocs[] = {
                "MAY ( "
                        "olcMemberOfDN "
                        "$ olcMemberOfDangling "
+                       "$ olcMemberOfDanglingError"
                        "$ olcMemberOfRefInt "
                        "$ olcMemberOfGroupOC "
                        "$ olcMemberOfMemberAD "
@@ -1683,6 +1725,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;
@@ -1742,6 +1803,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;
@@ -1880,7 +1950,7 @@ memberof_db_open(
                }
        }
 
-    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,
@@ -1891,7 +1961,7 @@ memberof_db_open(
                }
        }
 
-       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 );
        }