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 34enum _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 44static const char *_R_ACTION_enum_string(enum _R_ACTION action) 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 */ 73static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_name *r2) 74{ 75 /* REPLACE */ 76 return R_DO_REPLACE; 77} 78 79static bool r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners) 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 103static bool r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners) 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 127static bool r_1_is_same_as_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners) 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 138static bool r_contains_addrs_from_owner(struct winsdb_record *r1, const char *owner) 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/* 153UNIQUE,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE 154UNIQUE,ACTIVE vs. UNIQUE,TOMBSTONE with different ip(s) => NOT REPLACE 155UNIQUE,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE 156UNIQUE,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE 157UNIQUE,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE 158UNIQUE,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE 159UNIQUE,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE 160UNIQUE,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE 161UNIQUE,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE 162UNIQUE,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE 163UNIQUE,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE 164UNIQUE,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE 165UNIQUE,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE 166UNIQUE,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE 167UNIQUE,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE 168UNIQUE,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE 169UNIQUE,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE 170UNIQUE,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE 171UNIQUE,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE 172UNIQUE,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE 173UNIQUE,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE 174UNIQUE,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE 175UNIQUE,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE 176UNIQUE,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE 177*/ 178static enum _R_ACTION replace_unique_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2) 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/* 195GROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE 196GROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE 197GROUP,RELEASED vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE 198GROUP,RELEASED vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE 199GROUP,TOMBSTONE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE 200GROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE 201GROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE 202GROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE 203GROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE 204GROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE 205GROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE 206GROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE 207GROUP,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE 208GROUP,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE 209GROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE 210GROUP,RELEASED vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE 211GROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE 212GROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE 213GROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE 214GROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE 215GROUP,RELEASED vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE 216GROUP,RELEASED vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE 217GROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE 218GROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE 219*/ 220static enum _R_ACTION replace_group_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2) 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/* 237SGROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE 238SGROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE 239SGROUP,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE 240SGROUP,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE 241SGROUP,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE 242SGROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE 243SGROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE 244SGROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE 245SGROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE 246SGROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE 247SGROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE 248SGROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE 249SGROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE 250SGROUP,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE 251SGROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE 252SGROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE 253SGROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE 254SGROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE 255SGROUP,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE 256SGROUP,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE 257SGROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE 258SGROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE 259 260SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE 261SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE 262SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE 263SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE 264SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE 265SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE 266 267SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE 268SGROUP,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 269SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE 270SGROUP,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 271SGROUP,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 272SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE 273 274 275this is a bit strange, incoming tombstone replicas always replace old replicas: 276 277SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:NULL => B:NULL => REPLACE 278SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4 => REPLACE 279SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:B_3_4 => B:B_3_4 => REPLACE 280SGROUP,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*/ 282static enum _R_ACTION replace_sgroup_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2) 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/* 329MHOMED,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE 330MHOMED,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE 331MHOMED,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE 332MHOMED,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE 333MHOMED,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE 334MHOMED,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE 335MHOMED,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE 336MHOMED,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE 337MHOMED,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE 338MHOMED,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE 339MHOMED,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE 340MHOMED,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE 341MHOMED,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE 342MHOMED,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE 343MHOMED,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE 344MHOMED,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE 345MHOMED,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE 346MHOMED,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE 347MHOMED,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE 348MHOMED,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE 349MHOMED,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE 350MHOMED,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE 351MHOMED,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE 352MHOMED,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE 353*/ 354static enum _R_ACTION replace_mhomed_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2) 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/* 371active: 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 393Test 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 397released: 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*/ 415static enum _R_ACTION replace_unique_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2) 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/* 457active: 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 475released: 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*/ 493static enum _R_ACTION replace_group_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2) 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/* 507active (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 521Test 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 531SGROUP,ACTIVE vs. SGROUP,* is not handled here! 532 533released: 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*/ 551static enum _R_ACTION replace_sgroup_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2) 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/* 576active: 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 598Test 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 606Test Replica vs. owned active: some more UNIQUE,MHOMED combinations 607_MA_UA_SB_P<00> => MHOMED_MERGE 608 609released: 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*/ 627static enum _R_ACTION replace_mhomed_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2) 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 668static NTSTATUS r_do_add(struct wreplsrv_partner *partner, 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 716static NTSTATUS r_do_replace(struct wreplsrv_partner *partner, 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 761static NTSTATUS r_not_replace(struct wreplsrv_partner *partner, 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 772static NTSTATUS r_do_propagate(struct wreplsrv_partner *partner, 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/* 800Test 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 808Test 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*/ 814static NTSTATUS r_do_mhomed_merge(struct wreplsrv_partner *partner, 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 884struct 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 893static void r_do_late_release_demand_handler(struct irpc_request *ireq) 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 904static NTSTATUS r_do_late_release_demand(struct r_do_challenge_state *state) 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/* 940Test 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 948Test 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*/ 954static void r_do_challenge_handler(struct irpc_request *ireq) 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 1030static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner, 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 1085struct r_do_release_demand_state { 1086 struct messaging_context *msg_ctx; 1087 struct nbtd_proxy_wins_release_demand r; 1088}; 1089 1090static void r_do_release_demand_handler(struct irpc_request *ireq) 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 1101static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner, 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/* 1162SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE 1163SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE 1164SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE 1165SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE 1166SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE 1167SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE 1168 1169SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE 1170SGROUP,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 1171SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE 1172SGROUP,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 1173SGROUP,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 1174SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE 1175 1176Test 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*/ 1182static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner, 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 1349static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner, 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 1449NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, 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} 1481