root/source4/wrepl_server/wrepl_apply_records.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _R_ACTION_enum_string
  2. replace_same_owner
  3. r_1_is_subset_of_2_address_list
  4. r_1_is_superset_of_2_address_list
  5. r_1_is_same_as_2_address_list
  6. r_contains_addrs_from_owner
  7. replace_unique_replica_vs_X_replica
  8. replace_group_replica_vs_X_replica
  9. replace_sgroup_replica_vs_X_replica
  10. replace_mhomed_replica_vs_X_replica
  11. replace_unique_owned_vs_X_replica
  12. replace_group_owned_vs_X_replica
  13. replace_sgroup_owned_vs_X_replica
  14. replace_mhomed_owned_vs_X_replica
  15. r_do_add
  16. r_do_replace
  17. r_not_replace
  18. r_do_propagate
  19. r_do_mhomed_merge
  20. r_do_late_release_demand_handler
  21. r_do_late_release_demand
  22. r_do_challenge_handler
  23. r_do_challenge
  24. r_do_release_demand_handler
  25. r_do_release_demand
  26. r_do_sgroup_merge
  27. wreplsrv_apply_one_record
  28. wreplsrv_apply_records

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

/* [<][>][^][v][top][bottom][index][help] */