]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/memberof.c
if referential integrity is broken, things could go wrong; don't assert
[openldap] / servers / slapd / overlays / memberof.c
index 7d56d9789ef0fead99ed40a1cf3f99182195d6c0..45c388650d4f8ac67dae28b47df751bd651709f6 100644 (file)
@@ -264,6 +264,7 @@ memberof_saveMember_cb( Operation *op, SlapReply *rs )
        if ( rs->sr_type == REP_SEARCH ) {
                memberof_cookie_t       *mc;
                Attribute               *a;
+               BerVarray               vals = NULL;
 
                mc = (memberof_cookie_t *)op->o_callback->sc_private;
                mc->foundit = 1;
@@ -272,12 +273,13 @@ memberof_saveMember_cb( Operation *op, SlapReply *rs )
                assert( rs->sr_entry->e_attrs != NULL );
 
                a = attr_find( rs->sr_entry->e_attrs, mc->ad );
+               if ( a != NULL ) {
+                       vals = a->a_nvals;
+               }
 
-               assert( a != NULL );
-
-               memberof_saved_member_set( op, mc->key, a->a_nvals );
+               memberof_saved_member_set( op, mc->key, vals );
 
-               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\" "
@@ -416,6 +418,7 @@ memberof_value_modify(
        op2.o_ndn = op->o_bd->be_rootndn;
 
        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 ] );
@@ -430,6 +433,7 @@ memberof_value_modify(
        op2.orm_modlist = ml;
 
        ml = &mod[ 1 ];
+       ml->sml_numvals = 1;
        ml->sml_values = &values[ 2 ];
        BER_BVZERO( &ml->sml_values[ 1 ] );
        ml->sml_nvalues = &nvalues[ 2 ];
@@ -451,6 +455,13 @@ memberof_value_modify(
                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",
+                               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 ] );
@@ -471,6 +482,13 @@ memberof_value_modify(
                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",
+                               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 ] );
@@ -526,7 +544,7 @@ 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;
@@ -543,11 +561,7 @@ memberof_op_add( Operation *op, SlapReply *rs )
                        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 );
@@ -746,101 +760,133 @@ memberof_op_modify( Operation *op, SlapReply *rs )
        save_dn = op->o_dn;
        save_ndn = op->o_ndn;
 
-       if ( MEMBEROF_DANGLING_CHECK( mo )
-                       && !get_relax( op )
-                       && memberof_isGroupOrMember( op, &iswhat ) == LDAP_SUCCESS
-                       && ( iswhat & MEMBEROF_IS_GROUP ) )
+       if ( memberof_isGroupOrMember( op, &iswhat ) == LDAP_SUCCESS
+               && ( iswhat & 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;
+               int save_member = 0;
+
+               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 != 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 = 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 ( save_member ) {
+                       BerVarray       vals = NULL;
+
+                       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;
+                       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 && vals != NULL ) {
+                               memberof_saved_member_set( op, &saved_member_vals, vals );
+                               ber_bvarray_free_x( vals, op->o_tmpmemctx );
+                       }
+               }
+
+               if ( MEMBEROF_DANGLING_CHECK( mo )
+                               && !get_relax( op ) )
+               {
+                       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;
                                }
-       
-                               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:
+                               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 = 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 ] );
+                                                       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;
@@ -909,6 +955,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;
                                                        }
@@ -1019,6 +1066,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;
                                                }
@@ -1113,7 +1161,7 @@ memberof_res_add( Operation *op, SlapReply *rs )
                }
        }
 
-       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 );
@@ -1275,12 +1323,10 @@ memberof_res_modify( Operation *op, SlapReply *rs )
                                /* fall thru */
        
                        case LDAP_MOD_REPLACE:
+                               vals = memberof_saved_member_get( op, &saved_member_vals );
+
                                /* 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,
@@ -1443,39 +1489,7 @@ memberof_db_init(
        slap_overinst   *on = (slap_overinst *)be->bd_info;
        memberof_t      tmp_mo = { 0 }, *mo;
 
-       int             rc;
-       const char      *text = NULL;
-
-       rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &tmp_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, &tmp_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;
-       }
-
-       tmp_mo.mo_oc_group = oc_find( SLAPD_GROUP_CLASS );
-       if ( tmp_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;
-       }
-
        mo = (memberof_t *)ch_calloc( 1, sizeof( memberof_t ) );
-       *mo = tmp_mo;
-
        on->on_bi.bi_private = (void *)mo;
 
        return 0;
@@ -1651,8 +1665,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:
@@ -1678,18 +1694,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:
@@ -1837,6 +1856,40 @@ 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( ! 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_dupbv( &mo->mo_dn, &be->be_rootdn );