]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/syncrepl.c
Import ITS#3403 fix (syncrepl memory corruption) from HEAD
[openldap] / servers / slapd / syncrepl.c
index 382bfda6004725d47d0795301cda700f98a77628..24e31fab1895178deb42af00b2c9b8fdc5a4f40f 100644 (file)
@@ -45,6 +45,9 @@ static int dn_callback( struct slap_op *, struct slap_rep * );
 static int nonpresent_callback( struct slap_op *, struct slap_rep * );
 static int null_callback( struct slap_op *, struct slap_rep * );
 
+static int si_refreshDelete = 0;
+static int si_refreshPresent = 0;
+
 static AttributeDescription *sync_descs[4];
 
 struct runqueue_s syncrepl_rq;
@@ -109,6 +112,23 @@ init_syncrepl(syncinfo_t *si)
        }
        
        si->si_attrs = tmp;
+
+       for ( n = 0; si->si_exattrs[ n ] != NULL; n++ ) /* empty */;
+       if ( n ) {
+               /* Delete Attributes from exattrs list */
+               for ( i = 0; sync_descs[i] != NULL; i++ ) {
+                       for ( j = 0; si->si_exattrs[j] != NULL; j++ ) {
+                               if ( strcmp( si->si_exattrs[j], sync_descs[i]->ad_cname.bv_val )
+                                       == 0 )
+                               {
+                                       ch_free( si->si_exattrs[j] );
+                                       for ( k = j; si->si_exattrs[k] != NULL; k++ ) {
+                                               si->si_exattrs[k] = si->si_exattrs[k+1];
+                                       }
+                               }
+                       }
+               }
+       }
 }
 
 static int
@@ -431,6 +451,8 @@ done:
                }
        }
 
+       slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx );
+
        return rc;
 }
 
@@ -557,10 +579,10 @@ do_syncrep2(
                        case LDAP_RES_SEARCH_REFERENCE:
 #ifdef NEW_LOGGING
                                LDAP_LOG( OPERATION, ERR,
-                                       "do_syncrep2 : reference received\n", 0, 0, 0 );
+                                       "do_syncrep2: reference received error\n", 0, 0, 0 );
 #else
                                Debug( LDAP_DEBUG_ANY,
-                                       "do_syncrep2 : reference received\n", 0, 0, 0 );
+                                       "do_syncrep2: reference received error\n", 0, 0, 0 );
 #endif
                                break;
 
@@ -628,8 +650,6 @@ do_syncrep2(
                                rc = ldap_parse_intermediate( si->si_ld, msg,
                                        &retoid, &retdata, NULL, 0 );
                                if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
-                                       int             si_refreshDelete = 0;
-                                       int             si_refreshPresent = 0;
                                        ber_init2( ber, retdata, LBER_USE_DER );
 
                                        switch ( si_tag = ber_peek_tag( ber, &len )) {
@@ -640,6 +660,7 @@ do_syncrep2(
                                        case LDAP_TAG_SYNC_REFRESH_DELETE:
                                                si_refreshDelete = 1;
                                        case LDAP_TAG_SYNC_REFRESH_PRESENT:
+                                               si_refreshPresent = 1;
                                                si_refreshPresent = 1;
                                                ber_scanf( ber, "t{", &tag );
                                                if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
@@ -686,11 +707,12 @@ do_syncrep2(
                                                for ( i = 0; syncUUIDs[i].bv_val; i++ ) {
                                                        struct berval *syncuuid_bv;
                                                        syncuuid_bv = ber_dupbv( NULL, &syncUUIDs[i] );
+                                                       slap_sl_free( syncUUIDs[i].bv_val,op->o_tmpmemctx );
                                                        avl_insert( &si->si_presentlist,
                                                                        (caddr_t) syncuuid_bv,
                                                                        syncuuid_cmp, avl_dup_error );
                                                }
-                                               ber_memfree_x( syncUUIDs, op->o_tmpmemctx );
+                                               slap_sl_free( syncUUIDs, op->o_tmpmemctx );
                                                break;
                                        default:
 #ifdef NEW_LOGGING
@@ -812,6 +834,7 @@ do_syncrepl(
        int dostop = 0;
        ber_socket_t s;
        int i, defer = 1;
+       Backend *be;
 
 #ifdef NEW_LOGGING
        LDAP_LOG ( OPERATION, DETAIL1, "do_syncrepl\n", 0, 0, 0 );
@@ -847,7 +870,7 @@ do_syncrepl(
        op.o_dn = si->si_updatedn;
        op.o_ndn = si->si_updatedn;
        op.o_managedsait = 1;
-       op.o_bd = si->si_be;
+       op.o_bd = be = si->si_be;
 
        op.o_sync_state.ctxcsn = NULL;
        op.o_sync_state.sid = -1;
@@ -859,6 +882,8 @@ do_syncrepl(
        /* Establish session, do search */
        if ( !si->si_ld ) {
                first = 1;
+               si_refreshDelete = 0;
+               si_refreshPresent = 0;
                rc = do_syncrep1( &op, si );
        }
 
@@ -874,8 +899,7 @@ do_syncrepl(
                         */
                        if ( rc == LDAP_SUCCESS ) {
                                if ( first ) {
-                                       rc = connection_client_setup( s, do_syncrepl,
-                                               arg );
+                                       rc = connection_client_setup( s, do_syncrepl, arg );
                                } else {
                                        connection_client_enable( s );
                                } 
@@ -923,6 +947,8 @@ do_syncrepl(
 
                if ( !si->si_retrynum || si->si_retrynum[i] == -2 ) {
                        ldap_pvt_runqueue_remove( &syncrepl_rq, rtask );
+                       LDAP_STAILQ_REMOVE( &be->be_syncinfo, si, syncinfo_s, si_next );
+                       syncinfo_free( si );
                } else if ( si->si_retrynum[i] >= -1 ) {
                        if ( si->si_retrynum[i] > 0 )
                                si->si_retrynum[i]--;
@@ -1060,7 +1086,20 @@ syncrepl_message_to_entry(
                if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
                        *modtail = mod->sml_next;
                        slap_mod_free( &mod->sml_mod, 0 );
-                       free( mod );
+                       ch_free( mod );
+               } else {
+                       modtail = &mod->sml_next;
+               }
+       }
+
+       /* Strip out attrs in exattrs list */
+       for ( modtail = modlist; *modtail ; ) {
+               mod = *modtail;
+               if ( ldap_charray_inlist( si->si_exattrs,
+                                       mod->sml_desc->ad_type->sat_cname.bv_val )) {
+                       *modtail = mod->sml_next;
+                       slap_mod_free( &mod->sml_mod, 0 );
+                       ch_free( mod );
                } else {
                        modtail = &mod->sml_next;
                }
@@ -1125,9 +1164,11 @@ syncrepl_entry(
 
        if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ))
        {
-               syncuuid_bv = ber_dupbv( NULL, syncUUID );
-               avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
-                       syncuuid_cmp, avl_dup_error );
+               if (!si_refreshPresent) {
+                       syncuuid_bv = ber_dupbv( NULL, syncUUID );
+                       avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
+                               syncuuid_cmp, avl_dup_error );
+               }
        }
 
        if ( syncstate == LDAP_SYNC_PRESENT ) {
@@ -1350,10 +1391,11 @@ syncrepl_entry(
 done :
 
        if ( syncUUID_strrep.bv_val ) {
-               ber_memfree_x( syncUUID_strrep.bv_val, op->o_tmpmemctx );
+               slap_sl_free( syncUUID_strrep.bv_val, op->o_tmpmemctx );
        }
        if ( si->si_syncUUID_ndn.bv_val ) {
-               ber_memfree_x( si->si_syncUUID_ndn.bv_val, op->o_tmpmemctx );
+               ch_free( si->si_syncUUID_ndn.bv_val );
+               si->si_syncUUID_ndn.bv_val = NULL;
        }
        return ret;
 }
@@ -1381,7 +1423,7 @@ syncrepl_del_nonpresent(
        Modifications *mlnext;
        Modifications *mod;
        Modifications *modlist = NULL;
-       Modifications **modtail = &modlist;
+       Modifications **modtail;
        Attribute       *attr;
 
        struct berval pdn = BER_BVNULL;
@@ -1436,6 +1478,7 @@ syncrepl_del_nonpresent(
                        rc = op->o_bd->be_delete( op, &rs_delete );
 
                        if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) {
+                               modtail = &modlist;
                                mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
                                mod->sml_op = LDAP_MOD_REPLACE;
                                mod->sml_desc = slap_schema.si_ad_objectClass;
@@ -1713,21 +1756,24 @@ syncrepl_updateCookie(
        *modtail = mod;
        modtail = &mod->sml_next;
 
-       if ( scbva[0].bv_val ) ch_free( scbva[0].bv_val );
-       ber_dupbv( &scbva[0], &si->si_syncCookie.octet_str[0] );
        mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
        mod->sml_op = LDAP_MOD_REPLACE;
-       mod->sml_desc = slap_schema.si_ad_syncreplCookie;
+       mod->sml_desc = slap_schema.si_ad_subtreeSpecification;
        mod->sml_type = mod->sml_desc->ad_cname;
-       mod->sml_values = scbva;
+       mod->sml_values = ssbva;
        *modtail = mod;
        modtail = &mod->sml_next;
 
+       /* Keep this last, so we can avoid touching the previous
+        * attributes unnecessarily.
+        */
+       if ( scbva[0].bv_val ) ch_free( scbva[0].bv_val );
+       ber_dupbv( &scbva[0], &si->si_syncCookie.octet_str[0] );
        mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
        mod->sml_op = LDAP_MOD_REPLACE;
-       mod->sml_desc = slap_schema.si_ad_subtreeSpecification;
+       mod->sml_desc = slap_schema.si_ad_syncreplCookie;
        mod->sml_type = mod->sml_desc->ad_cname;
-       mod->sml_values = ssbva;
+       mod->sml_values = scbva;
        *modtail = mod;
        modtail = &mod->sml_next;
 
@@ -1735,7 +1781,7 @@ syncrepl_updateCookie(
 
        op->o_tag = LDAP_REQ_ADD;
        rc = slap_mods_opattrs( op, modlist, modtail,
-                                                        &text,txtbuf, textlen );
+                &text, txtbuf, textlen, 0 );
 
        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
                ml->sml_op = LDAP_MOD_REPLACE;
@@ -1792,7 +1838,8 @@ syncrepl_updateCookie(
        /* update persistent cookie */
 update_cookie_retry:
        op->o_tag = LDAP_REQ_MODIFY;
-       op->orm_modlist = modlist;
+       /* Just modify the cookie value, not the entire entry */
+       op->orm_modlist = mod;
        rc = be->be_modify( op, &rs_modify );
 
        if ( rs_modify.sr_err != LDAP_SUCCESS ) {
@@ -1910,7 +1957,7 @@ dn_callback(
                                "dn_callback : consistency error - entryUUID is not unique\n", 0, 0, 0 );
 #endif
                } else {
-                       ber_dupbv_x( &si->si_syncUUID_ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
+                       ber_dupbv_x( &si->si_syncUUID_ndn, &rs->sr_entry->e_nname, NULL );
                }
        } else if ( rs->sr_type == REP_RESULT ) {
                if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
@@ -2105,3 +2152,98 @@ avl_ber_bvfree( void *bv )
        }
        ch_free ( (char *) bv );
 }
+
+void
+syncinfo_free( syncinfo_t *sie )
+{
+       if ( sie->si_provideruri ) {
+               ch_free( sie->si_provideruri );
+       }
+       if ( sie->si_provideruri_bv ) {
+               ber_bvarray_free( sie->si_provideruri_bv );
+       }
+       if ( sie->si_updatedn.bv_val ) {
+               ch_free( sie->si_updatedn.bv_val );
+       }
+       if ( sie->si_binddn ) {
+               ch_free( sie->si_binddn );
+       }
+       if ( sie->si_passwd ) {
+               ch_free( sie->si_passwd );
+       }
+       if ( sie->si_saslmech ) {
+               ch_free( sie->si_saslmech );
+       }
+       if ( sie->si_secprops ) {
+               ch_free( sie->si_secprops );
+       }
+       if ( sie->si_realm ) {
+               ch_free( sie->si_realm );
+       }
+       if ( sie->si_authcId ) {
+               ch_free( sie->si_authcId );
+       }
+       if ( sie->si_authzId ) {
+               ch_free( sie->si_authzId );
+       }
+       if ( sie->si_filterstr.bv_val ) {
+               ch_free( sie->si_filterstr.bv_val );
+       }
+       if ( sie->si_base.bv_val ) {
+               ch_free( sie->si_base.bv_val );
+       }
+       if ( sie->si_attrs ) {
+               int i = 0;
+               while ( sie->si_attrs[i] != NULL ) {
+                       ch_free( sie->si_attrs[i] );
+                       i++;
+               }
+               ch_free( sie->si_attrs );
+       }
+       if ( sie->si_exattrs ) {
+               int i = 0;
+               while ( sie->si_exattrs[i] != NULL ) {
+                       ch_free( sie->si_exattrs[i] );
+                       i++;
+               }
+               ch_free( sie->si_exattrs );
+       }
+       if ( sie->si_retryinterval ) {
+               ch_free( sie->si_retryinterval );
+       }
+       if ( sie->si_retrynum ) {
+               ch_free( sie->si_retrynum );
+       }
+       if ( sie->si_retrynum_init ) {
+               ch_free( sie->si_retrynum_init );
+       }
+       slap_sync_cookie_free( &sie->si_syncCookie, 0 );
+       if ( sie->si_syncUUID_ndn.bv_val ) {
+               ch_free( sie->si_syncUUID_ndn.bv_val );
+       }
+       if ( sie->si_presentlist ) {
+           avl_free( sie->si_presentlist, avl_ber_bvfree );
+       }
+       if ( sie->si_ld ) {
+               ldap_ld_free( sie->si_ld, 1, NULL, NULL );
+       }
+       while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist )) {
+               struct nonpresent_entry* npe;
+               npe = LDAP_LIST_FIRST( &sie->si_nonpresentlist );
+               LDAP_LIST_REMOVE( npe, npe_link );
+               if ( npe->npe_name ) {
+                       if ( npe->npe_name->bv_val ) {
+                               ch_free( npe->npe_name->bv_val );
+                       }
+                       ch_free( npe->npe_name );
+               }
+               if ( npe->npe_nname ) {
+                       if ( npe->npe_nname->bv_val ) {
+                               ch_free( npe->npe_nname->bv_val );
+                       }
+                       ch_free( npe->npe_nname );
+               }
+               ch_free( npe );
+       }
+       ch_free( sie );
+}