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 "dlinklist.h"
25 #include "lib/events/events.h"
26 #include "lib/socket/socket.h"
27 #include "smbd/service_task.h"
28 #include "smbd/service_stream.h"
29 #include "lib/messaging/irpc.h"
30 #include "librpc/gen_ndr/ndr_winsrepl.h"
31 #include "wrepl_server/wrepl_server.h"
32 #include "wrepl_server/wrepl_out_helpers.h"
33 #include "nbt_server/wins/winsdb.h"
34 #include "ldb/include/ldb.h"
35 #include "libcli/composite/composite.h"
36 #include "libcli/wrepl/winsrepl.h"
37 #include "system/time.h"
48 static const char *_R_ACTION_enum_string(enum _R_ACTION action)
51 case R_INVALID: return "INVALID";
52 case R_DO_REPLACE: return "REPLACE";
53 case R_NOT_REPLACE: return "NOT_REPLACE";
54 case R_DO_CHALLENGE: return "CHALLEGNE";
55 case R_DO_RELEASE_DEMAND: return "RELEASE_DEMAND";
56 case R_DO_SGROUP_MERGE: return "SGROUP_MERGE";
59 return "enum _R_ACTION unknown";
62 #define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
63 #define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
64 #define R_IS_TOMBSTONE(r) ((r)->state == WREPL_STATE_TOMBSTONE)
66 #define R_IS_UNIQUE(r) ((r)->type == WREPL_TYPE_UNIQUE)
67 #define R_IS_GROUP(r) ((r)->type == WREPL_TYPE_GROUP)
68 #define R_IS_SGROUP(r) ((r)->type == WREPL_TYPE_SGROUP)
69 #define R_IS_MHOMED(r) ((r)->type == WREPL_TYPE_MHOMED)
71 /* blindly overwrite records from the same owner in all cases */
72 static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_name *r2)
78 static BOOL r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
81 size_t len = winsdb_addr_list_length(r1->addresses);
83 for (i=0; i < len; i++) {
85 for (j=0; j < r2->num_addresses; j++) {
86 if (strcmp(r1->addresses[i]->address, r2->addresses[j].address) != 0) {
90 if (check_owners && strcmp(r1->addresses[i]->wins_owner, r2->addresses[j].owner) != 0) {
96 if (!found) return False;
102 static BOOL r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
105 size_t len = winsdb_addr_list_length(r1->addresses);
107 for (i=0; i < r2->num_addresses; i++) {
109 for (j=0; j < len; j++) {
110 if (strcmp(r2->addresses[i].address, r1->addresses[j]->address) != 0) {
114 if (check_owners && strcmp(r2->addresses[i].owner, r1->addresses[j]->wins_owner) != 0) {
120 if (!found) return False;
126 static BOOL r_1_is_same_as_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
128 size_t len = winsdb_addr_list_length(r1->addresses);
130 if (len != r2->num_addresses) {
134 return r_1_is_superset_of_2_address_list(r1, r2, check_owners);
137 static BOOL r_contains_addrs_from_owner(struct winsdb_record *r1, const char *owner)
140 size_t len = winsdb_addr_list_length(r1->addresses);
142 for (i=0; i < len; i++) {
143 if (strcmp(r1->addresses[i]->wins_owner, owner) == 0) {
152 UNIQUE,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
153 UNIQUE,ACTIVE vs. UNIQUE,TOMBSTONE with different ip(s) => NOT REPLACE
154 UNIQUE,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
155 UNIQUE,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
156 UNIQUE,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
157 UNIQUE,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
158 UNIQUE,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
159 UNIQUE,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
160 UNIQUE,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
161 UNIQUE,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
162 UNIQUE,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
163 UNIQUE,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
164 UNIQUE,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
165 UNIQUE,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
166 UNIQUE,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
167 UNIQUE,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
168 UNIQUE,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
169 UNIQUE,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
170 UNIQUE,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
171 UNIQUE,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
172 UNIQUE,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
173 UNIQUE,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
174 UNIQUE,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
175 UNIQUE,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
177 static enum _R_ACTION replace_unique_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
179 if (!R_IS_ACTIVE(r1)) {
184 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
190 return R_NOT_REPLACE;
194 GROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
195 GROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
196 GROUP,RELEASED vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
197 GROUP,RELEASED vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
198 GROUP,TOMBSTONE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
199 GROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
200 GROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
201 GROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
202 GROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
203 GROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
204 GROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
205 GROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
206 GROUP,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
207 GROUP,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
208 GROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
209 GROUP,RELEASED vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
210 GROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
211 GROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
212 GROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
213 GROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
214 GROUP,RELEASED vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
215 GROUP,RELEASED vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
216 GROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
217 GROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
219 static enum _R_ACTION replace_group_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
221 if (!R_IS_ACTIVE(r1) && R_IS_GROUP(r2)) {
226 if (R_IS_TOMBSTONE(r1) && !R_IS_UNIQUE(r2)) {
232 return R_NOT_REPLACE;
236 SGROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
237 SGROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
238 SGROUP,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
239 SGROUP,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
240 SGROUP,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
241 SGROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
242 SGROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
243 SGROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
244 SGROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
245 SGROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
246 SGROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
247 SGROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
248 SGROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
249 SGROUP,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
250 SGROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
251 SGROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
252 SGROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
253 SGROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
254 SGROUP,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
255 SGROUP,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
256 SGROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
257 SGROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
259 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
260 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
261 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
262 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
263 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
264 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
266 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
267 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
268 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
269 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
270 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
271 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
273 static enum _R_ACTION replace_sgroup_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
275 if (!R_IS_ACTIVE(r1)) {
280 if (!R_IS_SGROUP(r2) || !R_IS_ACTIVE(r2)) {
282 return R_NOT_REPLACE;
285 if (r2->num_addresses == 0) {
286 if (r_contains_addrs_from_owner(r1, r2->owner)) {
287 /* not handled here: MERGE */
288 return R_DO_SGROUP_MERGE;
292 return R_NOT_REPLACE;
295 if (r_1_is_superset_of_2_address_list(r1, r2, True)) {
297 return R_NOT_REPLACE;
300 if (r_1_is_same_as_2_address_list(r1, r2, False)) {
305 /* not handled here: MERGE */
306 return R_DO_SGROUP_MERGE;
310 MHOMED,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
311 MHOMED,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
312 MHOMED,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
313 MHOMED,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
314 MHOMED,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
315 MHOMED,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
316 MHOMED,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
317 MHOMED,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
318 MHOMED,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
319 MHOMED,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
320 MHOMED,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
321 MHOMED,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
322 MHOMED,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
323 MHOMED,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
324 MHOMED,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
325 MHOMED,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
326 MHOMED,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
327 MHOMED,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
328 MHOMED,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
329 MHOMED,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
330 MHOMED,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
331 MHOMED,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
332 MHOMED,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
333 MHOMED,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
335 static enum _R_ACTION replace_mhomed_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
337 if (!R_IS_ACTIVE(r1)) {
342 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
348 return R_NOT_REPLACE;
353 _UA_UA_SI_U<00> => REPLACE
354 _UA_UA_DI_P<00> => NOT REPLACE
355 _UA_UA_DI_O<00> => NOT REPLACE
356 _UA_UA_DI_N<00> => REPLACE
357 _UA_UT_SI_U<00> => NOT REPLACE
358 _UA_UT_DI_U<00> => NOT REPLACE
359 _UA_GA_SI_R<00> => REPLACE
360 _UA_GA_DI_R<00> => REPLACE
361 _UA_GT_SI_U<00> => NOT REPLACE
362 _UA_GT_DI_U<00> => NOT REPLACE
363 _UA_SA_SI_R<00> => REPLACE
364 _UA_SA_DI_R<00> => REPLACE
365 _UA_ST_SI_U<00> => NOT REPLACE
366 _UA_ST_DI_U<00> => NOT REPLACE
367 _UA_MA_SI_U<00> => REPLACE
368 _UA_MA_SP_U<00> => REPLACE
369 _UA_MA_DI_P<00> => NOT REPLACE
370 _UA_MA_DI_O<00> => NOT REPLACE
371 _UA_MA_DI_N<00> => REPLACE
372 _UA_MT_SI_U<00> => NOT REPLACE
373 _UA_MT_DI_U<00> => NOT REPLACE
374 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
375 _UA_UA_DI_A<00> => MHOMED_MERGE
376 _UA_MA_DI_A<00> => MHOMED_MERGE
379 _UR_UA_SI<00> => REPLACE
380 _UR_UA_DI<00> => REPLACE
381 _UR_UT_SI<00> => REPLACE
382 _UR_UT_DI<00> => REPLACE
383 _UR_GA_SI<00> => REPLACE
384 _UR_GA_DI<00> => REPLACE
385 _UR_GT_SI<00> => REPLACE
386 _UR_GT_DI<00> => REPLACE
387 _UR_SA_SI<00> => REPLACE
388 _UR_SA_DI<00> => REPLACE
389 _UR_ST_SI<00> => REPLACE
390 _UR_ST_DI<00> => REPLACE
391 _UR_MA_SI<00> => REPLACE
392 _UR_MA_DI<00> => REPLACE
393 _UR_MT_SI<00> => REPLACE
394 _UR_MT_DI<00> => REPLACE
396 static enum _R_ACTION replace_unique_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
398 if (!R_IS_ACTIVE(r1)) {
403 if (!R_IS_ACTIVE(r2)) {
405 return R_NOT_REPLACE;
408 if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
409 /* REPLACE and send a release demand to the old name owner */
410 return R_DO_RELEASE_DEMAND;
414 * here we only have unique,active,owned vs.
415 * is unique,active,replica or mhomed,active,replica
418 if (r_1_is_subset_of_2_address_list(r1, r2, False)) {
420 * if r1 has a subset(or same) of the addresses of r2
422 * if r2 has a superset(or same) of the addresses of r1
424 * then replace the record
430 * in any other case, we need to do
431 * a name request to the old name holder
432 * to see if it's still there...
434 return R_DO_CHALLENGE;
439 _GA_UA_SI_U<00> => NOT REPLACE
440 _GA_UA_DI_U<00> => NOT REPLACE
441 _GA_UT_SI_U<00> => NOT REPLACE
442 _GA_UT_DI_U<00> => NOT REPLACE
443 _GA_GA_SI_U<00> => REPLACE
444 _GA_GA_DI_U<00> => REPLACE
445 _GA_GT_SI_U<00> => NOT REPLACE
446 _GA_GT_DI_U<00> => NOT REPLACE
447 _GA_SA_SI_U<00> => NOT REPLACE
448 _GA_SA_DI_U<00> => NOT REPLACE
449 _GA_ST_SI_U<00> => NOT REPLACE
450 _GA_ST_DI_U<00> => NOT REPLACE
451 _GA_MA_SI_U<00> => NOT REPLACE
452 _GA_MA_DI_U<00> => NOT REPLACE
453 _GA_MT_SI_U<00> => NOT REPLACE
454 _GA_MT_DI_U<00> => NOT REPLACE
457 _GR_UA_SI<00> => NOT REPLACE
458 _GR_UA_DI<00> => NOT REPLACE
459 _GR_UT_SI<00> => NOT REPLACE
460 _GR_UT_DI<00> => NOT REPLACE
461 _GR_GA_SI<00> => REPLACE
462 _GR_GA_DI<00> => REPLACE
463 _GR_GT_SI<00> => REPLACE
464 _GR_GT_DI<00> => REPLACE
465 _GR_SA_SI<00> => NOT REPLACE
466 _GR_SA_DI<00> => NOT REPLACE
467 _GR_ST_SI<00> => NOT REPLACE
468 _GR_ST_DI<00> => NOT REPLACE
469 _GR_MA_SI<00> => NOT REPLACE
470 _GR_MA_DI<00> => NOT REPLACE
471 _GR_MT_SI<00> => NOT REPLACE
472 _GR_MT_DI<00> => NOT REPLACE
474 static enum _R_ACTION replace_group_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
476 if (R_IS_GROUP(r1) && R_IS_GROUP(r2)) {
477 if (!R_IS_ACTIVE(r1) || R_IS_ACTIVE(r2)) {
484 return R_NOT_REPLACE;
488 active (not sgroup vs. sgroup yet!):
489 _SA_UA_SI_U<1c> => NOT REPLACE
490 _SA_UA_DI_U<1c> => NOT REPLACE
491 _SA_UT_SI_U<1c> => NOT REPLACE
492 _SA_UT_DI_U<1c> => NOT REPLACE
493 _SA_GA_SI_U<1c> => NOT REPLACE
494 _SA_GA_DI_U<1c> => NOT REPLACE
495 _SA_GT_SI_U<1c> => NOT REPLACE
496 _SA_GT_DI_U<1c> => NOT REPLACE
497 _SA_MA_SI_U<1c> => NOT REPLACE
498 _SA_MA_DI_U<1c> => NOT REPLACE
499 _SA_MT_SI_U<1c> => NOT REPLACE
500 _SA_MT_DI_U<1c> => NOT REPLACE
502 SGROUP,ACTIVE vs. SGROUP,* is not handled here!
505 _SR_UA_SI<1c> => REPLACE
506 _SR_UA_DI<1c> => REPLACE
507 _SR_UT_SI<1c> => REPLACE
508 _SR_UT_DI<1c> => REPLACE
509 _SR_GA_SI<1c> => REPLACE
510 _SR_GA_DI<1c> => REPLACE
511 _SR_GT_SI<1c> => REPLACE
512 _SR_GT_DI<1c> => REPLACE
513 _SR_SA_SI<1c> => REPLACE
514 _SR_SA_DI<1c> => REPLACE
515 _SR_ST_SI<1c> => REPLACE
516 _SR_ST_DI<1c> => REPLACE
517 _SR_MA_SI<1c> => REPLACE
518 _SR_MA_DI<1c> => REPLACE
519 _SR_MT_SI<1c> => REPLACE
520 _SR_MT_DI<1c> => REPLACE
522 static enum _R_ACTION replace_sgroup_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
524 if (!R_IS_ACTIVE(r1)) {
529 if (R_IS_SGROUP(r2)) {
530 /* not handled here: MERGE */
531 return R_DO_SGROUP_MERGE;
535 return R_NOT_REPLACE;
540 _MA_UA_SI_U<00> => REPLACE
541 _MA_UA_DI_P<00> => NOT REPLACE
542 _MA_UA_DI_O<00> => NOT REPLACE
543 _MA_UA_DI_N<00> => REPLACE
544 _MA_UT_SI_U<00> => NOT REPLACE
545 _MA_UT_DI_U<00> => NOT REPLACE
546 _MA_GA_SI_R<00> => REPLACE
547 _MA_GA_DI_R<00> => REPLACE
548 _MA_GT_SI_U<00> => NOT REPLACE
549 _MA_GT_DI_U<00> => NOT REPLACE
550 _MA_SA_SI_R<00> => REPLACE
551 _MA_SA_DI_R<00> => REPLACE
552 _MA_ST_SI_U<00> => NOT REPLACE
553 _MA_ST_DI_U<00> => NOT REPLACE
554 _MA_MA_SI_U<00> => REPLACE
555 _MA_MA_SP_U<00> => REPLACE
556 _MA_MA_DI_P<00> => NOT REPLACE
557 _MA_MA_DI_O<00> => NOT REPLACE
558 _MA_MA_DI_N<00> => REPLACE
559 _MA_MT_SI_U<00> => NOT REPLACE
560 _MA_MT_DI_U<00> => NOT REPLACE
561 Test Replica vs. owned active: some more MHOMED combinations
562 _MA_MA_SP_U<00> => REPLACE
563 _MA_MA_SM_U<00> => REPLACE
564 _MA_MA_SB_P<00> => MHOMED_MERGE
565 _MA_MA_SB_A<00> => MHOMED_MERGE
566 _MA_MA_SB_PRA<00> => NOT REPLACE
567 _MA_MA_SB_O<00> => NOT REPLACE
568 _MA_MA_SB_N<00> => REPLACE
569 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
570 _MA_UA_SB_P<00> => MHOMED_MERGE
573 _MR_UA_SI<00> => REPLACE
574 _MR_UA_DI<00> => REPLACE
575 _MR_UT_SI<00> => REPLACE
576 _MR_UT_DI<00> => REPLACE
577 _MR_GA_SI<00> => REPLACE
578 _MR_GA_DI<00> => REPLACE
579 _MR_GT_SI<00> => REPLACE
580 _MR_GT_DI<00> => REPLACE
581 _MR_SA_SI<00> => REPLACE
582 _MR_SA_DI<00> => REPLACE
583 _MR_ST_SI<00> => REPLACE
584 _MR_ST_DI<00> => REPLACE
585 _MR_MA_SI<00> => REPLACE
586 _MR_MA_DI<00> => REPLACE
587 _MR_MT_SI<00> => REPLACE
588 _MR_MT_DI<00> => REPLACE
590 static enum _R_ACTION replace_mhomed_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
592 if (!R_IS_ACTIVE(r1)) {
597 if (!R_IS_ACTIVE(r2)) {
599 return R_NOT_REPLACE;
602 if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
603 /* REPLACE and send a release demand to the old name owner */
604 return R_DO_RELEASE_DEMAND;
608 * here we only have mhomed,active,owned vs.
609 * is unique,active,replica or mhomed,active,replica
612 if (r_1_is_subset_of_2_address_list(r1, r2, False)) {
614 * if r1 has a subset(or same) of the addresses of r2
616 * if r2 has a superset(or same) of the addresses of r1
618 * then replace the record
624 * in any other case, we need to do
625 * a name request to the old name holder
626 * to see if it's still there...
628 return R_DO_CHALLENGE;
631 static NTSTATUS r_do_add(struct wreplsrv_partner *partner,
633 struct wrepl_wins_owner *owner,
634 struct wrepl_name *replica)
636 struct winsdb_record *rec;
640 rec = talloc(mem_ctx, struct winsdb_record);
641 NT_STATUS_HAVE_NO_MEMORY(rec);
643 rec->name = &replica->name;
644 rec->type = replica->type;
645 rec->state = replica->state;
646 rec->node = replica->node;
647 rec->is_static = replica->is_static;
648 rec->expire_time= time(NULL) + partner->service->config.verify_interval;
649 rec->version = replica->version_id;
650 rec->wins_owner = replica->owner;
651 rec->addresses = winsdb_addr_list_make(rec);
652 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
653 rec->registered_by = NULL;
655 for (i=0; i < replica->num_addresses; i++) {
656 /* TODO: find out if rec->expire_time is correct here */
657 rec->addresses = winsdb_addr_list_add(rec->addresses,
658 replica->addresses[i].address,
659 replica->addresses[i].owner,
661 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
664 ret = winsdb_add(partner->service->wins_db, rec, 0);
665 if (ret != NBT_RCODE_OK) {
666 DEBUG(0,("Failed to add record %s: %u\n",
667 nbt_name_string(mem_ctx, &replica->name), ret));
668 return NT_STATUS_FOOBAR;
671 DEBUG(4,("added record %s\n",
672 nbt_name_string(mem_ctx, &replica->name)));
677 static NTSTATUS r_do_replace(struct wreplsrv_partner *partner,
679 struct winsdb_record *rec,
680 struct wrepl_wins_owner *owner,
681 struct wrepl_name *replica)
686 rec->name = &replica->name;
687 rec->type = replica->type;
688 rec->state = replica->state;
689 rec->node = replica->node;
690 rec->is_static = replica->is_static;
691 rec->expire_time= time(NULL) + partner->service->config.verify_interval;
692 rec->version = replica->version_id;
693 rec->wins_owner = replica->owner;
694 rec->addresses = winsdb_addr_list_make(rec);
695 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
696 rec->registered_by = NULL;
698 for (i=0; i < replica->num_addresses; i++) {
699 /* TODO: find out if rec->expire_time is correct here */
700 rec->addresses = winsdb_addr_list_add(rec->addresses,
701 replica->addresses[i].address,
702 replica->addresses[i].owner,
704 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
707 ret = winsdb_modify(partner->service->wins_db, rec, 0);
708 if (ret != NBT_RCODE_OK) {
709 DEBUG(0,("Failed to replace record %s: %u\n",
710 nbt_name_string(mem_ctx, &replica->name), ret));
711 return NT_STATUS_FOOBAR;
714 DEBUG(4,("replaced record %s\n",
715 nbt_name_string(mem_ctx, &replica->name)));
720 static NTSTATUS r_not_replace(struct wreplsrv_partner *partner,
722 struct winsdb_record *rec,
723 struct wrepl_wins_owner *owner,
724 struct wrepl_name *replica)
726 DEBUG(4,("not replace record %s\n",
727 nbt_name_string(mem_ctx, &replica->name)));
731 static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner,
733 struct winsdb_record *rec,
734 struct wrepl_wins_owner *owner,
735 struct wrepl_name *replica)
738 DEBUG(0,("TODO: challenge record %s\n",
739 nbt_name_string(mem_ctx, &replica->name)));
743 static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner,
745 struct winsdb_record *rec,
746 struct wrepl_wins_owner *owner,
747 struct wrepl_name *replica)
750 struct winsdb_addr **addresses;
753 * we need to get a reference to the old addresses,
754 * as we need to send a release demand to them after replacing the record
755 * and r_do_replace() will modify rec->addresses
757 addresses = rec->addresses;
759 status = r_do_replace(partner, mem_ctx, rec, owner, replica);
760 NT_STATUS_NOT_OK_RETURN(status);
763 DEBUG(0,("TODO: send release demand for %s\n",
764 nbt_name_string(mem_ctx, &replica->name)));
769 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
770 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
771 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
772 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
773 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
774 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
776 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
777 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
778 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
779 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
780 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
781 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
783 Test Replica vs. owned active: SGROUP vs. SGROUP tests
784 _SA_SA_DI_U<1c> => SGROUP_MERGE
785 _SA_SA_SI_U<1c> => SGROUP_MERGE
786 _SA_SA_SP_U<1c> => SGROUP_MERGE
787 _SA_SA_SB_U<1c> => SGROUP_MERGE
789 static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner,
791 struct winsdb_record *rec,
792 struct wrepl_wins_owner *owner,
793 struct wrepl_name *replica)
795 struct winsdb_record *merge;
796 uint32_t modify_flags = 0;
800 BOOL changed_old_addrs = False;
801 BOOL become_owner = True;
803 merge = talloc(mem_ctx, struct winsdb_record);
804 NT_STATUS_HAVE_NO_MEMORY(merge);
806 merge->name = &replica->name;
807 merge->type = replica->type;
808 merge->state = replica->state;
809 merge->node = replica->node;
810 merge->is_static = replica->is_static;
811 merge->expire_time = time(NULL) + partner->service->config.verify_interval;
812 merge->version = replica->version_id;
813 merge->wins_owner = replica->owner;
814 merge->addresses = winsdb_addr_list_make(merge);
815 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
816 merge->registered_by = NULL;
818 len = winsdb_addr_list_length(rec->addresses);
820 for (i=0; i < len; i++) {
823 for (j=0; j < replica->num_addresses; j++) {
824 if (strcmp(rec->addresses[i]->address, replica->addresses[j].address) != 0) {
830 if (strcmp(rec->addresses[i]->wins_owner, replica->addresses[j].owner) != 0) {
831 changed_old_addrs = True;
837 /* if it's also in the replica, it'll added later */
841 * if the address isn't in the replica and is owned by replicas owner,
842 * it won't be added to the merged record
844 if (strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) {
845 changed_old_addrs = True;
850 * add the address to the merge result, with the old owner and expire_time
851 * TODO: check if that's correct for the expire_time
853 merge->addresses = winsdb_addr_list_add(merge->addresses,
854 rec->addresses[i]->address,
855 rec->addresses[i]->wins_owner,
856 rec->addresses[i]->expire_time);
857 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
860 for (i=0; i < replica->num_addresses; i++) {
861 /* TODO: find out if rec->expire_time is correct here */
862 merge->addresses = winsdb_addr_list_add(merge->addresses,
863 replica->addresses[i].address,
864 replica->addresses[i].owner,
866 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
869 /* we the old addresses change changed we don't become the owner */
870 if (changed_old_addrs) {
871 become_owner = False;
874 /* if we're the owner of the old record, we'll be the owner of the new one too */
875 if (strcmp(rec->wins_owner, WINSDB_OWNER_LOCAL)==0) {
880 * if the result has no addresses we take the ownership
882 len = winsdb_addr_list_length(merge->addresses);
888 * if addresses of the old record will be changed the replica owner
889 * will be owner of the merge result, otherwise we take the ownership
892 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
895 ret = winsdb_modify(partner->service->wins_db, merge, modify_flags);
896 if (ret != NBT_RCODE_OK) {
897 DEBUG(0,("Failed to modify sgroup merge record %s: %u\n",
898 nbt_name_string(mem_ctx, &replica->name), ret));
899 return NT_STATUS_FOOBAR;
902 DEBUG(4,("sgroup merge record %s\n",
903 nbt_name_string(mem_ctx, &replica->name)));
908 static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
910 struct wrepl_wins_owner *owner,
911 struct wrepl_name *replica)
914 struct winsdb_record *rec = NULL;
915 enum _R_ACTION action = R_INVALID;
916 BOOL same_owner = False;
917 BOOL replica_vs_replica = False;
918 BOOL local_vs_replica = False;
920 status = winsdb_lookup(partner->service->wins_db,
921 &replica->name, mem_ctx, &rec);
922 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
923 return r_do_add(partner, mem_ctx, owner, replica);
925 NT_STATUS_NOT_OK_RETURN(status);
927 if (strcmp(rec->wins_owner, WINSDB_OWNER_LOCAL)==0) {
928 local_vs_replica = True;
929 } else if (strcmp(rec->wins_owner, owner->address)==0) {
932 replica_vs_replica = True;
935 if (rec->is_static && !same_owner) {
936 /* TODO: this is just assumed and needs to be tested more */
937 action = R_NOT_REPLACE;
938 } else if (same_owner) {
939 action = replace_same_owner(rec, replica);
940 } else if (replica_vs_replica) {
942 case WREPL_TYPE_UNIQUE:
943 action = replace_unique_replica_vs_X_replica(rec, replica);
945 case WREPL_TYPE_GROUP:
946 action = replace_group_replica_vs_X_replica(rec, replica);
948 case WREPL_TYPE_SGROUP:
949 action = replace_sgroup_replica_vs_X_replica(rec, replica);
951 case WREPL_TYPE_MHOMED:
952 action = replace_mhomed_replica_vs_X_replica(rec, replica);
955 } else if (local_vs_replica) {
957 case WREPL_TYPE_UNIQUE:
958 action = replace_unique_owned_vs_X_replica(rec, replica);
960 case WREPL_TYPE_GROUP:
961 action = replace_group_owned_vs_X_replica(rec, replica);
963 case WREPL_TYPE_SGROUP:
964 action = replace_sgroup_owned_vs_X_replica(rec, replica);
966 case WREPL_TYPE_MHOMED:
967 action = replace_mhomed_owned_vs_X_replica(rec, replica);
972 DEBUG(4,("apply record %s: %s\n",
973 nbt_name_string(mem_ctx, &replica->name), _R_ACTION_enum_string(action)));
976 case R_INVALID: break;
978 return r_do_replace(partner, mem_ctx, rec, owner, replica);
980 return r_not_replace(partner, mem_ctx, rec, owner, replica);
982 return r_do_challenge(partner, mem_ctx, rec, owner, replica);
983 case R_DO_RELEASE_DEMAND:
984 return r_do_release_demand(partner, mem_ctx, rec, owner, replica);
985 case R_DO_SGROUP_MERGE:
986 return r_do_sgroup_merge(partner, mem_ctx, rec, owner, replica);
989 return NT_STATUS_INTERNAL_ERROR;
992 NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, struct wreplsrv_pull_names_io *names_io)
997 DEBUG(4,("apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
998 names_io->out.num_names, names_io->in.owner.address,
999 names_io->in.owner.min_version, names_io->in.owner.max_version,
1002 for (i=0; i < names_io->out.num_names; i++) {
1003 TALLOC_CTX *tmp_mem = talloc_new(partner);
1004 NT_STATUS_HAVE_NO_MEMORY(tmp_mem);
1006 status = wreplsrv_apply_one_record(partner, tmp_mem,
1007 &names_io->in.owner,
1008 &names_io->out.names[i]);
1009 talloc_free(tmp_mem);
1010 NT_STATUS_NOT_OK_RETURN(status);
1013 status = wreplsrv_add_table(partner->service,
1015 &partner->service->table,
1016 names_io->in.owner.address,
1017 names_io->in.owner.max_version);
1018 NT_STATUS_NOT_OK_RETURN(status);
1020 return NT_STATUS_OK;