Merge branch 'master' of ssh://jra@git.samba.org/data/git/samba
[kai/samba.git] / source4 / wrepl_server / wrepl_apply_records.c
index 5d7958926c5df97d10db445bb4515f739cbe09a1..380b77517fc557cac8c058c195b9edd91a77ca2f 100644 (file)
@@ -7,7 +7,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -16,8 +16,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
@@ -29,6 +28,7 @@
 #include "nbt_server/wins/winsdb.h"
 #include "libcli/wrepl/winsrepl.h"
 #include "system/time.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
 
 enum _R_ACTION {
        R_INVALID,
@@ -56,13 +56,17 @@ static const char *_R_ACTION_enum_string(enum _R_ACTION action)
 }
 
 #define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
+#if 0 /* unused */
 #define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
+#endif
 #define R_IS_TOMBSTONE(r) ((r)->state == WREPL_STATE_TOMBSTONE)
 
 #define R_IS_UNIQUE(r) ((r)->type == WREPL_TYPE_UNIQUE)
 #define R_IS_GROUP(r) ((r)->type == WREPL_TYPE_GROUP)
 #define R_IS_SGROUP(r) ((r)->type == WREPL_TYPE_SGROUP)
+#if 0 /* unused */
 #define R_IS_MHOMED(r) ((r)->type == WREPL_TYPE_MHOMED)
+#endif
 
 /* blindly overwrite records from the same owner in all cases */
 static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_name *r2)
@@ -71,77 +75,77 @@ static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_
        return R_DO_REPLACE;
 }
 
-static BOOL r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
+static bool r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
 {
        uint32_t i,j;
        size_t len = winsdb_addr_list_length(r1->addresses);
 
        for (i=0; i < len; i++) {
-               BOOL found = False;
+               bool found = false;
                for (j=0; j < r2->num_addresses; j++) {
                        if (strcmp(r1->addresses[i]->address, r2->addresses[j].address) != 0) {
                                continue;
                        }
 
                        if (check_owners && strcmp(r1->addresses[i]->wins_owner, r2->addresses[j].owner) != 0) {
-                               return False;
+                               return false;
                        }
-                       found = True;
+                       found = true;
                        break;
                }
-               if (!found) return False;
+               if (!found) return false;
        }
 
-       return True;
+       return true;
 }
 
-static BOOL r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
+static bool r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
 {
        uint32_t i,j;
        size_t len = winsdb_addr_list_length(r1->addresses);
 
        for (i=0; i < r2->num_addresses; i++) {
-               BOOL found = False;
+               bool found = false;
                for (j=0; j < len; j++) {
                        if (strcmp(r2->addresses[i].address, r1->addresses[j]->address) != 0) {
                                continue;
                        }
 
                        if (check_owners && strcmp(r2->addresses[i].owner, r1->addresses[j]->wins_owner) != 0) {
-                               return False;
+                               return false;
                        }
-                       found = True;
+                       found = true;
                        break;
                }
-               if (!found) return False;
+               if (!found) return false;
        }
 
-       return True;
+       return true;
 }
 
-static BOOL r_1_is_same_as_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
+static bool r_1_is_same_as_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
 {
        size_t len = winsdb_addr_list_length(r1->addresses);
 
        if (len != r2->num_addresses) {
-               return False;
+               return false;
        }
 
        return r_1_is_superset_of_2_address_list(r1, r2, check_owners);
 }
 
-static BOOL r_contains_addrs_from_owner(struct winsdb_record *r1, const char *owner)
+static bool r_contains_addrs_from_owner(struct winsdb_record *r1, const char *owner)
 {
        uint32_t i;
        size_t len = winsdb_addr_list_length(r1->addresses);
 
        for (i=0; i < len; i++) {
                if (strcmp(r1->addresses[i]->wins_owner, owner) == 0) {
-                       return True;
+                       return true;
                }
        }
 
-       return False;
+       return false;
 }
 
 /*
@@ -265,6 +269,14 @@ SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_M
 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4_OWNER_B => B:A_3_4_OWNER_B_X_3_4 => SGROUP_MERGE
 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:B_3_4_X_1_2 => C:B_3_4_X_1_2_3_4 => SGROUP_MERGE
 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
+
+this is a bit strange, incoming tombstone replicas always replace old replicas:
+
+SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:NULL => B:NULL => REPLACE
+SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4 => REPLACE
+SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:B_3_4 => B:B_3_4 => REPLACE
+SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:B_3_4_X_3_4 => B:B_3_4_X_3_4 => REPLACE
 */
 static enum _R_ACTION replace_sgroup_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
 {
@@ -273,11 +285,21 @@ static enum _R_ACTION replace_sgroup_replica_vs_X_replica(struct winsdb_record *
                return R_DO_REPLACE;
        }
 
-       if (!R_IS_SGROUP(r2) || !R_IS_ACTIVE(r2)) {
+       if (!R_IS_SGROUP(r2)) {
                /* NOT REPLACE */
                return R_NOT_REPLACE;
        }
 
+       /*
+        * this is strange, but correct
+        * the incoming tombstone replace the current active
+        * record
+        */
+       if (!R_IS_ACTIVE(r2)) {
+               /* REPLACE */
+               return R_DO_REPLACE;
+       }
+
        if (r2->num_addresses == 0) {
                if (r_contains_addrs_from_owner(r1, r2->owner)) {
                        /* not handled here: MERGE */
@@ -288,12 +310,12 @@ static enum _R_ACTION replace_sgroup_replica_vs_X_replica(struct winsdb_record *
                return R_NOT_REPLACE;
        }
 
-       if (r_1_is_superset_of_2_address_list(r1, r2, True)) {
+       if (r_1_is_superset_of_2_address_list(r1, r2, true)) {
                /* NOT REPLACE */
                return R_NOT_REPLACE;
        }
 
-       if (r_1_is_same_as_2_address_list(r1, r2, False)) {
+       if (r_1_is_same_as_2_address_list(r1, r2, false)) {
                /* REPLACE */
                return R_DO_REPLACE;
        }
@@ -397,8 +419,8 @@ static enum _R_ACTION replace_unique_owned_vs_X_replica(struct winsdb_record *r1
        }
 
        if (!R_IS_ACTIVE(r2)) {
-               /* NOT REPLACE */
-               return R_NOT_REPLACE;
+               /* NOT REPLACE, and PROPAGATE */
+               return R_DO_PROPAGATE;
        }
 
        if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
@@ -411,7 +433,7 @@ static enum _R_ACTION replace_unique_owned_vs_X_replica(struct winsdb_record *r1
         * is unique,active,replica or mhomed,active,replica
         */
 
-       if (r_1_is_subset_of_2_address_list(r1, r2, False)) {
+       if (r_1_is_subset_of_2_address_list(r1, r2, false)) {
                /* 
                 * if r1 has a subset(or same) of the addresses of r2
                 * <=>
@@ -476,8 +498,8 @@ static enum _R_ACTION replace_group_owned_vs_X_replica(struct winsdb_record *r1,
                }
        }
 
-       /* NOT REPLACE */
-       return R_NOT_REPLACE;
+       /* NOT REPLACE, but PROPAGATE */
+       return R_DO_PROPAGATE;
 }
 
 /*
@@ -533,14 +555,17 @@ static enum _R_ACTION replace_sgroup_owned_vs_X_replica(struct winsdb_record *r1
        }
 
        if (!R_IS_SGROUP(r2) || !R_IS_ACTIVE(r2)) {
-               /* NOT REPLACE */
-               return R_NOT_REPLACE;
+               /* NOT REPLACE, but PROPAGATE */
+               return R_DO_PROPAGATE;
        }
 
-       /*
-        * TODO: should we have the same logic here like in 
-        *       replace_sgroup_replica_vs_X_replica() ?
-        */
+       if (r_1_is_same_as_2_address_list(r1, r2, true)) {
+               /*
+                * as we're the old owner and the addresses and their
+                * owners are identical
+                */
+               return R_NOT_REPLACE;
+       }
 
        /* not handled here: MERGE */
        return R_DO_SGROUP_MERGE;
@@ -606,8 +631,8 @@ static enum _R_ACTION replace_mhomed_owned_vs_X_replica(struct winsdb_record *r1
        }
 
        if (!R_IS_ACTIVE(r2)) {
-               /* NOT REPLACE */
-               return R_NOT_REPLACE;
+               /* NOT REPLACE, but PROPAGATE */
+               return R_DO_PROPAGATE;
        }
 
        if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
@@ -620,7 +645,7 @@ static enum _R_ACTION replace_mhomed_owned_vs_X_replica(struct winsdb_record *r1
         * is unique,active,replica or mhomed,active,replica
         */
 
-       if (r_1_is_subset_of_2_address_list(r1, r2, False)) {
+       if (r_1_is_subset_of_2_address_list(r1, r2, false)) {
                /* 
                 * if r1 has a subset(or same) of the addresses of r2
                 * <=>
@@ -665,10 +690,12 @@ static NTSTATUS r_do_add(struct wreplsrv_partner *partner,
 
        for (i=0; i < replica->num_addresses; i++) {
                /* TODO: find out if rec->expire_time is correct here */
-               rec->addresses = winsdb_addr_list_add(rec->addresses,
+               rec->addresses = winsdb_addr_list_add(partner->service->wins_db,
+                                                     rec, rec->addresses,
                                                      replica->addresses[i].address,
                                                      replica->addresses[i].owner,
-                                                     rec->expire_time);
+                                                     rec->expire_time,
+                                                     false);
                NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
        }
 
@@ -708,10 +735,12 @@ static NTSTATUS r_do_replace(struct wreplsrv_partner *partner,
 
        for (i=0; i < replica->num_addresses; i++) {
                /* TODO: find out if rec->expire_time is correct here */
-               rec->addresses = winsdb_addr_list_add(rec->addresses,
+               rec->addresses = winsdb_addr_list_add(partner->service->wins_db,
+                                                     rec, rec->addresses,
                                                      replica->addresses[i].address,
                                                      replica->addresses[i].owner,
-                                                     rec->expire_time);
+                                                     rec->expire_time,
+                                                     false);
                NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
        }
 
@@ -808,31 +837,33 @@ static NTSTATUS r_do_mhomed_merge(struct wreplsrv_partner *partner,
        merge->registered_by = NULL;
 
        for (i=0; i < replica->num_addresses; i++) {
-               /* TODO: find out if rec->expire_time is correct here */
-               merge->addresses = winsdb_addr_list_add(merge->addresses,
+               merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
+                                                       merge, merge->addresses,
                                                        replica->addresses[i].address,
                                                        replica->addresses[i].owner,
-                                                       merge->expire_time);
+                                                       merge->expire_time,
+                                                       false);
                NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
        }
 
        len = winsdb_addr_list_length(rec->addresses);
 
        for (i=0; i < len; i++) {
-               BOOL found = False;
+               bool found = false;
                for (j=0; j < replica->num_addresses; j++) {
                        if (strcmp(replica->addresses[j].address, rec->addresses[i]->address) == 0) {
-                               found = True;
+                               found = true;
                                break;
                        }
                }
                if (found) continue;
 
-               /* TODO: find out if rec->expire_time is correct here */
-               merge->addresses = winsdb_addr_list_add(merge->addresses,
+               merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
+                                                       merge, merge->addresses,
                                                        rec->addresses[i]->address,
                                                        rec->addresses[i]->wins_owner,
-                                                       merge->expire_time);
+                                                       rec->addresses[i]->expire_time,
+                                                       false);
                NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
        }
 
@@ -872,15 +903,15 @@ static void r_do_late_release_demand_handler(struct irpc_request *ireq)
 static NTSTATUS r_do_late_release_demand(struct r_do_challenge_state *state)
 {
        struct irpc_request *ireq;
-       uint32_t *nbt_servers;
+       struct server_id *nbt_servers;
        struct nbtd_proxy_wins_release_demand r;
        uint32_t i;
 
        DEBUG(4,("late release demand record %s\n",
                 nbt_name_string(state, &state->replica.name)));
 
-       nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server");
-       if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
+       nbt_servers = irpc_servers_byname(state->msg_ctx, state, "nbt_server");
+       if ((nbt_servers == NULL) || (nbt_servers[0].id == 0)) {
                return NT_STATUS_INTERNAL_ERROR;
        }
 
@@ -924,9 +955,9 @@ static void r_do_challenge_handler(struct irpc_request *ireq)
        NTSTATUS status;
        struct r_do_challenge_state *state = talloc_get_type(ireq->async.private,
                                                             struct r_do_challenge_state);
-       BOOL old_is_subset = False;
-       BOOL new_is_subset = False;
-       BOOL found = False;
+       bool old_is_subset = false;
+       bool new_is_subset = false;
+       bool found = false;
        uint32_t i,j;
        uint32_t num_rec_addrs;
 
@@ -943,17 +974,17 @@ static void r_do_challenge_handler(struct irpc_request *ireq)
        }
 
        for (i=0; i < state->replica.num_addresses; i++) {
-               found = False;
-               new_is_subset = True;
+               found = false;
+               new_is_subset = true;
                for (j=0; j < state->r.out.num_addrs; j++) {
                        if (strcmp(state->replica.addresses[i].address, state->r.out.addrs[j].addr) == 0) {
-                               found = True;
+                               found = true;
                                break;
                        }
                }
                if (found) continue;
 
-               new_is_subset = False;
+               new_is_subset = false;
                break;
        }
 
@@ -965,26 +996,29 @@ static void r_do_challenge_handler(struct irpc_request *ireq)
 
        num_rec_addrs = winsdb_addr_list_length(state->rec->addresses);
        for (i=0; i < num_rec_addrs; i++) {
-               found = False;
-               old_is_subset = True;
+               found = false;
+               old_is_subset = true;
                for (j=0; j < state->r.out.num_addrs; j++) {
                        if (strcmp(state->rec->addresses[i]->address, state->r.out.addrs[j].addr) == 0) {
-                               found = True;
+                               found = true;
                                break;
                        }
                }
                if (found) continue;
 
-               old_is_subset = False;
+               old_is_subset = false;
                break;
        }
 
        if (!old_is_subset) {
-               r_do_late_release_demand(state);
+               status = r_do_late_release_demand(state);
                /* 
-                * don't free state here, because we pass it down,
+                * only free state on error, because we pass it down,
                 * and r_do_late_release_demand() will free it
                 */
+               if (!NT_STATUS_IS_OK(status)) {
+                       talloc_free(state);
+               }
                return;
        }
 
@@ -1000,7 +1034,7 @@ static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner,
 {
        struct irpc_request *ireq;
        struct r_do_challenge_state *state;
-       uint32_t *nbt_servers;
+       struct server_id *nbt_servers;
        const char **addrs;
        uint32_t i;
 
@@ -1019,8 +1053,8 @@ static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner,
        talloc_steal(state, replica->owner);
        talloc_steal(state, replica->addresses);
 
-       nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server");
-       if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
+       nbt_servers = irpc_servers_byname(state->msg_ctx, state, "nbt_server");
+       if ((nbt_servers == NULL) || (nbt_servers[0].id == 0)) {
                return NT_STATUS_INTERNAL_ERROR;
        }
 
@@ -1047,11 +1081,20 @@ static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner,
        return NT_STATUS_OK;
 }
 
+struct r_do_release_demand_state {
+       struct messaging_context *msg_ctx;
+       struct nbtd_proxy_wins_release_demand r;
+};
+
 static void r_do_release_demand_handler(struct irpc_request *ireq)
 {
        NTSTATUS status;
+       struct r_do_release_demand_state *state = talloc_get_type(ireq->async.private,
+                                                 struct r_do_release_demand_state);
+
        status = irpc_call_recv(ireq);
        /* don't care about the result */
+       talloc_free(state);
 }
 
 static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner,
@@ -1062,10 +1105,10 @@ static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner,
 {
        NTSTATUS status;
        struct irpc_request *ireq;
-       uint32_t *nbt_servers;
+       struct server_id *nbt_servers;
        const char **addrs;
        struct winsdb_addr **addresses;
-       struct nbtd_proxy_wins_release_demand r;
+       struct r_do_release_demand_state *state;
        uint32_t i;
 
        /*
@@ -1081,30 +1124,36 @@ static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner,
        DEBUG(4,("release demand record %s\n",
                 nbt_name_string(mem_ctx, &replica->name)));
 
-       nbt_servers = irpc_servers_byname(partner->service->task->msg_ctx, "nbt_server");
-       if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
+       state = talloc_zero(mem_ctx, struct r_do_release_demand_state);
+       NT_STATUS_HAVE_NO_MEMORY(state);
+       state->msg_ctx  = partner->service->task->msg_ctx;
+
+       nbt_servers = irpc_servers_byname(state->msg_ctx, state, "nbt_server");
+       if ((nbt_servers == NULL) || (nbt_servers[0].id == 0)) {
                return NT_STATUS_INTERNAL_ERROR;
        }
 
-       r.in.name       = *rec->name;
-       r.in.num_addrs  = winsdb_addr_list_length(addresses);
-       r.in.addrs      = talloc_array(partner, struct nbtd_proxy_wins_addr, r.in.num_addrs);
-       NT_STATUS_HAVE_NO_MEMORY(r.in.addrs);
+       state->r.in.name        = *rec->name;
+       state->r.in.num_addrs   = winsdb_addr_list_length(addresses);
+       state->r.in.addrs       = talloc_array(state, struct nbtd_proxy_wins_addr,
+                                              state->r.in.num_addrs);
+       NT_STATUS_HAVE_NO_MEMORY(state->r.in.addrs);
        /* TODO: fix pidl to handle inline ipv4address arrays */
-       addrs                   = winsdb_addr_string_list(r.in.addrs, addresses);
+       addrs                   = winsdb_addr_string_list(state->r.in.addrs, addresses);
        NT_STATUS_HAVE_NO_MEMORY(addrs);
-       for (i=0; i < r.in.num_addrs; i++) {
-               r.in.addrs[i].addr = addrs[i];
+       for (i=0; i < state->r.in.num_addrs; i++) {
+               state->r.in.addrs[i].addr = addrs[i];
        }
 
-       ireq = IRPC_CALL_SEND(partner->service->task->msg_ctx, nbt_servers[0],
+       ireq = IRPC_CALL_SEND(state->msg_ctx, nbt_servers[0],
                              irpc, NBTD_PROXY_WINS_RELEASE_DEMAND,
-                             &r, partner);
+                             &state->r, state);
        NT_STATUS_HAVE_NO_MEMORY(ireq);
 
        ireq->async.fn          = r_do_release_demand_handler;
-       ireq->async.private     = NULL;
+       ireq->async.private     = state;
 
+       talloc_steal(partner, state);
        return NT_STATUS_OK;
 }
 
@@ -1140,8 +1189,8 @@ static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner,
        uint32_t i,j;
        uint8_t ret;
        size_t len;
-       BOOL changed_old_addrs = False;
-       BOOL become_owner = True;
+       bool changed_old_addrs = false;
+       bool become_owner = true;
 
        merge = talloc(mem_ctx, struct winsdb_record);
        NT_STATUS_HAVE_NO_MEMORY(merge);
@@ -1161,62 +1210,63 @@ static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner,
        len = winsdb_addr_list_length(rec->addresses);
 
        for (i=0; i < len; i++) {
-               BOOL found = False;
+               bool found = false;
 
                for (j=0; j < replica->num_addresses; j++) {
                        if (strcmp(rec->addresses[i]->address, replica->addresses[j].address) != 0) {
                                continue;
                        }
 
-                       found = True;
+                       found = true;
 
                        if (strcmp(rec->addresses[i]->wins_owner, replica->addresses[j].owner) != 0) {
-                               changed_old_addrs = True;
+                               changed_old_addrs = true;
                                break;
                        }
                        break;
                }
 
-               /* if it's also in the replica, it'll added later */
-               if (found) continue;
-
                /* 
                 * if the address isn't in the replica and is owned by replicas owner,
                 * it won't be added to the merged record
                 */
-               if (strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) {
-                       changed_old_addrs = True;
+               if (!found && strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) {
+                       changed_old_addrs = true;
                        continue;
                }
 
                /*
-                * add the address to the merge result, with the old owner and expire_time
-                * TODO: check if that's correct for the expire_time
+                * add the address to the merge result, with the old owner and expire_time,
+                * the owner and expire_time will be overwritten later if the address is
+                * in the replica too
                 */
-               merge->addresses = winsdb_addr_list_add(merge->addresses,
+               merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
+                                                       merge, merge->addresses,
                                                        rec->addresses[i]->address,
                                                        rec->addresses[i]->wins_owner,
-                                                       rec->addresses[i]->expire_time);
+                                                       rec->addresses[i]->expire_time,
+                                                       false);
                NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
        }
 
        for (i=0; i < replica->num_addresses; i++) {
-               /* TODO: find out if rec->expire_time is correct here */
-               merge->addresses = winsdb_addr_list_add(merge->addresses,
+               merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
+                                                       merge, merge->addresses,
                                                        replica->addresses[i].address,
                                                        replica->addresses[i].owner,
-                                                       merge->expire_time);
+                                                       merge->expire_time,
+                                                       false);
                NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
        }
 
        /* we the old addresses change changed we don't become the owner */
        if (changed_old_addrs) {
-               become_owner = False;
+               become_owner = false;
        }
 
        /* if we're the owner of the old record, we'll be the owner of the new one too */
        if (strcmp(rec->wins_owner, partner->service->wins_db->local_owner)==0) {
-               become_owner = True;
+               become_owner = true;
        }
 
        /*
@@ -1224,7 +1274,7 @@ static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner,
         */
        len = winsdb_addr_list_length(merge->addresses);
        if (len == 0) {
-               become_owner = True;
+               become_owner = true;
        }
 
        /* 
@@ -1256,9 +1306,9 @@ static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
        NTSTATUS status;
        struct winsdb_record *rec = NULL;
        enum _R_ACTION action = R_INVALID;
-       BOOL same_owner = False;
-       BOOL replica_vs_replica = False;
-       BOOL local_vs_replica = False;
+       bool same_owner = false;
+       bool replica_vs_replica = false;
+       bool local_vs_replica = false;
 
        status = winsdb_lookup(partner->service->wins_db,
                               &replica->name, mem_ctx, &rec);
@@ -1268,11 +1318,11 @@ static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
        NT_STATUS_NOT_OK_RETURN(status);
 
        if (strcmp(rec->wins_owner, partner->service->wins_db->local_owner)==0) {
-               local_vs_replica = True;
+               local_vs_replica = true;
        } else if (strcmp(rec->wins_owner, owner->address)==0) {
-               same_owner = True;
+               same_owner = true;
        } else {
-               replica_vs_replica = True;
+               replica_vs_replica = true;
        }
 
        if (rec->is_static && !same_owner) {
@@ -1324,15 +1374,6 @@ static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
                        action = replace_mhomed_owned_vs_X_replica(rec, replica);
                        break;
                }
-
-               /*
-                * if we own the local record, and it should not be replaced
-                * then propagate the conflict result back to the other
-                * wins servers
-                */
-               if (action == R_NOT_REPLACE) {
-                       action = R_DO_PROPAGATE;
-               }
        }
 
        DEBUG(4,("apply record %s: %s\n",
@@ -1350,31 +1391,32 @@ static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
                return r_do_challenge(partner, mem_ctx, rec, owner, replica);
        case R_DO_RELEASE_DEMAND:
                return r_do_release_demand(partner, mem_ctx, rec, owner, replica);
-       case R_DO_SGROUP_MERGE: 
+       case R_DO_SGROUP_MERGE:
                return r_do_sgroup_merge(partner, mem_ctx, rec, owner, replica);
        }
 
        return NT_STATUS_INTERNAL_ERROR;
 }
 
-NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, struct wreplsrv_pull_names_io *names_io)
+NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner,
+                               struct wrepl_wins_owner *owner,
+                               uint32_t num_names, struct wrepl_name *names)
 {
        NTSTATUS status;
        uint32_t i;
 
        DEBUG(4,("apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
-               names_io->out.num_names, names_io->in.owner.address,
-               (long long)names_io->in.owner.min_version, 
-               (long long)names_io->in.owner.max_version,
+               num_names, owner->address,
+               (long long)owner->min_version, 
+               (long long)owner->max_version,
                partner->address));
 
-       for (i=0; i < names_io->out.num_names; i++) {
+       for (i=0; i < num_names; i++) {
                TALLOC_CTX *tmp_mem = talloc_new(partner);
                NT_STATUS_HAVE_NO_MEMORY(tmp_mem);
 
                status = wreplsrv_apply_one_record(partner, tmp_mem,
-                                                  &names_io->in.owner,
-                                                  &names_io->out.names[i]);
+                                                  owner, &names[i]);
                talloc_free(tmp_mem);
                NT_STATUS_NOT_OK_RETURN(status);
        }
@@ -1382,8 +1424,8 @@ NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, struct wreplsr
        status = wreplsrv_add_table(partner->service,
                                    partner->service,
                                    &partner->service->table,
-                                   names_io->in.owner.address,
-                                   names_io->in.owner.max_version);
+                                   owner->address,
+                                   owner->max_version);
        NT_STATUS_NOT_OK_RETURN(status);
 
        return NT_STATUS_OK;