LCOV - code coverage report
Current view: top level - source4/wrepl_server - wrepl_apply_records.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 461 546 84.4 %
Date: 2024-04-21 15:09:00 Functions: 27 28 96.4 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    
       4             :    WINS Replication server
       5             :    
       6             :    Copyright (C) Stefan Metzmacher      2005
       7             :    
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include <tevent.h>
      24             : #include "samba/service_task.h"
      25             : #include "lib/messaging/irpc.h"
      26             : #include "librpc/gen_ndr/ndr_irpc_c.h"
      27             : #include "librpc/gen_ndr/ndr_winsrepl.h"
      28             : #include "wrepl_server/wrepl_server.h"
      29             : #include "nbt_server/wins/winsdb.h"
      30             : #include "libcli/wrepl/winsrepl.h"
      31             : #include "system/time.h"
      32             : #include "librpc/gen_ndr/ndr_nbt.h"
      33             : #include "param/param.h"
      34             : 
      35             : enum _R_ACTION {
      36             :         R_INVALID,
      37             :         R_DO_REPLACE,
      38             :         R_NOT_REPLACE,
      39             :         R_DO_PROPAGATE,
      40             :         R_DO_CHALLENGE,
      41             :         R_DO_RELEASE_DEMAND,
      42             :         R_DO_SGROUP_MERGE
      43             : };
      44             : 
      45           0 : static const char *_R_ACTION_enum_string(enum _R_ACTION action)
      46             : {
      47           0 :         switch (action) {
      48           0 :         case R_INVALID:                 return "INVALID";
      49           0 :         case R_DO_REPLACE:              return "REPLACE";
      50           0 :         case R_NOT_REPLACE:             return "NOT_REPLACE";
      51           0 :         case R_DO_PROPAGATE:            return "PROPAGATE";
      52           0 :         case R_DO_CHALLENGE:            return "CHALLEGNE";
      53           0 :         case R_DO_RELEASE_DEMAND:       return "RELEASE_DEMAND";
      54           0 :         case R_DO_SGROUP_MERGE:         return "SGROUP_MERGE";
      55             :         }
      56             : 
      57           0 :         return "enum _R_ACTION unknown";
      58             : }
      59             : 
      60             : #define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
      61             : #if 0 /* unused */
      62             : #define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
      63             : #endif
      64             : #define R_IS_TOMBSTONE(r) ((r)->state == WREPL_STATE_TOMBSTONE)
      65             : 
      66             : #define R_IS_UNIQUE(r) ((r)->type == WREPL_TYPE_UNIQUE)
      67             : #define R_IS_GROUP(r) ((r)->type == WREPL_TYPE_GROUP)
      68             : #define R_IS_SGROUP(r) ((r)->type == WREPL_TYPE_SGROUP)
      69             : #if 0 /* unused */
      70             : #define R_IS_MHOMED(r) ((r)->type == WREPL_TYPE_MHOMED)
      71             : #endif
      72             : 
      73             : /* blindly overwrite records from the same owner in all cases */
      74         350 : static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_name *r2)
      75             : {
      76             :         /* REPLACE */
      77         350 :         return R_DO_REPLACE;
      78             : }
      79             : 
      80          29 : static bool r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
      81             : {
      82           0 :         uint32_t i,j;
      83          29 :         size_t len = winsdb_addr_list_length(r1->addresses);
      84             : 
      85          45 :         for (i=0; i < len; i++) {
      86          37 :                 bool found = false;
      87          66 :                 for (j=0; j < r2->num_addresses; j++) {
      88          45 :                         if (strcmp(r1->addresses[i]->address, r2->addresses[j].address) != 0) {
      89          29 :                                 continue;
      90             :                         }
      91             : 
      92          16 :                         if (check_owners && strcmp(r1->addresses[i]->wins_owner, r2->addresses[j].owner) != 0) {
      93           0 :                                 return false;
      94             :                         }
      95          16 :                         found = true;
      96          16 :                         break;
      97             :                 }
      98          37 :                 if (!found) return false;
      99             :         }
     100             : 
     101           8 :         return true;
     102             : }
     103             : 
     104          18 : static bool r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
     105             : {
     106           0 :         uint32_t i,j;
     107          18 :         size_t len = winsdb_addr_list_length(r1->addresses);
     108             : 
     109          30 :         for (i=0; i < r2->num_addresses; i++) {
     110          26 :                 bool found = false;
     111          58 :                 for (j=0; j < len; j++) {
     112          48 :                         if (strcmp(r2->addresses[i].address, r1->addresses[j]->address) != 0) {
     113          32 :                                 continue;
     114             :                         }
     115             : 
     116          16 :                         if (check_owners && strcmp(r2->addresses[i].owner, r1->addresses[j]->wins_owner) != 0) {
     117           4 :                                 return false;
     118             :                         }
     119          12 :                         found = true;
     120          12 :                         break;
     121             :                 }
     122          22 :                 if (!found) return false;
     123             :         }
     124             : 
     125           4 :         return true;
     126             : }
     127             : 
     128          20 : static bool r_1_is_same_as_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
     129             : {
     130          20 :         size_t len = winsdb_addr_list_length(r1->addresses);
     131             : 
     132          20 :         if (len != r2->num_addresses) {
     133          12 :                 return false;
     134             :         }
     135             : 
     136           8 :         return r_1_is_superset_of_2_address_list(r1, r2, check_owners);
     137             : }
     138             : 
     139           8 : static bool r_contains_addrs_from_owner(struct winsdb_record *r1, const char *owner)
     140             : {
     141           0 :         uint32_t i;
     142           8 :         size_t len = winsdb_addr_list_length(r1->addresses);
     143             : 
     144          16 :         for (i=0; i < len; i++) {
     145          13 :                 if (strcmp(r1->addresses[i]->wins_owner, owner) == 0) {
     146           5 :                         return true;
     147             :                 }
     148             :         }
     149             : 
     150           3 :         return false;
     151             : }
     152             : 
     153             : /*
     154             : UNIQUE,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
     155             : UNIQUE,ACTIVE vs. UNIQUE,TOMBSTONE with different ip(s) => NOT REPLACE
     156             : UNIQUE,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
     157             : UNIQUE,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
     158             : UNIQUE,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
     159             : UNIQUE,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
     160             : UNIQUE,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
     161             : UNIQUE,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
     162             : UNIQUE,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
     163             : UNIQUE,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
     164             : UNIQUE,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
     165             : UNIQUE,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
     166             : UNIQUE,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
     167             : UNIQUE,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
     168             : UNIQUE,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
     169             : UNIQUE,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
     170             : UNIQUE,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
     171             : UNIQUE,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
     172             : UNIQUE,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
     173             : UNIQUE,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
     174             : UNIQUE,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
     175             : UNIQUE,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
     176             : UNIQUE,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
     177             : UNIQUE,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
     178             : */
     179          28 : static enum _R_ACTION replace_unique_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
     180             : {
     181          28 :         if (!R_IS_ACTIVE(r1)) {
     182             :                 /* REPLACE */
     183          20 :                 return R_DO_REPLACE;
     184             :         }
     185             : 
     186           8 :         if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
     187             :                 /* REPLACE */
     188           3 :                 return R_DO_REPLACE;
     189             :         }
     190             : 
     191             :         /* NOT REPLACE */
     192           5 :         return R_NOT_REPLACE;
     193             : }
     194             : 
     195             : /*
     196             : GROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
     197             : GROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
     198             : GROUP,RELEASED vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
     199             : GROUP,RELEASED vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
     200             : GROUP,TOMBSTONE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
     201             : GROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
     202             : GROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
     203             : GROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
     204             : GROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
     205             : GROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
     206             : GROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
     207             : GROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
     208             : GROUP,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
     209             : GROUP,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
     210             : GROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
     211             : GROUP,RELEASED vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
     212             : GROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
     213             : GROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
     214             : GROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
     215             : GROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
     216             : GROUP,RELEASED vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
     217             : GROUP,RELEASED vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
     218             : GROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
     219             : GROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
     220             : */
     221          25 : static enum _R_ACTION replace_group_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
     222             : {
     223          25 :         if (!R_IS_ACTIVE(r1) && R_IS_GROUP(r2)) {
     224             :                 /* REPLACE */
     225           3 :                 return R_DO_REPLACE;
     226             :         }
     227             : 
     228          22 :         if (R_IS_TOMBSTONE(r1) && !R_IS_UNIQUE(r2)) {
     229             :                 /* REPLACE */
     230           5 :                 return R_DO_REPLACE;
     231             :         }
     232             : 
     233             :         /* NOT REPLACE */
     234          17 :         return R_NOT_REPLACE;
     235             : }
     236             : 
     237             : /*
     238             : SGROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
     239             : SGROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
     240             : SGROUP,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
     241             : SGROUP,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
     242             : SGROUP,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
     243             : SGROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
     244             : SGROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
     245             : SGROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
     246             : SGROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
     247             : SGROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
     248             : SGROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
     249             : SGROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
     250             : SGROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
     251             : SGROUP,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
     252             : SGROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
     253             : SGROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
     254             : SGROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
     255             : SGROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
     256             : SGROUP,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
     257             : SGROUP,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
     258             : SGROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
     259             : SGROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
     260             : 
     261             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
     262             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
     263             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
     264             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
     265             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
     266             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
     267             : 
     268             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
     269             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4_X_3_4 => SGROUP_MERGE
     270             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
     271             : 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
     272             : 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
     273             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
     274             : 
     275             :  
     276             : this is a bit strange, incoming tombstone replicas always replace old replicas:
     277             : 
     278             : SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:NULL => B:NULL => REPLACE
     279             : SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4 => REPLACE
     280             : SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:B_3_4 => B:B_3_4 => REPLACE
     281             : 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
     282             : */
     283          63 : static enum _R_ACTION replace_sgroup_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
     284             : {
     285          63 :         if (!R_IS_ACTIVE(r1)) {
     286             :                 /* REPLACE */
     287          35 :                 return R_DO_REPLACE;
     288             :         }
     289             : 
     290          28 :         if (!R_IS_SGROUP(r2)) {
     291             :                 /* NOT REPLACE */
     292           6 :                 return R_NOT_REPLACE;
     293             :         }
     294             : 
     295             :         /*
     296             :          * this is strange, but correct
     297             :          * the incoming tombstone replace the current active
     298             :          * record
     299             :          */
     300          22 :         if (!R_IS_ACTIVE(r2)) {
     301             :                 /* REPLACE */
     302           4 :                 return R_DO_REPLACE;
     303             :         }
     304             : 
     305          18 :         if (r2->num_addresses == 0) {
     306           8 :                 if (r_contains_addrs_from_owner(r1, r2->owner)) {
     307             :                         /* not handled here: MERGE */
     308           5 :                         return R_DO_SGROUP_MERGE;
     309             :                 }
     310             : 
     311             :                 /* NOT REPLACE */
     312           3 :                 return R_NOT_REPLACE;
     313             :         }
     314             : 
     315          10 :         if (r_1_is_superset_of_2_address_list(r1, r2, true)) {
     316             :                 /* NOT REPLACE */
     317           2 :                 return R_NOT_REPLACE;
     318             :         }
     319             : 
     320           8 :         if (r_1_is_same_as_2_address_list(r1, r2, false)) {
     321             :                 /* REPLACE */
     322           2 :                 return R_DO_REPLACE;
     323             :         }
     324             : 
     325             :         /* not handled here: MERGE */
     326           6 :         return R_DO_SGROUP_MERGE;
     327             : }
     328             : 
     329             : /*
     330             : MHOMED,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
     331             : MHOMED,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
     332             : MHOMED,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
     333             : MHOMED,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
     334             : MHOMED,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
     335             : MHOMED,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
     336             : MHOMED,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
     337             : MHOMED,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
     338             : MHOMED,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
     339             : MHOMED,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
     340             : MHOMED,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
     341             : MHOMED,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
     342             : MHOMED,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
     343             : MHOMED,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
     344             : MHOMED,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
     345             : MHOMED,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
     346             : MHOMED,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
     347             : MHOMED,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
     348             : MHOMED,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
     349             : MHOMED,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
     350             : MHOMED,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
     351             : MHOMED,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
     352             : MHOMED,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
     353             : MHOMED,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
     354             : */
     355          25 : static enum _R_ACTION replace_mhomed_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
     356             : {
     357          25 :         if (!R_IS_ACTIVE(r1)) {
     358             :                 /* REPLACE */
     359          16 :                 return R_DO_REPLACE;
     360             :         }
     361             : 
     362           9 :         if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
     363             :                 /* REPLACE */
     364           3 :                 return R_DO_REPLACE;
     365             :         }
     366             : 
     367             :         /* NOT REPLACE */
     368           6 :         return R_NOT_REPLACE;
     369             : }
     370             : 
     371             : /*
     372             : active:
     373             : _UA_UA_SI_U<00> => REPLACE
     374             : _UA_UA_DI_P<00> => NOT REPLACE
     375             : _UA_UA_DI_O<00> => NOT REPLACE
     376             : _UA_UA_DI_N<00> => REPLACE
     377             : _UA_UT_SI_U<00> => NOT REPLACE
     378             : _UA_UT_DI_U<00> => NOT REPLACE
     379             : _UA_GA_SI_R<00> => REPLACE
     380             : _UA_GA_DI_R<00> => REPLACE
     381             : _UA_GT_SI_U<00> => NOT REPLACE
     382             : _UA_GT_DI_U<00> => NOT REPLACE
     383             : _UA_SA_SI_R<00> => REPLACE
     384             : _UA_SA_DI_R<00> => REPLACE
     385             : _UA_ST_SI_U<00> => NOT REPLACE
     386             : _UA_ST_DI_U<00> => NOT REPLACE
     387             : _UA_MA_SI_U<00> => REPLACE
     388             : _UA_MA_SP_U<00> => REPLACE
     389             : _UA_MA_DI_P<00> => NOT REPLACE
     390             : _UA_MA_DI_O<00> => NOT REPLACE
     391             : _UA_MA_DI_N<00> => REPLACE
     392             : _UA_MT_SI_U<00> => NOT REPLACE
     393             : _UA_MT_DI_U<00> => NOT REPLACE
     394             : Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
     395             : _UA_UA_DI_A<00> => MHOMED_MERGE
     396             : _UA_MA_DI_A<00> => MHOMED_MERGE
     397             : 
     398             : released:
     399             : _UR_UA_SI<00> => REPLACE
     400             : _UR_UA_DI<00> => REPLACE
     401             : _UR_UT_SI<00> => REPLACE
     402             : _UR_UT_DI<00> => REPLACE
     403             : _UR_GA_SI<00> => REPLACE
     404             : _UR_GA_DI<00> => REPLACE
     405             : _UR_GT_SI<00> => REPLACE
     406             : _UR_GT_DI<00> => REPLACE
     407             : _UR_SA_SI<00> => REPLACE
     408             : _UR_SA_DI<00> => REPLACE
     409             : _UR_ST_SI<00> => REPLACE
     410             : _UR_ST_DI<00> => REPLACE
     411             : _UR_MA_SI<00> => REPLACE
     412             : _UR_MA_DI<00> => REPLACE
     413             : _UR_MT_SI<00> => REPLACE
     414             : _UR_MT_DI<00> => REPLACE
     415             : */
     416          40 : static enum _R_ACTION replace_unique_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
     417             : {
     418          40 :         if (!R_IS_ACTIVE(r1)) {
     419             :                 /* REPLACE */
     420          16 :                 return R_DO_REPLACE;
     421             :         }
     422             : 
     423          24 :         if (!R_IS_ACTIVE(r2)) {
     424             :                 /* NOT REPLACE, and PROPAGATE */
     425           8 :                 return R_DO_PROPAGATE;
     426             :         }
     427             : 
     428          16 :         if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
     429             :                 /* REPLACE and send a release demand to the old name owner */
     430           4 :                 return R_DO_RELEASE_DEMAND;
     431             :         }
     432             : 
     433             :         /* 
     434             :          * here we only have unique,active,owned vs.
     435             :          * is unique,active,replica or mhomed,active,replica
     436             :          */
     437             : 
     438          12 :         if (r_1_is_subset_of_2_address_list(r1, r2, false)) {
     439             :                 /* 
     440             :                  * if r1 has a subset(or same) of the addresses of r2
     441             :                  * <=>
     442             :                  * if r2 has a superset(or same) of the addresses of r1
     443             :                  *
     444             :                  * then replace the record
     445             :                  */
     446           3 :                 return R_DO_REPLACE;
     447             :         }
     448             : 
     449             :         /*
     450             :          * in any other case, we need to do
     451             :          * a name request to the old name holder
     452             :          * to see if it's still there...
     453             :          */
     454           9 :         return R_DO_CHALLENGE;
     455             : }
     456             : 
     457             : /*
     458             : active:
     459             : _GA_UA_SI_U<00> => NOT REPLACE
     460             : _GA_UA_DI_U<00> => NOT REPLACE
     461             : _GA_UT_SI_U<00> => NOT REPLACE
     462             : _GA_UT_DI_U<00> => NOT REPLACE
     463             : _GA_GA_SI_U<00> => REPLACE
     464             : _GA_GA_DI_U<00> => REPLACE
     465             : _GA_GT_SI_U<00> => NOT REPLACE
     466             : _GA_GT_DI_U<00> => NOT REPLACE
     467             : _GA_SA_SI_U<00> => NOT REPLACE
     468             : _GA_SA_DI_U<00> => NOT REPLACE
     469             : _GA_ST_SI_U<00> => NOT REPLACE
     470             : _GA_ST_DI_U<00> => NOT REPLACE
     471             : _GA_MA_SI_U<00> => NOT REPLACE
     472             : _GA_MA_DI_U<00> => NOT REPLACE
     473             : _GA_MT_SI_U<00> => NOT REPLACE
     474             : _GA_MT_DI_U<00> => NOT REPLACE
     475             : 
     476             : released:
     477             : _GR_UA_SI<00> => NOT REPLACE
     478             : _GR_UA_DI<00> => NOT REPLACE
     479             : _GR_UT_SI<00> => NOT REPLACE
     480             : _GR_UT_DI<00> => NOT REPLACE
     481             : _GR_GA_SI<00> => REPLACE
     482             : _GR_GA_DI<00> => REPLACE
     483             : _GR_GT_SI<00> => REPLACE
     484             : _GR_GT_DI<00> => REPLACE
     485             : _GR_SA_SI<00> => NOT REPLACE
     486             : _GR_SA_DI<00> => NOT REPLACE
     487             : _GR_ST_SI<00> => NOT REPLACE
     488             : _GR_ST_DI<00> => NOT REPLACE
     489             : _GR_MA_SI<00> => NOT REPLACE
     490             : _GR_MA_DI<00> => NOT REPLACE
     491             : _GR_MT_SI<00> => NOT REPLACE
     492             : _GR_MT_DI<00> => NOT REPLACE
     493             : */
     494          32 : static enum _R_ACTION replace_group_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
     495             : {
     496          32 :         if (R_IS_GROUP(r1) && R_IS_GROUP(r2)) {
     497           8 :                 if (!R_IS_ACTIVE(r1) || R_IS_ACTIVE(r2)) {
     498             :                         /* REPLACE */
     499           6 :                         return R_DO_REPLACE;
     500             :                 }
     501             :         }
     502             : 
     503             :         /* NOT REPLACE, but PROPAGATE */
     504          26 :         return R_DO_PROPAGATE;
     505             : }
     506             : 
     507             : /*
     508             : active (not sgroup vs. sgroup yet!):
     509             : _SA_UA_SI_U<1c> => NOT REPLACE
     510             : _SA_UA_DI_U<1c> => NOT REPLACE
     511             : _SA_UT_SI_U<1c> => NOT REPLACE
     512             : _SA_UT_DI_U<1c> => NOT REPLACE
     513             : _SA_GA_SI_U<1c> => NOT REPLACE
     514             : _SA_GA_DI_U<1c> => NOT REPLACE
     515             : _SA_GT_SI_U<1c> => NOT REPLACE
     516             : _SA_GT_DI_U<1c> => NOT REPLACE
     517             : _SA_MA_SI_U<1c> => NOT REPLACE
     518             : _SA_MA_DI_U<1c> => NOT REPLACE
     519             : _SA_MT_SI_U<1c> => NOT REPLACE
     520             : _SA_MT_DI_U<1c> => NOT REPLACE
     521             : 
     522             : Test Replica vs. owned active: SGROUP vs. SGROUP tests
     523             : _SA_SA_DI_U<1c> => SGROUP_MERGE
     524             : _SA_SA_SI_U<1c> => SGROUP_MERGE
     525             : _SA_SA_SP_U<1c> => SGROUP_MERGE
     526             : _SA_SA_SB_U<1c> => SGROUP_MERGE
     527             : _SA_ST_DI_U<1c> => NOT REPLACE
     528             : _SA_ST_SI_U<1c> => NOT REPLACE
     529             : _SA_ST_SP_U<1c> => NOT REPLACE
     530             : _SA_ST_SB_U<1c> => NOT REPLACE
     531             : 
     532             : SGROUP,ACTIVE vs. SGROUP,* is not handled here!
     533             : 
     534             : released:
     535             : _SR_UA_SI<1c> => REPLACE
     536             : _SR_UA_DI<1c> => REPLACE
     537             : _SR_UT_SI<1c> => REPLACE
     538             : _SR_UT_DI<1c> => REPLACE
     539             : _SR_GA_SI<1c> => REPLACE
     540             : _SR_GA_DI<1c> => REPLACE
     541             : _SR_GT_SI<1c> => REPLACE
     542             : _SR_GT_DI<1c> => REPLACE
     543             : _SR_SA_SI<1c> => REPLACE
     544             : _SR_SA_DI<1c> => REPLACE
     545             : _SR_ST_SI<1c> => REPLACE
     546             : _SR_ST_DI<1c> => REPLACE
     547             : _SR_MA_SI<1c> => REPLACE
     548             : _SR_MA_DI<1c> => REPLACE
     549             : _SR_MT_SI<1c> => REPLACE
     550             : _SR_MT_DI<1c> => REPLACE
     551             : */
     552          54 : static enum _R_ACTION replace_sgroup_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
     553             : {
     554          54 :         if (!R_IS_ACTIVE(r1)) {
     555             :                 /* REPLACE */
     556          26 :                 return R_DO_REPLACE;
     557             :         }
     558             : 
     559          28 :         if (!R_IS_SGROUP(r2) || !R_IS_ACTIVE(r2)) {
     560             :                 /* NOT REPLACE, but PROPAGATE */
     561          16 :                 return R_DO_PROPAGATE;
     562             :         }
     563             : 
     564          12 :         if (r_1_is_same_as_2_address_list(r1, r2, true)) {
     565             :                 /*
     566             :                  * as we're the old owner and the addresses and their
     567             :                  * owners are identical
     568             :                  */
     569           0 :                 return R_NOT_REPLACE;
     570             :         }
     571             : 
     572             :         /* not handled here: MERGE */
     573          12 :         return R_DO_SGROUP_MERGE;
     574             : }
     575             : 
     576             : /*
     577             : active:
     578             : _MA_UA_SI_U<00> => REPLACE
     579             : _MA_UA_DI_P<00> => NOT REPLACE
     580             : _MA_UA_DI_O<00> => NOT REPLACE
     581             : _MA_UA_DI_N<00> => REPLACE
     582             : _MA_UT_SI_U<00> => NOT REPLACE
     583             : _MA_UT_DI_U<00> => NOT REPLACE
     584             : _MA_GA_SI_R<00> => REPLACE
     585             : _MA_GA_DI_R<00> => REPLACE
     586             : _MA_GT_SI_U<00> => NOT REPLACE
     587             : _MA_GT_DI_U<00> => NOT REPLACE
     588             : _MA_SA_SI_R<00> => REPLACE
     589             : _MA_SA_DI_R<00> => REPLACE
     590             : _MA_ST_SI_U<00> => NOT REPLACE
     591             : _MA_ST_DI_U<00> => NOT REPLACE
     592             : _MA_MA_SI_U<00> => REPLACE
     593             : _MA_MA_SP_U<00> => REPLACE
     594             : _MA_MA_DI_P<00> => NOT REPLACE
     595             : _MA_MA_DI_O<00> => NOT REPLACE
     596             : _MA_MA_DI_N<00> => REPLACE
     597             : _MA_MT_SI_U<00> => NOT REPLACE
     598             : _MA_MT_DI_U<00> => NOT REPLACE
     599             : Test Replica vs. owned active: some more MHOMED combinations
     600             : _MA_MA_SP_U<00> => REPLACE
     601             : _MA_MA_SM_U<00> => REPLACE
     602             : _MA_MA_SB_P<00> => MHOMED_MERGE
     603             : _MA_MA_SB_A<00> => MHOMED_MERGE
     604             : _MA_MA_SB_PRA<00> => NOT REPLACE
     605             : _MA_MA_SB_O<00> => NOT REPLACE
     606             : _MA_MA_SB_N<00> => REPLACE
     607             : Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
     608             : _MA_UA_SB_P<00> => MHOMED_MERGE
     609             : 
     610             : released:
     611             : _MR_UA_SI<00> => REPLACE
     612             : _MR_UA_DI<00> => REPLACE
     613             : _MR_UT_SI<00> => REPLACE
     614             : _MR_UT_DI<00> => REPLACE
     615             : _MR_GA_SI<00> => REPLACE
     616             : _MR_GA_DI<00> => REPLACE
     617             : _MR_GT_SI<00> => REPLACE
     618             : _MR_GT_DI<00> => REPLACE
     619             : _MR_SA_SI<00> => REPLACE
     620             : _MR_SA_DI<00> => REPLACE
     621             : _MR_ST_SI<00> => REPLACE
     622             : _MR_ST_DI<00> => REPLACE
     623             : _MR_MA_SI<00> => REPLACE
     624             : _MR_MA_DI<00> => REPLACE
     625             : _MR_MT_SI<00> => REPLACE
     626             : _MR_MT_DI<00> => REPLACE
     627             : */
     628          45 : static enum _R_ACTION replace_mhomed_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
     629             : {
     630          45 :         if (!R_IS_ACTIVE(r1)) {
     631             :                 /* REPLACE */
     632          16 :                 return R_DO_REPLACE;
     633             :         }
     634             : 
     635          29 :         if (!R_IS_ACTIVE(r2)) {
     636             :                 /* NOT REPLACE, but PROPAGATE */
     637           8 :                 return R_DO_PROPAGATE;
     638             :         }
     639             : 
     640          21 :         if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
     641             :                 /* REPLACE and send a release demand to the old name owner */
     642           4 :                 return R_DO_RELEASE_DEMAND;
     643             :         }
     644             : 
     645             :         /* 
     646             :          * here we only have mhomed,active,owned vs.
     647             :          * is unique,active,replica or mhomed,active,replica
     648             :          */
     649             : 
     650          17 :         if (r_1_is_subset_of_2_address_list(r1, r2, false)) {
     651             :                 /* 
     652             :                  * if r1 has a subset(or same) of the addresses of r2
     653             :                  * <=>
     654             :                  * if r2 has a superset(or same) of the addresses of r1
     655             :                  *
     656             :                  * then replace the record
     657             :                  */
     658           5 :                 return R_DO_REPLACE;
     659             :         }
     660             : 
     661             :         /*
     662             :          * in any other case, we need to do
     663             :          * a name request to the old name holder
     664             :          * to see if it's still there...
     665             :          */
     666          12 :         return R_DO_CHALLENGE;
     667             : }
     668             : 
     669          13 : static NTSTATUS r_do_add(struct wreplsrv_partner *partner,
     670             :                          TALLOC_CTX *mem_ctx,
     671             :                          struct wrepl_wins_owner *owner,
     672             :                          struct wrepl_name *replica)
     673             : {
     674           0 :         struct winsdb_record *rec;
     675           0 :         uint32_t i;
     676           0 :         uint8_t ret;
     677             : 
     678          13 :         rec = talloc(mem_ctx, struct winsdb_record);
     679          13 :         NT_STATUS_HAVE_NO_MEMORY(rec);
     680             : 
     681          13 :         rec->name    = &replica->name;
     682          13 :         rec->type    = replica->type;
     683          13 :         rec->state   = replica->state;
     684          13 :         rec->node    = replica->node;
     685          13 :         rec->is_static       = replica->is_static;
     686          13 :         rec->expire_time= time(NULL) + partner->service->config.verify_interval;
     687          13 :         rec->version = replica->version_id;
     688          13 :         rec->wins_owner      = replica->owner;
     689          13 :         rec->addresses       = winsdb_addr_list_make(rec);
     690          13 :         NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
     691          13 :         rec->registered_by = NULL;
     692             : 
     693          26 :         for (i=0; i < replica->num_addresses; i++) {
     694             :                 /* TODO: find out if rec->expire_time is correct here */
     695          26 :                 rec->addresses = winsdb_addr_list_add(partner->service->wins_db,
     696             :                                                       rec, rec->addresses,
     697          13 :                                                       replica->addresses[i].address,
     698          13 :                                                       replica->addresses[i].owner,
     699             :                                                       rec->expire_time,
     700             :                                                       false);
     701          13 :                 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
     702             :         }
     703             : 
     704          13 :         ret = winsdb_add(partner->service->wins_db, rec, 0);
     705          13 :         if (ret != NBT_RCODE_OK) {
     706           0 :                 DEBUG(0,("Failed to add record %s: %u\n",
     707             :                         nbt_name_string(mem_ctx, &replica->name), ret));
     708           0 :                 return NT_STATUS_FOOBAR;
     709             :         }
     710             : 
     711          13 :         DEBUG(4,("added record %s\n",
     712             :                 nbt_name_string(mem_ctx, &replica->name)));
     713             : 
     714          13 :         return NT_STATUS_OK;
     715             : }
     716             : 
     717         526 : static NTSTATUS r_do_replace(struct wreplsrv_partner *partner,
     718             :                              TALLOC_CTX *mem_ctx,
     719             :                              struct winsdb_record *rec,
     720             :                              struct wrepl_wins_owner *owner,
     721             :                              struct wrepl_name *replica)
     722             : {
     723           0 :         uint32_t i;
     724           0 :         uint8_t ret;
     725             : 
     726         526 :         rec->name    = &replica->name;
     727         526 :         rec->type    = replica->type;
     728         526 :         rec->state   = replica->state;
     729         526 :         rec->node    = replica->node;
     730         526 :         rec->is_static       = replica->is_static;
     731         526 :         rec->expire_time= time(NULL) + partner->service->config.verify_interval;
     732         526 :         rec->version = replica->version_id;
     733         526 :         rec->wins_owner      = replica->owner;
     734         526 :         rec->addresses       = winsdb_addr_list_make(rec);
     735         526 :         NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
     736         526 :         rec->registered_by = NULL;
     737             : 
     738        1145 :         for (i=0; i < replica->num_addresses; i++) {
     739             :                 /* TODO: find out if rec->expire_time is correct here */
     740        1238 :                 rec->addresses = winsdb_addr_list_add(partner->service->wins_db,
     741             :                                                       rec, rec->addresses,
     742         619 :                                                       replica->addresses[i].address,
     743         619 :                                                       replica->addresses[i].owner,
     744             :                                                       rec->expire_time,
     745             :                                                       false);
     746         619 :                 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
     747             :         }
     748             : 
     749         526 :         ret = winsdb_modify(partner->service->wins_db, rec, 0);
     750         526 :         if (ret != NBT_RCODE_OK) {
     751           0 :                 DEBUG(0,("Failed to replace record %s: %u\n",
     752             :                         nbt_name_string(mem_ctx, &replica->name), ret));
     753           0 :                 return NT_STATUS_FOOBAR;
     754             :         }
     755             : 
     756         526 :         DEBUG(4,("replaced record %s\n",
     757             :                 nbt_name_string(mem_ctx, &replica->name)));
     758             : 
     759         526 :         return NT_STATUS_OK;
     760             : }
     761             : 
     762          48 : static NTSTATUS r_not_replace(struct wreplsrv_partner *partner,
     763             :                               TALLOC_CTX *mem_ctx,
     764             :                               struct winsdb_record *rec,
     765             :                               struct wrepl_wins_owner *owner,
     766             :                               struct wrepl_name *replica)
     767             : {
     768          48 :         DEBUG(4,("not replace record %s\n",
     769             :                  nbt_name_string(mem_ctx, &replica->name)));
     770          48 :         return NT_STATUS_OK;
     771             : }
     772             : 
     773          58 : static NTSTATUS r_do_propagate(struct wreplsrv_partner *partner,
     774             :                                TALLOC_CTX *mem_ctx,
     775             :                                struct winsdb_record *rec,
     776             :                                struct wrepl_wins_owner *owner,
     777             :                                struct wrepl_name *replica)
     778             : {
     779           0 :         uint8_t ret;
     780           0 :         uint32_t modify_flags;
     781             : 
     782             :         /*
     783             :          * allocate a new version id for the record to that it'll be replicated
     784             :          */
     785          58 :         modify_flags    = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
     786             : 
     787          58 :         ret = winsdb_modify(partner->service->wins_db, rec, modify_flags);
     788          58 :         if (ret != NBT_RCODE_OK) {
     789           0 :                 DEBUG(0,("Failed to replace record %s: %u\n",
     790             :                         nbt_name_string(mem_ctx, &replica->name), ret));
     791           0 :                 return NT_STATUS_FOOBAR;
     792             :         }
     793             : 
     794          58 :         DEBUG(4,("propagated record %s\n",
     795             :                  nbt_name_string(mem_ctx, &replica->name)));
     796             : 
     797          58 :         return NT_STATUS_OK;
     798             : }
     799             : 
     800             : /* 
     801             : Test Replica vs. owned active: some more MHOMED combinations
     802             : _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
     803             : _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
     804             : _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
     805             : _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
     806             : _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
     807             : _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
     808             : _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
     809             : Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
     810             : _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
     811             : _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
     812             : _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
     813             : _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
     814             : */
     815           5 : static NTSTATUS r_do_mhomed_merge(struct wreplsrv_partner *partner,
     816             :                                   TALLOC_CTX *mem_ctx,
     817             :                                   struct winsdb_record *rec,
     818             :                                   struct wrepl_wins_owner *owner,
     819             :                                   struct wrepl_name *replica)
     820             : {
     821           0 :         struct winsdb_record *merge;
     822           0 :         uint32_t i,j;
     823           0 :         uint8_t ret;
     824           0 :         size_t len;
     825             : 
     826           5 :         merge = talloc(mem_ctx, struct winsdb_record);
     827           5 :         NT_STATUS_HAVE_NO_MEMORY(merge);
     828             : 
     829           5 :         merge->name          = &replica->name;
     830           5 :         merge->type          = WREPL_TYPE_MHOMED;
     831           5 :         merge->state         = replica->state;
     832           5 :         merge->node          = replica->node;
     833           5 :         merge->is_static     = replica->is_static;
     834           5 :         merge->expire_time   = time(NULL) + partner->service->config.verify_interval;
     835           5 :         merge->version               = replica->version_id;
     836           5 :         merge->wins_owner    = replica->owner;
     837           5 :         merge->addresses     = winsdb_addr_list_make(merge);
     838           5 :         NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
     839           5 :         merge->registered_by = NULL;
     840             : 
     841          10 :         for (i=0; i < replica->num_addresses; i++) {
     842          10 :                 merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
     843             :                                                         merge, merge->addresses,
     844           5 :                                                         replica->addresses[i].address,
     845           5 :                                                         replica->addresses[i].owner,
     846             :                                                         merge->expire_time,
     847             :                                                         false);
     848           5 :                 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
     849             :         }
     850             : 
     851           5 :         len = winsdb_addr_list_length(rec->addresses);
     852             : 
     853          13 :         for (i=0; i < len; i++) {
     854           8 :                 bool found = false;
     855          13 :                 for (j=0; j < replica->num_addresses; j++) {
     856           8 :                         if (strcmp(replica->addresses[j].address, rec->addresses[i]->address) == 0) {
     857           3 :                                 found = true;
     858           3 :                                 break;
     859             :                         }
     860             :                 }
     861           8 :                 if (found) continue;
     862             : 
     863          10 :                 merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
     864             :                                                         merge, merge->addresses,
     865           5 :                                                         rec->addresses[i]->address,
     866           5 :                                                         rec->addresses[i]->wins_owner,
     867           5 :                                                         rec->addresses[i]->expire_time,
     868             :                                                         false);
     869           5 :                 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
     870             :         }
     871             : 
     872           5 :         ret = winsdb_modify(partner->service->wins_db, merge, 0);
     873           5 :         if (ret != NBT_RCODE_OK) {
     874           0 :                 DEBUG(0,("Failed to modify mhomed merge record %s: %u\n",
     875             :                         nbt_name_string(mem_ctx, &replica->name), ret));
     876           0 :                 return NT_STATUS_FOOBAR;
     877             :         }
     878             : 
     879           5 :         DEBUG(4,("mhomed merge record %s\n",
     880             :                 nbt_name_string(mem_ctx, &replica->name)));
     881             : 
     882           5 :         return NT_STATUS_OK;
     883             : }
     884             : 
     885             : struct r_do_challenge_state {
     886             :         struct dcerpc_binding_handle *irpc_handle;
     887             :         struct wreplsrv_partner *partner;
     888             :         struct winsdb_record *rec;
     889             :         struct wrepl_wins_owner owner;
     890             :         struct wrepl_name replica;
     891             :         struct nbtd_proxy_wins_challenge r;
     892             :         struct nbtd_proxy_wins_release_demand dr;
     893             : };
     894             : 
     895           2 : static void r_do_late_release_demand_handler(struct tevent_req *subreq)
     896             : {
     897           0 :         NTSTATUS status;
     898           0 :         struct r_do_challenge_state *state =
     899           2 :                 tevent_req_callback_data(subreq,
     900             :                 struct r_do_challenge_state);
     901             : 
     902           2 :         status = dcerpc_nbtd_proxy_wins_release_demand_r_recv(subreq, state);
     903           2 :         TALLOC_FREE(subreq);
     904             : 
     905             :         /* don't care about the result */
     906           0 :         (void)status;
     907           2 :         talloc_free(state);
     908           2 : }
     909             : 
     910           2 : static NTSTATUS r_do_late_release_demand(struct r_do_challenge_state *state)
     911             : {
     912           0 :         struct tevent_req *subreq;
     913           0 :         uint32_t i;
     914             : 
     915           2 :         DEBUG(4,("late release demand record %s\n",
     916             :                  nbt_name_string(state, &state->replica.name)));
     917             : 
     918           2 :         state->dr.in.name    = state->replica.name;
     919           2 :         state->dr.in.num_addrs       = state->r.out.num_addrs;
     920           2 :         state->dr.in.addrs   = talloc_array(state,
     921             :                                                struct nbtd_proxy_wins_addr,
     922             :                                                state->dr.in.num_addrs);
     923           2 :         NT_STATUS_HAVE_NO_MEMORY(state->dr.in.addrs);
     924             :         /* TODO: fix pidl to handle inline ipv4address arrays */
     925           4 :         for (i=0; i < state->dr.in.num_addrs; i++) {
     926           2 :                 state->dr.in.addrs[i].addr = state->r.out.addrs[i].addr;
     927             :         }
     928             : 
     929           2 :         subreq = dcerpc_nbtd_proxy_wins_release_demand_r_send(state,
     930           2 :                         state->partner->service->task->event_ctx,
     931             :                         state->irpc_handle,
     932             :                         &state->dr);
     933           2 :         NT_STATUS_HAVE_NO_MEMORY(subreq);
     934             : 
     935           2 :         tevent_req_set_callback(subreq, r_do_late_release_demand_handler, state);
     936             : 
     937           2 :         return NT_STATUS_OK;
     938             : }
     939             : 
     940             : /* 
     941             : Test Replica vs. owned active: some more MHOMED combinations
     942             : _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
     943             : _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
     944             : _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
     945             : _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
     946             : _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
     947             : _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
     948             : _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
     949             : Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
     950             : _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
     951             : _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
     952             : _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
     953             : _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
     954             : */
     955          21 : static void r_do_challenge_handler(struct tevent_req *subreq)
     956             : {
     957           0 :         NTSTATUS status;
     958           0 :         struct r_do_challenge_state *state =
     959          21 :                 tevent_req_callback_data(subreq,
     960             :                 struct r_do_challenge_state);
     961          21 :         bool old_is_subset = false;
     962          21 :         bool new_is_subset = false;
     963          21 :         bool found = false;
     964           0 :         uint32_t i,j;
     965           0 :         uint32_t num_rec_addrs;
     966             : 
     967          21 :         status = dcerpc_nbtd_proxy_wins_challenge_r_recv(subreq, state);
     968          21 :         TALLOC_FREE(subreq);
     969             : 
     970          21 :         DEBUG(4,("r_do_challenge_handler: %s: %s\n", 
     971             :                  nbt_name_string(state, &state->replica.name), nt_errstr(status)));
     972             : 
     973          21 :         if (NT_STATUS_EQUAL(NT_STATUS_IO_TIMEOUT, status) ||
     974          21 :             NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
     975           5 :                 r_do_replace(state->partner, state, state->rec, &state->owner, &state->replica);
     976           5 :                 talloc_free(state);
     977           5 :                 return;
     978             :         }
     979             : 
     980          23 :         for (i=0; i < state->replica.num_addresses; i++) {
     981          16 :                 found = false;
     982          16 :                 new_is_subset = true;
     983          32 :                 for (j=0; j < state->r.out.num_addrs; j++) {
     984          23 :                         if (strcmp(state->replica.addresses[i].address, state->r.out.addrs[j].addr) == 0) {
     985           7 :                                 found = true;
     986           7 :                                 break;
     987             :                         }
     988             :                 }
     989          16 :                 if (found) continue;
     990             : 
     991           9 :                 new_is_subset = false;
     992           9 :                 break;
     993             :         }
     994             : 
     995          16 :         if (!new_is_subset) {
     996           9 :                 r_not_replace(state->partner, state, state->rec, &state->owner, &state->replica);
     997           9 :                 talloc_free(state);
     998           9 :                 return;
     999             :         }
    1000             : 
    1001           7 :         num_rec_addrs = winsdb_addr_list_length(state->rec->addresses);
    1002          16 :         for (i=0; i < num_rec_addrs; i++) {
    1003          11 :                 found = false;
    1004          11 :                 old_is_subset = true;
    1005          16 :                 for (j=0; j < state->r.out.num_addrs; j++) {
    1006          14 :                         if (strcmp(state->rec->addresses[i]->address, state->r.out.addrs[j].addr) == 0) {
    1007           9 :                                 found = true;
    1008           9 :                                 break;
    1009             :                         }
    1010             :                 }
    1011          11 :                 if (found) continue;
    1012             : 
    1013           2 :                 old_is_subset = false;
    1014           2 :                 break;
    1015             :         }
    1016             : 
    1017           7 :         if (!old_is_subset) {
    1018           2 :                 status = r_do_late_release_demand(state);
    1019             :                 /* 
    1020             :                  * only free state on error, because we pass it down,
    1021             :                  * and r_do_late_release_demand() will free it
    1022             :                  */
    1023           2 :                 if (!NT_STATUS_IS_OK(status)) {
    1024           0 :                         talloc_free(state);
    1025             :                 }
    1026           2 :                 return;
    1027             :         }
    1028             : 
    1029           5 :         r_do_mhomed_merge(state->partner, state, state->rec, &state->owner, &state->replica);
    1030           5 :         talloc_free(state);
    1031             : }
    1032             : 
    1033          21 : static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner,
    1034             :                                TALLOC_CTX *mem_ctx,
    1035             :                                struct winsdb_record *rec,
    1036             :                                struct wrepl_wins_owner *owner,
    1037             :                                struct wrepl_name *replica)
    1038             : {
    1039           0 :         struct r_do_challenge_state *state;
    1040           0 :         struct tevent_req *subreq;
    1041           0 :         const char **addrs;
    1042           0 :         uint32_t i;
    1043             : 
    1044          21 :         DEBUG(4,("challenge record %s\n",
    1045             :                  nbt_name_string(mem_ctx, &replica->name)));
    1046             : 
    1047          21 :         state = talloc_zero(mem_ctx, struct r_do_challenge_state);
    1048          21 :         NT_STATUS_HAVE_NO_MEMORY(state);
    1049          21 :         state->partner       = partner;
    1050          21 :         state->rec   = talloc_steal(state, rec);
    1051          21 :         state->owner = *owner;
    1052          21 :         state->replica       = *replica;
    1053             :         /* some stuff to have valid memory pointers in the async complete function */
    1054          21 :         state->replica.name = *state->rec->name;
    1055          21 :         talloc_steal(state, replica->owner);
    1056          21 :         talloc_steal(state, replica->addresses);
    1057             : 
    1058          42 :         state->irpc_handle = irpc_binding_handle_by_name(state,
    1059          21 :                                                          partner->service->task->msg_ctx,
    1060             :                                                          "nbt_server",
    1061             :                                                          &ndr_table_irpc);
    1062          21 :         if (state->irpc_handle == NULL) {
    1063           0 :                 return NT_STATUS_INTERNAL_ERROR;
    1064             :         }
    1065             : 
    1066          21 :         state->r.in.name     = *rec->name;
    1067          21 :         state->r.in.num_addrs        = winsdb_addr_list_length(rec->addresses);
    1068          21 :         state->r.in.addrs    = talloc_array(state, struct nbtd_proxy_wins_addr, state->r.in.num_addrs);
    1069          21 :         NT_STATUS_HAVE_NO_MEMORY(state->r.in.addrs);
    1070             :         /* TODO: fix pidl to handle inline ipv4address arrays */
    1071          21 :         addrs                   = winsdb_addr_string_list(state->r.in.addrs, rec->addresses);
    1072          21 :         NT_STATUS_HAVE_NO_MEMORY(addrs);
    1073          48 :         for (i=0; i < state->r.in.num_addrs; i++) {
    1074          27 :                 state->r.in.addrs[i].addr = addrs[i];
    1075             :         }
    1076             : 
    1077          21 :         subreq = dcerpc_nbtd_proxy_wins_challenge_r_send(state,
    1078          21 :                         state->partner->service->task->event_ctx,
    1079             :                         state->irpc_handle,
    1080             :                         &state->r);
    1081          21 :         NT_STATUS_HAVE_NO_MEMORY(subreq);
    1082             : 
    1083          21 :         tevent_req_set_callback(subreq, r_do_challenge_handler, state);
    1084             : 
    1085          21 :         talloc_steal(partner, state);
    1086          21 :         return NT_STATUS_OK;
    1087             : }
    1088             : 
    1089             : struct r_do_release_demand_state {
    1090             :         struct nbtd_proxy_wins_release_demand r;
    1091             : };
    1092             : 
    1093           8 : static void r_do_release_demand_handler(struct tevent_req *subreq)
    1094             : {
    1095           0 :         NTSTATUS status;
    1096           0 :         struct r_do_release_demand_state *state =
    1097           8 :                 tevent_req_callback_data(subreq,
    1098             :                 struct r_do_release_demand_state);
    1099             : 
    1100           8 :         status = dcerpc_nbtd_proxy_wins_release_demand_r_recv(subreq, state);
    1101           8 :         TALLOC_FREE(subreq);
    1102             : 
    1103             :         /* don't care about the result */
    1104           0 :         (void)status;
    1105           8 :         talloc_free(state);
    1106           8 : }
    1107             : 
    1108           8 : static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner,
    1109             :                                     TALLOC_CTX *mem_ctx,
    1110             :                                     struct winsdb_record *rec,
    1111             :                                     struct wrepl_wins_owner *owner,
    1112             :                                     struct wrepl_name *replica)
    1113             : {
    1114           0 :         NTSTATUS status;
    1115           0 :         struct dcerpc_binding_handle *irpc_handle;
    1116           0 :         const char **addrs;
    1117           0 :         struct winsdb_addr **addresses;
    1118           0 :         struct r_do_release_demand_state *state;
    1119           0 :         struct tevent_req *subreq;
    1120           0 :         uint32_t i;
    1121             : 
    1122             :         /*
    1123             :          * we need to get a reference to the old addresses,
    1124             :          * as we need to send a release demand to them after replacing the record
    1125             :          * and r_do_replace() will modify rec->addresses
    1126             :          */
    1127           8 :         addresses = rec->addresses;
    1128             : 
    1129           8 :         status = r_do_replace(partner, mem_ctx, rec, owner, replica);
    1130           8 :         NT_STATUS_NOT_OK_RETURN(status);
    1131             : 
    1132           8 :         DEBUG(4,("release demand record %s\n",
    1133             :                  nbt_name_string(mem_ctx, &replica->name)));
    1134             : 
    1135           8 :         state = talloc_zero(mem_ctx, struct r_do_release_demand_state);
    1136           8 :         NT_STATUS_HAVE_NO_MEMORY(state);
    1137             : 
    1138           8 :         irpc_handle = irpc_binding_handle_by_name(state,
    1139           8 :                                                   partner->service->task->msg_ctx,
    1140             :                                                   "nbt_server",
    1141             :                                                   &ndr_table_irpc);
    1142           8 :         if (irpc_handle == NULL) {
    1143           0 :                 return NT_STATUS_INTERNAL_ERROR;
    1144             :         }
    1145             : 
    1146           8 :         state->r.in.name     = *rec->name;
    1147           8 :         state->r.in.num_addrs        = winsdb_addr_list_length(addresses);
    1148           8 :         state->r.in.addrs    = talloc_array(state, struct nbtd_proxy_wins_addr,
    1149             :                                                state->r.in.num_addrs);
    1150           8 :         NT_STATUS_HAVE_NO_MEMORY(state->r.in.addrs);
    1151             :         /* TODO: fix pidl to handle inline ipv4address arrays */
    1152           8 :         addrs                   = winsdb_addr_string_list(state->r.in.addrs, addresses);
    1153           8 :         NT_STATUS_HAVE_NO_MEMORY(addrs);
    1154          16 :         for (i=0; i < state->r.in.num_addrs; i++) {
    1155           8 :                 state->r.in.addrs[i].addr = addrs[i];
    1156             :         }
    1157             : 
    1158           8 :         subreq = dcerpc_nbtd_proxy_wins_release_demand_r_send(state,
    1159           8 :                         partner->service->task->event_ctx,
    1160             :                         irpc_handle,
    1161             :                         &state->r);
    1162           8 :         NT_STATUS_HAVE_NO_MEMORY(subreq);
    1163             : 
    1164           8 :         tevent_req_set_callback(subreq, r_do_release_demand_handler, state);
    1165             : 
    1166           8 :         talloc_steal(partner, state);
    1167           8 :         return NT_STATUS_OK;
    1168             : }
    1169             : 
    1170             : /*
    1171             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
    1172             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
    1173             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
    1174             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
    1175             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
    1176             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
    1177             : 
    1178             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
    1179             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4_X_3_4 => SGROUP_MERGE
    1180             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
    1181             : 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
    1182             : 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
    1183             : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
    1184             : 
    1185             : Test Replica vs. owned active: SGROUP vs. SGROUP tests
    1186             : _SA_SA_DI_U<1c> => SGROUP_MERGE
    1187             : _SA_SA_SI_U<1c> => SGROUP_MERGE
    1188             : _SA_SA_SP_U<1c> => SGROUP_MERGE
    1189             : _SA_SA_SB_U<1c> => SGROUP_MERGE
    1190             : */
    1191          23 : static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner,
    1192             :                                   TALLOC_CTX *mem_ctx,
    1193             :                                   struct winsdb_record *rec,
    1194             :                                   struct wrepl_wins_owner *owner,
    1195             :                                   struct wrepl_name *replica)
    1196             : {
    1197           0 :         struct winsdb_record *merge;
    1198          23 :         uint32_t modify_flags = 0;
    1199           0 :         uint32_t i,j;
    1200           0 :         uint8_t ret;
    1201           0 :         size_t len;
    1202          23 :         bool changed_old_addrs = false;
    1203          23 :         bool skip_replica_owned_by_us = false;
    1204          23 :         bool become_owner = true;
    1205          23 :         bool propagate = lpcfg_parm_bool(partner->service->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false);
    1206          23 :         const char *local_owner = partner->service->wins_db->local_owner;
    1207             : 
    1208          23 :         merge = talloc(mem_ctx, struct winsdb_record);
    1209          23 :         NT_STATUS_HAVE_NO_MEMORY(merge);
    1210             : 
    1211          23 :         merge->name          = &replica->name;
    1212          23 :         merge->type          = replica->type;
    1213          23 :         merge->state         = replica->state;
    1214          23 :         merge->node          = replica->node;
    1215          23 :         merge->is_static     = replica->is_static;
    1216          23 :         merge->expire_time   = time(NULL) + partner->service->config.verify_interval;
    1217          23 :         merge->version               = replica->version_id;
    1218          23 :         merge->wins_owner    = replica->owner;
    1219          23 :         merge->addresses     = winsdb_addr_list_make(merge);
    1220          23 :         NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
    1221          23 :         merge->registered_by = NULL;
    1222             : 
    1223          23 :         len = winsdb_addr_list_length(rec->addresses);
    1224             : 
    1225          91 :         for (i=0; i < len; i++) {
    1226          68 :                 bool found = false;
    1227             : 
    1228         109 :                 for (j=0; j < replica->num_addresses; j++) {
    1229          50 :                         if (strcmp(rec->addresses[i]->address, replica->addresses[j].address) != 0) {
    1230          41 :                                 continue;
    1231             :                         }
    1232             : 
    1233           9 :                         found = true;
    1234             : 
    1235           9 :                         if (strcmp(rec->addresses[i]->wins_owner, replica->addresses[j].owner) != 0) {
    1236           7 :                                 changed_old_addrs = true;
    1237           7 :                                 break;
    1238             :                         }
    1239           2 :                         break;
    1240             :                 }
    1241             : 
    1242             :                 /* 
    1243             :                  * if the address isn't in the replica and is owned by replicas owner,
    1244             :                  * it won't be added to the merged record
    1245             :                  */
    1246          68 :                 if (!found && strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) {
    1247          34 :                         changed_old_addrs = true;
    1248          34 :                         continue;
    1249             :                 }
    1250             : 
    1251             :                 /*
    1252             :                  * add the address to the merge result, with the old owner and expire_time,
    1253             :                  * the owner and expire_time will be overwritten later if the address is
    1254             :                  * in the replica too
    1255             :                  */
    1256          68 :                 merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
    1257             :                                                         merge, merge->addresses,
    1258          34 :                                                         rec->addresses[i]->address,
    1259          34 :                                                         rec->addresses[i]->wins_owner,
    1260          34 :                                                         rec->addresses[i]->expire_time,
    1261             :                                                         false);
    1262          34 :                 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
    1263             :         }
    1264             : 
    1265          48 :         for (i=0; i < replica->num_addresses; i++) {
    1266          25 :                 if (propagate &&
    1267           0 :                     strcmp(replica->addresses[i].owner, local_owner) == 0) {
    1268           0 :                         const struct winsdb_addr *a;
    1269             : 
    1270             :                         /*
    1271             :                          * NOTE: this is different to the windows behavior
    1272             :                          *       and off by default, but it better propagated
    1273             :                          *       name releases
    1274             :                          */
    1275           0 :                         a = winsdb_addr_list_check(merge->addresses,
    1276           0 :                                                    replica->addresses[i].address);
    1277           0 :                         if (!a) {
    1278             :                                 /* don't add addresses owned by us */
    1279           0 :                                 skip_replica_owned_by_us = true;
    1280             :                         }
    1281           0 :                         continue;
    1282             :                 }
    1283          50 :                 merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
    1284             :                                                         merge, merge->addresses,
    1285          25 :                                                         replica->addresses[i].address,
    1286          25 :                                                         replica->addresses[i].owner,
    1287             :                                                         merge->expire_time,
    1288             :                                                         false);
    1289          25 :                 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
    1290             :         }
    1291             : 
    1292             :         /* we the old addresses change changed we don't become the owner */
    1293          23 :         if (changed_old_addrs) {
    1294          19 :                 become_owner = false;
    1295             :         }
    1296             : 
    1297             :         /*
    1298             :          * when we notice another server believes an address
    1299             :          * is owned by us and that's not the case
    1300             :          * we propagate the result
    1301             :          */
    1302          23 :         if (skip_replica_owned_by_us) {
    1303           0 :                 become_owner = true;
    1304             :         }
    1305             : 
    1306             :         /* if we're the owner of the old record, we'll be the owner of the new one too */
    1307          23 :         if (strcmp(rec->wins_owner, local_owner)==0) {
    1308          12 :                 become_owner = true;
    1309             :         }
    1310             : 
    1311             :         /*
    1312             :          * if the result has no addresses we take the ownership
    1313             :          */
    1314          23 :         len = winsdb_addr_list_length(merge->addresses);
    1315          23 :         if (len == 0) {
    1316           8 :                 become_owner = true;
    1317             :         }
    1318             : 
    1319             :         /* 
    1320             :          * if addresses of the old record will be changed the replica owner
    1321             :          * will be owner of the merge result, otherwise we take the ownership
    1322             :          */
    1323          23 :         if (become_owner) {
    1324          18 :                 time_t lh = 0;
    1325             : 
    1326          18 :                 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
    1327             : 
    1328             :                 /*
    1329             :                  * if we're the owner, the expire time becomes the highest
    1330             :                  * expire time of owned addresses
    1331             :                  */
    1332          18 :                 len = winsdb_addr_list_length(merge->addresses);
    1333             : 
    1334          54 :                 for (i=0; i < len; i++) {
    1335          36 :                         if (strcmp(merge->addresses[i]->wins_owner, local_owner)==0) {
    1336           3 :                                 lh = MAX(lh, merge->addresses[i]->expire_time);
    1337             :                         }
    1338             :                 }
    1339             : 
    1340          18 :                 if (lh != 0) {
    1341           2 :                         merge->expire_time = lh;
    1342             :                 }
    1343             :         }
    1344             : 
    1345          23 :         ret = winsdb_modify(partner->service->wins_db, merge, modify_flags);
    1346          23 :         if (ret != NBT_RCODE_OK) {
    1347           0 :                 DEBUG(0,("Failed to modify sgroup merge record %s: %u\n",
    1348             :                         nbt_name_string(mem_ctx, &replica->name), ret));
    1349           0 :                 return NT_STATUS_FOOBAR;
    1350             :         }
    1351             : 
    1352          23 :         DEBUG(4,("sgroup merge record %s\n",
    1353             :                 nbt_name_string(mem_ctx, &replica->name)));
    1354             : 
    1355          23 :         return NT_STATUS_OK;
    1356             : }
    1357             : 
    1358         675 : static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
    1359             :                                           TALLOC_CTX *mem_ctx,
    1360             :                                           struct wrepl_wins_owner *owner,
    1361             :                                           struct wrepl_name *replica)
    1362             : {
    1363           0 :         NTSTATUS status;
    1364         675 :         struct winsdb_record *rec = NULL;
    1365         675 :         enum _R_ACTION action = R_INVALID;
    1366         675 :         bool same_owner = false;
    1367         675 :         bool replica_vs_replica = false;
    1368         675 :         bool local_vs_replica = false;
    1369             : 
    1370         675 :         if (replica->name.scope) {
    1371           0 :                 TALLOC_CTX *parent;
    1372           0 :                 const char *scope;
    1373             : 
    1374             :                 /*
    1375             :                  * Windows 2008 truncates the scope to 237 bytes,
    1376             :                  * so we do...
    1377             :                  */
    1378         132 :                 parent = talloc_parent(replica->name.scope);
    1379         132 :                 scope = talloc_strndup(parent, replica->name.scope, 237);
    1380         132 :                 NT_STATUS_HAVE_NO_MEMORY(scope);
    1381         132 :                 replica->name.scope = scope;
    1382             :         }
    1383             : 
    1384         675 :         status = winsdb_lookup(partner->service->wins_db,
    1385         675 :                                &replica->name, mem_ctx, &rec);
    1386         675 :         if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
    1387          13 :                 return r_do_add(partner, mem_ctx, owner, replica);
    1388             :         }
    1389         662 :         NT_STATUS_NOT_OK_RETURN(status);
    1390             : 
    1391         662 :         if (strcmp(rec->wins_owner, partner->service->wins_db->local_owner)==0) {
    1392         171 :                 local_vs_replica = true;
    1393         491 :         } else if (strcmp(rec->wins_owner, owner->address)==0) {
    1394         350 :                 same_owner = true;
    1395             :         } else {
    1396         141 :                 replica_vs_replica = true;
    1397             :         }
    1398             : 
    1399         662 :         if (rec->is_static && !same_owner) {
    1400           0 :                 action = R_NOT_REPLACE;
    1401             : 
    1402             :                 /*
    1403             :                  * if we own the local record, then propagate it back to
    1404             :                  * the other wins servers.
    1405             :                  * to prevent ping-pong with other servers, we don't do this
    1406             :                  * if the replica is static too.
    1407             :                  *
    1408             :                  * It seems that w2k3 doesn't do this, but I thing that's a bug
    1409             :                  * and doing propagation helps to have consistent data on all servers
    1410             :                  */
    1411           0 :                 if (local_vs_replica && !replica->is_static) {
    1412           0 :                         action = R_DO_PROPAGATE;
    1413             :                 }
    1414         662 :         } else if (replica->is_static && !rec->is_static && !same_owner) {
    1415           0 :                 action = R_DO_REPLACE;
    1416         662 :         } else if (same_owner) {
    1417         350 :                 action = replace_same_owner(rec, replica);
    1418         312 :         } else if (replica_vs_replica) {
    1419         141 :                 switch (rec->type) {
    1420          28 :                 case WREPL_TYPE_UNIQUE:
    1421          28 :                         action = replace_unique_replica_vs_X_replica(rec, replica);
    1422          28 :                         break;
    1423          25 :                 case WREPL_TYPE_GROUP:
    1424          25 :                         action = replace_group_replica_vs_X_replica(rec, replica);
    1425          25 :                         break;
    1426          63 :                 case WREPL_TYPE_SGROUP:
    1427          63 :                         action = replace_sgroup_replica_vs_X_replica(rec, replica);
    1428          63 :                         break;
    1429          25 :                 case WREPL_TYPE_MHOMED:
    1430          25 :                         action = replace_mhomed_replica_vs_X_replica(rec, replica);
    1431          25 :                         break;
    1432             :                 }
    1433         171 :         } else if (local_vs_replica) {
    1434         171 :                 switch (rec->type) {
    1435          40 :                 case WREPL_TYPE_UNIQUE:
    1436          40 :                         action = replace_unique_owned_vs_X_replica(rec, replica);
    1437          40 :                         break;
    1438          32 :                 case WREPL_TYPE_GROUP:
    1439          32 :                         action = replace_group_owned_vs_X_replica(rec, replica);
    1440          32 :                         break;
    1441          54 :                 case WREPL_TYPE_SGROUP:
    1442          54 :                         action = replace_sgroup_owned_vs_X_replica(rec, replica);
    1443          54 :                         break;
    1444          45 :                 case WREPL_TYPE_MHOMED:
    1445          45 :                         action = replace_mhomed_owned_vs_X_replica(rec, replica);
    1446          45 :                         break;
    1447             :                 }
    1448             :         }
    1449             : 
    1450         662 :         DEBUG(4,("apply record %s: %s\n",
    1451             :                  nbt_name_string(mem_ctx, &replica->name), _R_ACTION_enum_string(action)));
    1452             : 
    1453         662 :         switch (action) {
    1454           0 :         case R_INVALID: break;
    1455         513 :         case R_DO_REPLACE:
    1456         513 :                 return r_do_replace(partner, mem_ctx, rec, owner, replica);
    1457          39 :         case R_NOT_REPLACE:
    1458          39 :                 return r_not_replace(partner, mem_ctx, rec, owner, replica);
    1459          58 :         case R_DO_PROPAGATE:
    1460          58 :                 return r_do_propagate(partner, mem_ctx, rec, owner, replica);
    1461          21 :         case R_DO_CHALLENGE:
    1462          21 :                 return r_do_challenge(partner, mem_ctx, rec, owner, replica);
    1463           8 :         case R_DO_RELEASE_DEMAND:
    1464           8 :                 return r_do_release_demand(partner, mem_ctx, rec, owner, replica);
    1465          23 :         case R_DO_SGROUP_MERGE:
    1466          23 :                 return r_do_sgroup_merge(partner, mem_ctx, rec, owner, replica);
    1467             :         }
    1468             : 
    1469           0 :         return NT_STATUS_INTERNAL_ERROR;
    1470             : }
    1471             : 
    1472         675 : NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner,
    1473             :                                 struct wrepl_wins_owner *owner,
    1474             :                                 uint32_t num_names, struct wrepl_name *names)
    1475             : {
    1476           0 :         NTSTATUS status;
    1477           0 :         uint32_t i;
    1478             : 
    1479         675 :         DEBUG(4,("apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
    1480             :                 num_names, owner->address,
    1481             :                 (long long)owner->min_version, 
    1482             :                 (long long)owner->max_version,
    1483             :                 partner->address));
    1484             : 
    1485        1350 :         for (i=0; i < num_names; i++) {
    1486         675 :                 TALLOC_CTX *tmp_mem = talloc_new(partner);
    1487         675 :                 NT_STATUS_HAVE_NO_MEMORY(tmp_mem);
    1488             : 
    1489         675 :                 status = wreplsrv_apply_one_record(partner, tmp_mem,
    1490         675 :                                                    owner, &names[i]);
    1491         675 :                 talloc_free(tmp_mem);
    1492         675 :                 NT_STATUS_NOT_OK_RETURN(status);
    1493             :         }
    1494             : 
    1495         675 :         status = wreplsrv_add_table(partner->service,
    1496         675 :                                     partner->service,
    1497         675 :                                     &partner->service->table,
    1498             :                                     owner->address,
    1499             :                                     owner->max_version);
    1500         675 :         NT_STATUS_NOT_OK_RETURN(status);
    1501             : 
    1502         675 :         return NT_STATUS_OK;
    1503             : }

Generated by: LCOV version 1.14