2 Unix SMB/CIFS implementation.
4 WINS Replication server
6 Copyright (C) Stefan Metzmacher 2005
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "smbd/service_task.h"
25 #include "lib/messaging/irpc.h"
26 #include "librpc/gen_ndr/ndr_irpc.h"
27 #include "librpc/gen_ndr/ndr_winsrepl.h"
28 #include "wrepl_server/wrepl_server.h"
29 #include "nbt_server/wins/winsdb.h"
30 #include "libcli/wrepl/winsrepl.h"
31 #include "system/time.h"
43 static const char *_R_ACTION_enum_string(enum _R_ACTION action)
46 case R_INVALID: return "INVALID";
47 case R_DO_REPLACE: return "REPLACE";
48 case R_NOT_REPLACE: return "NOT_REPLACE";
49 case R_DO_PROPAGATE: return "PROPAGATE";
50 case R_DO_CHALLENGE: return "CHALLEGNE";
51 case R_DO_RELEASE_DEMAND: return "RELEASE_DEMAND";
52 case R_DO_SGROUP_MERGE: return "SGROUP_MERGE";
55 return "enum _R_ACTION unknown";
58 #define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
59 #define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
60 #define R_IS_TOMBSTONE(r) ((r)->state == WREPL_STATE_TOMBSTONE)
62 #define R_IS_UNIQUE(r) ((r)->type == WREPL_TYPE_UNIQUE)
63 #define R_IS_GROUP(r) ((r)->type == WREPL_TYPE_GROUP)
64 #define R_IS_SGROUP(r) ((r)->type == WREPL_TYPE_SGROUP)
65 #define R_IS_MHOMED(r) ((r)->type == WREPL_TYPE_MHOMED)
67 /* blindly overwrite records from the same owner in all cases */
68 static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_name *r2)
74 static BOOL r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
77 size_t len = winsdb_addr_list_length(r1->addresses);
79 for (i=0; i < len; i++) {
81 for (j=0; j < r2->num_addresses; j++) {
82 if (strcmp(r1->addresses[i]->address, r2->addresses[j].address) != 0) {
86 if (check_owners && strcmp(r1->addresses[i]->wins_owner, r2->addresses[j].owner) != 0) {
92 if (!found) return False;
98 static BOOL r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
101 size_t len = winsdb_addr_list_length(r1->addresses);
103 for (i=0; i < r2->num_addresses; i++) {
105 for (j=0; j < len; j++) {
106 if (strcmp(r2->addresses[i].address, r1->addresses[j]->address) != 0) {
110 if (check_owners && strcmp(r2->addresses[i].owner, r1->addresses[j]->wins_owner) != 0) {
116 if (!found) return False;
122 static BOOL r_1_is_same_as_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
124 size_t len = winsdb_addr_list_length(r1->addresses);
126 if (len != r2->num_addresses) {
130 return r_1_is_superset_of_2_address_list(r1, r2, check_owners);
133 static BOOL r_contains_addrs_from_owner(struct winsdb_record *r1, const char *owner)
136 size_t len = winsdb_addr_list_length(r1->addresses);
138 for (i=0; i < len; i++) {
139 if (strcmp(r1->addresses[i]->wins_owner, owner) == 0) {
148 UNIQUE,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
149 UNIQUE,ACTIVE vs. UNIQUE,TOMBSTONE with different ip(s) => NOT REPLACE
150 UNIQUE,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
151 UNIQUE,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
152 UNIQUE,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
153 UNIQUE,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
154 UNIQUE,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
155 UNIQUE,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
156 UNIQUE,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
157 UNIQUE,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
158 UNIQUE,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
159 UNIQUE,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
160 UNIQUE,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
161 UNIQUE,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
162 UNIQUE,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
163 UNIQUE,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
164 UNIQUE,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
165 UNIQUE,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
166 UNIQUE,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
167 UNIQUE,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
168 UNIQUE,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
169 UNIQUE,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
170 UNIQUE,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
171 UNIQUE,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
173 static enum _R_ACTION replace_unique_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
175 if (!R_IS_ACTIVE(r1)) {
180 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
186 return R_NOT_REPLACE;
190 GROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
191 GROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
192 GROUP,RELEASED vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
193 GROUP,RELEASED vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
194 GROUP,TOMBSTONE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
195 GROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
196 GROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
197 GROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
198 GROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
199 GROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
200 GROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
201 GROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
202 GROUP,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
203 GROUP,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
204 GROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
205 GROUP,RELEASED vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
206 GROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
207 GROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
208 GROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
209 GROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
210 GROUP,RELEASED vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
211 GROUP,RELEASED vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
212 GROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
213 GROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
215 static enum _R_ACTION replace_group_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
217 if (!R_IS_ACTIVE(r1) && R_IS_GROUP(r2)) {
222 if (R_IS_TOMBSTONE(r1) && !R_IS_UNIQUE(r2)) {
228 return R_NOT_REPLACE;
232 SGROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
233 SGROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
234 SGROUP,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
235 SGROUP,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
236 SGROUP,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
237 SGROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
238 SGROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
239 SGROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
240 SGROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
241 SGROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
242 SGROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
243 SGROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
244 SGROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
245 SGROUP,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
246 SGROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
247 SGROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
248 SGROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
249 SGROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
250 SGROUP,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
251 SGROUP,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
252 SGROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
253 SGROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
255 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
256 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
257 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
258 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
259 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
260 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
262 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
263 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
264 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
265 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
266 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
267 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
270 this is a bit strange, incoming tombstone replicas always replace old replicas:
272 SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:NULL => B:NULL => REPLACE
273 SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4 => REPLACE
274 SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:B_3_4 => B:B_3_4 => REPLACE
275 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
277 static enum _R_ACTION replace_sgroup_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
279 if (!R_IS_ACTIVE(r1)) {
284 if (!R_IS_SGROUP(r2)) {
286 return R_NOT_REPLACE;
290 * this is strange, but correct
291 * the incoming tombstone replace the current active
294 if (!R_IS_ACTIVE(r2)) {
299 if (r2->num_addresses == 0) {
300 if (r_contains_addrs_from_owner(r1, r2->owner)) {
301 /* not handled here: MERGE */
302 return R_DO_SGROUP_MERGE;
306 return R_NOT_REPLACE;
309 if (r_1_is_superset_of_2_address_list(r1, r2, True)) {
311 return R_NOT_REPLACE;
314 if (r_1_is_same_as_2_address_list(r1, r2, False)) {
319 /* not handled here: MERGE */
320 return R_DO_SGROUP_MERGE;
324 MHOMED,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
325 MHOMED,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
326 MHOMED,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
327 MHOMED,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
328 MHOMED,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
329 MHOMED,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
330 MHOMED,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
331 MHOMED,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
332 MHOMED,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
333 MHOMED,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
334 MHOMED,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
335 MHOMED,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
336 MHOMED,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
337 MHOMED,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
338 MHOMED,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
339 MHOMED,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
340 MHOMED,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
341 MHOMED,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
342 MHOMED,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
343 MHOMED,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
344 MHOMED,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
345 MHOMED,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
346 MHOMED,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
347 MHOMED,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
349 static enum _R_ACTION replace_mhomed_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
351 if (!R_IS_ACTIVE(r1)) {
356 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
362 return R_NOT_REPLACE;
367 _UA_UA_SI_U<00> => REPLACE
368 _UA_UA_DI_P<00> => NOT REPLACE
369 _UA_UA_DI_O<00> => NOT REPLACE
370 _UA_UA_DI_N<00> => REPLACE
371 _UA_UT_SI_U<00> => NOT REPLACE
372 _UA_UT_DI_U<00> => NOT REPLACE
373 _UA_GA_SI_R<00> => REPLACE
374 _UA_GA_DI_R<00> => REPLACE
375 _UA_GT_SI_U<00> => NOT REPLACE
376 _UA_GT_DI_U<00> => NOT REPLACE
377 _UA_SA_SI_R<00> => REPLACE
378 _UA_SA_DI_R<00> => REPLACE
379 _UA_ST_SI_U<00> => NOT REPLACE
380 _UA_ST_DI_U<00> => NOT REPLACE
381 _UA_MA_SI_U<00> => REPLACE
382 _UA_MA_SP_U<00> => REPLACE
383 _UA_MA_DI_P<00> => NOT REPLACE
384 _UA_MA_DI_O<00> => NOT REPLACE
385 _UA_MA_DI_N<00> => REPLACE
386 _UA_MT_SI_U<00> => NOT REPLACE
387 _UA_MT_DI_U<00> => NOT REPLACE
388 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
389 _UA_UA_DI_A<00> => MHOMED_MERGE
390 _UA_MA_DI_A<00> => MHOMED_MERGE
393 _UR_UA_SI<00> => REPLACE
394 _UR_UA_DI<00> => REPLACE
395 _UR_UT_SI<00> => REPLACE
396 _UR_UT_DI<00> => REPLACE
397 _UR_GA_SI<00> => REPLACE
398 _UR_GA_DI<00> => REPLACE
399 _UR_GT_SI<00> => REPLACE
400 _UR_GT_DI<00> => REPLACE
401 _UR_SA_SI<00> => REPLACE
402 _UR_SA_DI<00> => REPLACE
403 _UR_ST_SI<00> => REPLACE
404 _UR_ST_DI<00> => REPLACE
405 _UR_MA_SI<00> => REPLACE
406 _UR_MA_DI<00> => REPLACE
407 _UR_MT_SI<00> => REPLACE
408 _UR_MT_DI<00> => REPLACE
410 static enum _R_ACTION replace_unique_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
412 if (!R_IS_ACTIVE(r1)) {
417 if (!R_IS_ACTIVE(r2)) {
419 return R_NOT_REPLACE;
422 if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
423 /* REPLACE and send a release demand to the old name owner */
424 return R_DO_RELEASE_DEMAND;
428 * here we only have unique,active,owned vs.
429 * is unique,active,replica or mhomed,active,replica
432 if (r_1_is_subset_of_2_address_list(r1, r2, False)) {
434 * if r1 has a subset(or same) of the addresses of r2
436 * if r2 has a superset(or same) of the addresses of r1
438 * then replace the record
444 * in any other case, we need to do
445 * a name request to the old name holder
446 * to see if it's still there...
448 return R_DO_CHALLENGE;
453 _GA_UA_SI_U<00> => NOT REPLACE
454 _GA_UA_DI_U<00> => NOT REPLACE
455 _GA_UT_SI_U<00> => NOT REPLACE
456 _GA_UT_DI_U<00> => NOT REPLACE
457 _GA_GA_SI_U<00> => REPLACE
458 _GA_GA_DI_U<00> => REPLACE
459 _GA_GT_SI_U<00> => NOT REPLACE
460 _GA_GT_DI_U<00> => NOT REPLACE
461 _GA_SA_SI_U<00> => NOT REPLACE
462 _GA_SA_DI_U<00> => NOT REPLACE
463 _GA_ST_SI_U<00> => NOT REPLACE
464 _GA_ST_DI_U<00> => NOT REPLACE
465 _GA_MA_SI_U<00> => NOT REPLACE
466 _GA_MA_DI_U<00> => NOT REPLACE
467 _GA_MT_SI_U<00> => NOT REPLACE
468 _GA_MT_DI_U<00> => NOT REPLACE
471 _GR_UA_SI<00> => NOT REPLACE
472 _GR_UA_DI<00> => NOT REPLACE
473 _GR_UT_SI<00> => NOT REPLACE
474 _GR_UT_DI<00> => NOT REPLACE
475 _GR_GA_SI<00> => REPLACE
476 _GR_GA_DI<00> => REPLACE
477 _GR_GT_SI<00> => REPLACE
478 _GR_GT_DI<00> => REPLACE
479 _GR_SA_SI<00> => NOT REPLACE
480 _GR_SA_DI<00> => NOT REPLACE
481 _GR_ST_SI<00> => NOT REPLACE
482 _GR_ST_DI<00> => NOT REPLACE
483 _GR_MA_SI<00> => NOT REPLACE
484 _GR_MA_DI<00> => NOT REPLACE
485 _GR_MT_SI<00> => NOT REPLACE
486 _GR_MT_DI<00> => NOT REPLACE
488 static enum _R_ACTION replace_group_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
490 if (R_IS_GROUP(r1) && R_IS_GROUP(r2)) {
491 if (!R_IS_ACTIVE(r1) || R_IS_ACTIVE(r2)) {
498 return R_NOT_REPLACE;
502 active (not sgroup vs. sgroup yet!):
503 _SA_UA_SI_U<1c> => NOT REPLACE
504 _SA_UA_DI_U<1c> => NOT REPLACE
505 _SA_UT_SI_U<1c> => NOT REPLACE
506 _SA_UT_DI_U<1c> => NOT REPLACE
507 _SA_GA_SI_U<1c> => NOT REPLACE
508 _SA_GA_DI_U<1c> => NOT REPLACE
509 _SA_GT_SI_U<1c> => NOT REPLACE
510 _SA_GT_DI_U<1c> => NOT REPLACE
511 _SA_MA_SI_U<1c> => NOT REPLACE
512 _SA_MA_DI_U<1c> => NOT REPLACE
513 _SA_MT_SI_U<1c> => NOT REPLACE
514 _SA_MT_DI_U<1c> => NOT REPLACE
516 Test Replica vs. owned active: SGROUP vs. SGROUP tests
517 _SA_SA_DI_U<1c> => SGROUP_MERGE
518 _SA_SA_SI_U<1c> => SGROUP_MERGE
519 _SA_SA_SP_U<1c> => SGROUP_MERGE
520 _SA_SA_SB_U<1c> => SGROUP_MERGE
521 _SA_ST_DI_U<1c> => NOT REPLACE
522 _SA_ST_SI_U<1c> => NOT REPLACE
523 _SA_ST_SP_U<1c> => NOT REPLACE
524 _SA_ST_SB_U<1c> => NOT REPLACE
526 SGROUP,ACTIVE vs. SGROUP,* is not handled here!
529 _SR_UA_SI<1c> => REPLACE
530 _SR_UA_DI<1c> => REPLACE
531 _SR_UT_SI<1c> => REPLACE
532 _SR_UT_DI<1c> => REPLACE
533 _SR_GA_SI<1c> => REPLACE
534 _SR_GA_DI<1c> => REPLACE
535 _SR_GT_SI<1c> => REPLACE
536 _SR_GT_DI<1c> => REPLACE
537 _SR_SA_SI<1c> => REPLACE
538 _SR_SA_DI<1c> => REPLACE
539 _SR_ST_SI<1c> => REPLACE
540 _SR_ST_DI<1c> => REPLACE
541 _SR_MA_SI<1c> => REPLACE
542 _SR_MA_DI<1c> => REPLACE
543 _SR_MT_SI<1c> => REPLACE
544 _SR_MT_DI<1c> => REPLACE
546 static enum _R_ACTION replace_sgroup_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
548 if (!R_IS_ACTIVE(r1)) {
553 if (!R_IS_SGROUP(r2) || !R_IS_ACTIVE(r2)) {
555 return R_NOT_REPLACE;
559 * TODO: should we have the same logic here like in
560 * replace_sgroup_replica_vs_X_replica() ?
563 /* not handled here: MERGE */
564 return R_DO_SGROUP_MERGE;
569 _MA_UA_SI_U<00> => REPLACE
570 _MA_UA_DI_P<00> => NOT REPLACE
571 _MA_UA_DI_O<00> => NOT REPLACE
572 _MA_UA_DI_N<00> => REPLACE
573 _MA_UT_SI_U<00> => NOT REPLACE
574 _MA_UT_DI_U<00> => NOT REPLACE
575 _MA_GA_SI_R<00> => REPLACE
576 _MA_GA_DI_R<00> => REPLACE
577 _MA_GT_SI_U<00> => NOT REPLACE
578 _MA_GT_DI_U<00> => NOT REPLACE
579 _MA_SA_SI_R<00> => REPLACE
580 _MA_SA_DI_R<00> => REPLACE
581 _MA_ST_SI_U<00> => NOT REPLACE
582 _MA_ST_DI_U<00> => NOT REPLACE
583 _MA_MA_SI_U<00> => REPLACE
584 _MA_MA_SP_U<00> => REPLACE
585 _MA_MA_DI_P<00> => NOT REPLACE
586 _MA_MA_DI_O<00> => NOT REPLACE
587 _MA_MA_DI_N<00> => REPLACE
588 _MA_MT_SI_U<00> => NOT REPLACE
589 _MA_MT_DI_U<00> => NOT REPLACE
590 Test Replica vs. owned active: some more MHOMED combinations
591 _MA_MA_SP_U<00> => REPLACE
592 _MA_MA_SM_U<00> => REPLACE
593 _MA_MA_SB_P<00> => MHOMED_MERGE
594 _MA_MA_SB_A<00> => MHOMED_MERGE
595 _MA_MA_SB_PRA<00> => NOT REPLACE
596 _MA_MA_SB_O<00> => NOT REPLACE
597 _MA_MA_SB_N<00> => REPLACE
598 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
599 _MA_UA_SB_P<00> => MHOMED_MERGE
602 _MR_UA_SI<00> => REPLACE
603 _MR_UA_DI<00> => REPLACE
604 _MR_UT_SI<00> => REPLACE
605 _MR_UT_DI<00> => REPLACE
606 _MR_GA_SI<00> => REPLACE
607 _MR_GA_DI<00> => REPLACE
608 _MR_GT_SI<00> => REPLACE
609 _MR_GT_DI<00> => REPLACE
610 _MR_SA_SI<00> => REPLACE
611 _MR_SA_DI<00> => REPLACE
612 _MR_ST_SI<00> => REPLACE
613 _MR_ST_DI<00> => REPLACE
614 _MR_MA_SI<00> => REPLACE
615 _MR_MA_DI<00> => REPLACE
616 _MR_MT_SI<00> => REPLACE
617 _MR_MT_DI<00> => REPLACE
619 static enum _R_ACTION replace_mhomed_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
621 if (!R_IS_ACTIVE(r1)) {
626 if (!R_IS_ACTIVE(r2)) {
628 return R_NOT_REPLACE;
631 if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
632 /* REPLACE and send a release demand to the old name owner */
633 return R_DO_RELEASE_DEMAND;
637 * here we only have mhomed,active,owned vs.
638 * is unique,active,replica or mhomed,active,replica
641 if (r_1_is_subset_of_2_address_list(r1, r2, False)) {
643 * if r1 has a subset(or same) of the addresses of r2
645 * if r2 has a superset(or same) of the addresses of r1
647 * then replace the record
653 * in any other case, we need to do
654 * a name request to the old name holder
655 * to see if it's still there...
657 return R_DO_CHALLENGE;
660 static NTSTATUS r_do_add(struct wreplsrv_partner *partner,
662 struct wrepl_wins_owner *owner,
663 struct wrepl_name *replica)
665 struct winsdb_record *rec;
669 rec = talloc(mem_ctx, struct winsdb_record);
670 NT_STATUS_HAVE_NO_MEMORY(rec);
672 rec->name = &replica->name;
673 rec->type = replica->type;
674 rec->state = replica->state;
675 rec->node = replica->node;
676 rec->is_static = replica->is_static;
677 rec->expire_time= time(NULL) + partner->service->config.verify_interval;
678 rec->version = replica->version_id;
679 rec->wins_owner = replica->owner;
680 rec->addresses = winsdb_addr_list_make(rec);
681 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
682 rec->registered_by = NULL;
684 for (i=0; i < replica->num_addresses; i++) {
685 /* TODO: find out if rec->expire_time is correct here */
686 rec->addresses = winsdb_addr_list_add(rec->addresses,
687 replica->addresses[i].address,
688 replica->addresses[i].owner,
690 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
693 ret = winsdb_add(partner->service->wins_db, rec, 0);
694 if (ret != NBT_RCODE_OK) {
695 DEBUG(0,("Failed to add record %s: %u\n",
696 nbt_name_string(mem_ctx, &replica->name), ret));
697 return NT_STATUS_FOOBAR;
700 DEBUG(4,("added record %s\n",
701 nbt_name_string(mem_ctx, &replica->name)));
706 static NTSTATUS r_do_replace(struct wreplsrv_partner *partner,
708 struct winsdb_record *rec,
709 struct wrepl_wins_owner *owner,
710 struct wrepl_name *replica)
715 rec->name = &replica->name;
716 rec->type = replica->type;
717 rec->state = replica->state;
718 rec->node = replica->node;
719 rec->is_static = replica->is_static;
720 rec->expire_time= time(NULL) + partner->service->config.verify_interval;
721 rec->version = replica->version_id;
722 rec->wins_owner = replica->owner;
723 rec->addresses = winsdb_addr_list_make(rec);
724 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
725 rec->registered_by = NULL;
727 for (i=0; i < replica->num_addresses; i++) {
728 /* TODO: find out if rec->expire_time is correct here */
729 rec->addresses = winsdb_addr_list_add(rec->addresses,
730 replica->addresses[i].address,
731 replica->addresses[i].owner,
733 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
736 ret = winsdb_modify(partner->service->wins_db, rec, 0);
737 if (ret != NBT_RCODE_OK) {
738 DEBUG(0,("Failed to replace record %s: %u\n",
739 nbt_name_string(mem_ctx, &replica->name), ret));
740 return NT_STATUS_FOOBAR;
743 DEBUG(4,("replaced record %s\n",
744 nbt_name_string(mem_ctx, &replica->name)));
749 static NTSTATUS r_not_replace(struct wreplsrv_partner *partner,
751 struct winsdb_record *rec,
752 struct wrepl_wins_owner *owner,
753 struct wrepl_name *replica)
755 DEBUG(4,("not replace record %s\n",
756 nbt_name_string(mem_ctx, &replica->name)));
760 static NTSTATUS r_do_propagate(struct wreplsrv_partner *partner,
762 struct winsdb_record *rec,
763 struct wrepl_wins_owner *owner,
764 struct wrepl_name *replica)
767 uint32_t modify_flags;
770 * allocate a new version id for the record to that it'll be replicated
772 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
774 ret = winsdb_modify(partner->service->wins_db, rec, modify_flags);
775 if (ret != NBT_RCODE_OK) {
776 DEBUG(0,("Failed to replace record %s: %u\n",
777 nbt_name_string(mem_ctx, &replica->name), ret));
778 return NT_STATUS_FOOBAR;
781 DEBUG(4,("propagated record %s\n",
782 nbt_name_string(mem_ctx, &replica->name)));
788 Test Replica vs. owned active: some more MHOMED combinations
789 _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
790 _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
791 _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
792 _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
793 _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
794 _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
795 _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
796 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
797 _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
798 _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
799 _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
800 _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
802 static NTSTATUS r_do_mhomed_merge(struct wreplsrv_partner *partner,
804 struct winsdb_record *rec,
805 struct wrepl_wins_owner *owner,
806 struct wrepl_name *replica)
808 struct winsdb_record *merge;
813 merge = talloc(mem_ctx, struct winsdb_record);
814 NT_STATUS_HAVE_NO_MEMORY(merge);
816 merge->name = &replica->name;
817 merge->type = WREPL_TYPE_MHOMED;
818 merge->state = replica->state;
819 merge->node = replica->node;
820 merge->is_static = replica->is_static;
821 merge->expire_time = time(NULL) + partner->service->config.verify_interval;
822 merge->version = replica->version_id;
823 merge->wins_owner = replica->owner;
824 merge->addresses = winsdb_addr_list_make(merge);
825 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
826 merge->registered_by = NULL;
828 for (i=0; i < replica->num_addresses; i++) {
829 /* TODO: find out if rec->expire_time is correct here */
830 merge->addresses = winsdb_addr_list_add(merge->addresses,
831 replica->addresses[i].address,
832 replica->addresses[i].owner,
834 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
837 len = winsdb_addr_list_length(rec->addresses);
839 for (i=0; i < len; i++) {
841 for (j=0; j < replica->num_addresses; j++) {
842 if (strcmp(replica->addresses[j].address, rec->addresses[i]->address) == 0) {
849 /* TODO: find out if rec->expire_time is correct here */
850 merge->addresses = winsdb_addr_list_add(merge->addresses,
851 rec->addresses[i]->address,
852 rec->addresses[i]->wins_owner,
854 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
857 ret = winsdb_modify(partner->service->wins_db, merge, 0);
858 if (ret != NBT_RCODE_OK) {
859 DEBUG(0,("Failed to modify mhomed merge record %s: %u\n",
860 nbt_name_string(mem_ctx, &replica->name), ret));
861 return NT_STATUS_FOOBAR;
864 DEBUG(4,("mhomed merge record %s\n",
865 nbt_name_string(mem_ctx, &replica->name)));
870 struct r_do_challenge_state {
871 struct messaging_context *msg_ctx;
872 struct wreplsrv_partner *partner;
873 struct winsdb_record *rec;
874 struct wrepl_wins_owner owner;
875 struct wrepl_name replica;
876 struct nbtd_proxy_wins_challenge r;
879 static void r_do_late_release_demand_handler(struct irpc_request *ireq)
882 struct r_do_challenge_state *state = talloc_get_type(ireq->async.private,
883 struct r_do_challenge_state);
885 status = irpc_call_recv(ireq);
886 /* don't care about the result */
890 static NTSTATUS r_do_late_release_demand(struct r_do_challenge_state *state)
892 struct irpc_request *ireq;
893 uint32_t *nbt_servers;
894 struct nbtd_proxy_wins_release_demand r;
897 DEBUG(4,("late release demand record %s\n",
898 nbt_name_string(state, &state->replica.name)));
900 nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server");
901 if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
902 return NT_STATUS_INTERNAL_ERROR;
905 r.in.name = state->replica.name;
906 r.in.num_addrs = state->r.out.num_addrs;
907 r.in.addrs = talloc_array(state, struct nbtd_proxy_wins_addr, r.in.num_addrs);
908 NT_STATUS_HAVE_NO_MEMORY(r.in.addrs);
909 /* TODO: fix pidl to handle inline ipv4address arrays */
910 for (i=0; i < r.in.num_addrs; i++) {
911 r.in.addrs[i].addr = state->r.out.addrs[i].addr;
914 ireq = IRPC_CALL_SEND(state->msg_ctx, nbt_servers[0],
915 irpc, NBTD_PROXY_WINS_RELEASE_DEMAND,
917 NT_STATUS_HAVE_NO_MEMORY(ireq);
919 ireq->async.fn = r_do_late_release_demand_handler;
920 ireq->async.private = state;
926 Test Replica vs. owned active: some more MHOMED combinations
927 _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
928 _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
929 _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
930 _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
931 _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
932 _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
933 _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
934 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
935 _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
936 _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
937 _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
938 _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
940 static void r_do_challenge_handler(struct irpc_request *ireq)
943 struct r_do_challenge_state *state = talloc_get_type(ireq->async.private,
944 struct r_do_challenge_state);
945 BOOL old_is_subset = False;
946 BOOL new_is_subset = False;
949 uint32_t num_rec_addrs;
951 status = irpc_call_recv(ireq);
953 DEBUG(4,("r_do_challenge_handler: %s: %s\n",
954 nbt_name_string(state, &state->replica.name), nt_errstr(status)));
956 if (NT_STATUS_EQUAL(NT_STATUS_IO_TIMEOUT, status) ||
957 NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
958 r_do_replace(state->partner, state, state->rec, &state->owner, &state->replica);
963 for (i=0; i < state->replica.num_addresses; i++) {
965 new_is_subset = True;
966 for (j=0; j < state->r.out.num_addrs; j++) {
967 if (strcmp(state->replica.addresses[i].address, state->r.out.addrs[j].addr) == 0) {
974 new_is_subset = False;
978 if (!new_is_subset) {
979 r_not_replace(state->partner, state, state->rec, &state->owner, &state->replica);
984 num_rec_addrs = winsdb_addr_list_length(state->rec->addresses);
985 for (i=0; i < num_rec_addrs; i++) {
987 old_is_subset = True;
988 for (j=0; j < state->r.out.num_addrs; j++) {
989 if (strcmp(state->rec->addresses[i]->address, state->r.out.addrs[j].addr) == 0) {
996 old_is_subset = False;
1000 if (!old_is_subset) {
1001 r_do_late_release_demand(state);
1003 * don't free state here, because we pass it down,
1004 * and r_do_late_release_demand() will free it
1009 r_do_mhomed_merge(state->partner, state, state->rec, &state->owner, &state->replica);
1013 static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner,
1014 TALLOC_CTX *mem_ctx,
1015 struct winsdb_record *rec,
1016 struct wrepl_wins_owner *owner,
1017 struct wrepl_name *replica)
1019 struct irpc_request *ireq;
1020 struct r_do_challenge_state *state;
1021 uint32_t *nbt_servers;
1025 DEBUG(4,("challenge record %s\n",
1026 nbt_name_string(mem_ctx, &replica->name)));
1028 state = talloc_zero(mem_ctx, struct r_do_challenge_state);
1029 NT_STATUS_HAVE_NO_MEMORY(state);
1030 state->msg_ctx = partner->service->task->msg_ctx;
1031 state->partner = partner;
1032 state->rec = talloc_steal(state, rec);
1033 state->owner = *owner;
1034 state->replica = *replica;
1035 /* some stuff to have valid memory pointers in the async complete function */
1036 state->replica.name = *state->rec->name;
1037 talloc_steal(state, replica->owner);
1038 talloc_steal(state, replica->addresses);
1040 nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server");
1041 if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
1042 return NT_STATUS_INTERNAL_ERROR;
1045 state->r.in.name = *rec->name;
1046 state->r.in.num_addrs = winsdb_addr_list_length(rec->addresses);
1047 state->r.in.addrs = talloc_array(state, struct nbtd_proxy_wins_addr, state->r.in.num_addrs);
1048 NT_STATUS_HAVE_NO_MEMORY(state->r.in.addrs);
1049 /* TODO: fix pidl to handle inline ipv4address arrays */
1050 addrs = winsdb_addr_string_list(state->r.in.addrs, rec->addresses);
1051 NT_STATUS_HAVE_NO_MEMORY(addrs);
1052 for (i=0; i < state->r.in.num_addrs; i++) {
1053 state->r.in.addrs[i].addr = addrs[i];
1056 ireq = IRPC_CALL_SEND(state->msg_ctx, nbt_servers[0],
1057 irpc, NBTD_PROXY_WINS_CHALLENGE,
1059 NT_STATUS_HAVE_NO_MEMORY(ireq);
1061 ireq->async.fn = r_do_challenge_handler;
1062 ireq->async.private = state;
1064 talloc_steal(partner, state);
1065 return NT_STATUS_OK;
1068 static void r_do_release_demand_handler(struct irpc_request *ireq)
1071 status = irpc_call_recv(ireq);
1072 /* don't care about the result */
1075 static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner,
1076 TALLOC_CTX *mem_ctx,
1077 struct winsdb_record *rec,
1078 struct wrepl_wins_owner *owner,
1079 struct wrepl_name *replica)
1082 struct irpc_request *ireq;
1083 uint32_t *nbt_servers;
1085 struct winsdb_addr **addresses;
1086 struct nbtd_proxy_wins_release_demand r;
1090 * we need to get a reference to the old addresses,
1091 * as we need to send a release demand to them after replacing the record
1092 * and r_do_replace() will modify rec->addresses
1094 addresses = rec->addresses;
1096 status = r_do_replace(partner, mem_ctx, rec, owner, replica);
1097 NT_STATUS_NOT_OK_RETURN(status);
1099 DEBUG(4,("release demand record %s\n",
1100 nbt_name_string(mem_ctx, &replica->name)));
1102 nbt_servers = irpc_servers_byname(partner->service->task->msg_ctx, "nbt_server");
1103 if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
1104 return NT_STATUS_INTERNAL_ERROR;
1107 r.in.name = *rec->name;
1108 r.in.num_addrs = winsdb_addr_list_length(addresses);
1109 r.in.addrs = talloc_array(partner, struct nbtd_proxy_wins_addr, r.in.num_addrs);
1110 NT_STATUS_HAVE_NO_MEMORY(r.in.addrs);
1111 /* TODO: fix pidl to handle inline ipv4address arrays */
1112 addrs = winsdb_addr_string_list(r.in.addrs, addresses);
1113 NT_STATUS_HAVE_NO_MEMORY(addrs);
1114 for (i=0; i < r.in.num_addrs; i++) {
1115 r.in.addrs[i].addr = addrs[i];
1118 ireq = IRPC_CALL_SEND(partner->service->task->msg_ctx, nbt_servers[0],
1119 irpc, NBTD_PROXY_WINS_RELEASE_DEMAND,
1121 NT_STATUS_HAVE_NO_MEMORY(ireq);
1123 ireq->async.fn = r_do_release_demand_handler;
1124 ireq->async.private = NULL;
1126 return NT_STATUS_OK;
1130 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
1131 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
1132 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
1133 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
1134 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
1135 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
1137 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
1138 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
1139 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
1140 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
1141 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
1142 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
1144 Test Replica vs. owned active: SGROUP vs. SGROUP tests
1145 _SA_SA_DI_U<1c> => SGROUP_MERGE
1146 _SA_SA_SI_U<1c> => SGROUP_MERGE
1147 _SA_SA_SP_U<1c> => SGROUP_MERGE
1148 _SA_SA_SB_U<1c> => SGROUP_MERGE
1150 static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner,
1151 TALLOC_CTX *mem_ctx,
1152 struct winsdb_record *rec,
1153 struct wrepl_wins_owner *owner,
1154 struct wrepl_name *replica)
1156 struct winsdb_record *merge;
1157 uint32_t modify_flags = 0;
1161 BOOL changed_old_addrs = False;
1162 BOOL become_owner = True;
1164 merge = talloc(mem_ctx, struct winsdb_record);
1165 NT_STATUS_HAVE_NO_MEMORY(merge);
1167 merge->name = &replica->name;
1168 merge->type = replica->type;
1169 merge->state = replica->state;
1170 merge->node = replica->node;
1171 merge->is_static = replica->is_static;
1172 merge->expire_time = time(NULL) + partner->service->config.verify_interval;
1173 merge->version = replica->version_id;
1174 merge->wins_owner = replica->owner;
1175 merge->addresses = winsdb_addr_list_make(merge);
1176 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
1177 merge->registered_by = NULL;
1179 len = winsdb_addr_list_length(rec->addresses);
1181 for (i=0; i < len; i++) {
1184 for (j=0; j < replica->num_addresses; j++) {
1185 if (strcmp(rec->addresses[i]->address, replica->addresses[j].address) != 0) {
1191 if (strcmp(rec->addresses[i]->wins_owner, replica->addresses[j].owner) != 0) {
1192 changed_old_addrs = True;
1198 /* if it's also in the replica, it'll added later */
1199 if (found) continue;
1202 * if the address isn't in the replica and is owned by replicas owner,
1203 * it won't be added to the merged record
1205 if (strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) {
1206 changed_old_addrs = True;
1211 * add the address to the merge result, with the old owner and expire_time
1213 merge->addresses = winsdb_addr_list_add(merge->addresses,
1214 rec->addresses[i]->address,
1215 rec->addresses[i]->wins_owner,
1216 rec->addresses[i]->expire_time);
1217 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
1220 for (i=0; i < replica->num_addresses; i++) {
1221 /* TODO: find out if rec->expire_time is correct here */
1222 merge->addresses = winsdb_addr_list_add(merge->addresses,
1223 replica->addresses[i].address,
1224 replica->addresses[i].owner,
1225 merge->expire_time);
1226 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
1229 /* we the old addresses change changed we don't become the owner */
1230 if (changed_old_addrs) {
1231 become_owner = False;
1234 /* if we're the owner of the old record, we'll be the owner of the new one too */
1235 if (strcmp(rec->wins_owner, partner->service->wins_db->local_owner)==0) {
1236 become_owner = True;
1240 * if the result has no addresses we take the ownership
1242 len = winsdb_addr_list_length(merge->addresses);
1244 become_owner = True;
1248 * if addresses of the old record will be changed the replica owner
1249 * will be owner of the merge result, otherwise we take the ownership
1252 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
1255 ret = winsdb_modify(partner->service->wins_db, merge, modify_flags);
1256 if (ret != NBT_RCODE_OK) {
1257 DEBUG(0,("Failed to modify sgroup merge record %s: %u\n",
1258 nbt_name_string(mem_ctx, &replica->name), ret));
1259 return NT_STATUS_FOOBAR;
1262 DEBUG(4,("sgroup merge record %s\n",
1263 nbt_name_string(mem_ctx, &replica->name)));
1265 return NT_STATUS_OK;
1268 static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
1269 TALLOC_CTX *mem_ctx,
1270 struct wrepl_wins_owner *owner,
1271 struct wrepl_name *replica)
1274 struct winsdb_record *rec = NULL;
1275 enum _R_ACTION action = R_INVALID;
1276 BOOL same_owner = False;
1277 BOOL replica_vs_replica = False;
1278 BOOL local_vs_replica = False;
1280 status = winsdb_lookup(partner->service->wins_db,
1281 &replica->name, mem_ctx, &rec);
1282 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
1283 return r_do_add(partner, mem_ctx, owner, replica);
1285 NT_STATUS_NOT_OK_RETURN(status);
1287 if (strcmp(rec->wins_owner, partner->service->wins_db->local_owner)==0) {
1288 local_vs_replica = True;
1289 } else if (strcmp(rec->wins_owner, owner->address)==0) {
1292 replica_vs_replica = True;
1295 if (rec->is_static && !same_owner) {
1296 action = R_NOT_REPLACE;
1299 * if we own the local record, then propagate it back to
1300 * the other wins servers.
1301 * to prevent ping-pong with other servers, we don't do this
1302 * if the replica is static too.
1304 * It seems that w2k3 doesn't do this, but I thing that's a bug
1305 * and doing propagation helps to have consistent data on all servers
1307 if (local_vs_replica && !replica->is_static) {
1308 action = R_DO_PROPAGATE;
1310 } else if (replica->is_static && !rec->is_static && !same_owner) {
1311 action = R_DO_REPLACE;
1312 } else if (same_owner) {
1313 action = replace_same_owner(rec, replica);
1314 } else if (replica_vs_replica) {
1315 switch (rec->type) {
1316 case WREPL_TYPE_UNIQUE:
1317 action = replace_unique_replica_vs_X_replica(rec, replica);
1319 case WREPL_TYPE_GROUP:
1320 action = replace_group_replica_vs_X_replica(rec, replica);
1322 case WREPL_TYPE_SGROUP:
1323 action = replace_sgroup_replica_vs_X_replica(rec, replica);
1325 case WREPL_TYPE_MHOMED:
1326 action = replace_mhomed_replica_vs_X_replica(rec, replica);
1329 } else if (local_vs_replica) {
1330 switch (rec->type) {
1331 case WREPL_TYPE_UNIQUE:
1332 action = replace_unique_owned_vs_X_replica(rec, replica);
1334 case WREPL_TYPE_GROUP:
1335 action = replace_group_owned_vs_X_replica(rec, replica);
1337 case WREPL_TYPE_SGROUP:
1338 action = replace_sgroup_owned_vs_X_replica(rec, replica);
1340 case WREPL_TYPE_MHOMED:
1341 action = replace_mhomed_owned_vs_X_replica(rec, replica);
1346 * if we own the local record, and it should not be replaced
1347 * then propagate the conflict result back to the other
1350 if (action == R_NOT_REPLACE) {
1351 action = R_DO_PROPAGATE;
1355 DEBUG(4,("apply record %s: %s\n",
1356 nbt_name_string(mem_ctx, &replica->name), _R_ACTION_enum_string(action)));
1359 case R_INVALID: break;
1361 return r_do_replace(partner, mem_ctx, rec, owner, replica);
1363 return r_not_replace(partner, mem_ctx, rec, owner, replica);
1364 case R_DO_PROPAGATE:
1365 return r_do_propagate(partner, mem_ctx, rec, owner, replica);
1366 case R_DO_CHALLENGE:
1367 return r_do_challenge(partner, mem_ctx, rec, owner, replica);
1368 case R_DO_RELEASE_DEMAND:
1369 return r_do_release_demand(partner, mem_ctx, rec, owner, replica);
1370 case R_DO_SGROUP_MERGE:
1371 return r_do_sgroup_merge(partner, mem_ctx, rec, owner, replica);
1374 return NT_STATUS_INTERNAL_ERROR;
1377 NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, struct wreplsrv_pull_names_io *names_io)
1382 DEBUG(4,("apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
1383 names_io->out.num_names, names_io->in.owner.address,
1384 (long long)names_io->in.owner.min_version,
1385 (long long)names_io->in.owner.max_version,
1388 for (i=0; i < names_io->out.num_names; i++) {
1389 TALLOC_CTX *tmp_mem = talloc_new(partner);
1390 NT_STATUS_HAVE_NO_MEMORY(tmp_mem);
1392 status = wreplsrv_apply_one_record(partner, tmp_mem,
1393 &names_io->in.owner,
1394 &names_io->out.names[i]);
1395 talloc_free(tmp_mem);
1396 NT_STATUS_NOT_OK_RETURN(status);
1399 status = wreplsrv_add_table(partner->service,
1401 &partner->service->table,
1402 names_io->in.owner.address,
1403 names_io->in.owner.max_version);
1404 NT_STATUS_NOT_OK_RETURN(status);
1406 return NT_STATUS_OK;