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 "wrepl_server/wrepl_out_helpers.h"
30 #include "nbt_server/wins/winsdb.h"
31 #include "libcli/wrepl/winsrepl.h"
32 #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_CHALLENGE: return "CHALLEGNE";
50 case R_DO_RELEASE_DEMAND: return "RELEASE_DEMAND";
51 case R_DO_SGROUP_MERGE: return "SGROUP_MERGE";
54 return "enum _R_ACTION unknown";
57 #define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
58 #define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
59 #define R_IS_TOMBSTONE(r) ((r)->state == WREPL_STATE_TOMBSTONE)
61 #define R_IS_UNIQUE(r) ((r)->type == WREPL_TYPE_UNIQUE)
62 #define R_IS_GROUP(r) ((r)->type == WREPL_TYPE_GROUP)
63 #define R_IS_SGROUP(r) ((r)->type == WREPL_TYPE_SGROUP)
64 #define R_IS_MHOMED(r) ((r)->type == WREPL_TYPE_MHOMED)
66 /* blindly overwrite records from the same owner in all cases */
67 static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_name *r2)
73 static BOOL r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
76 size_t len = winsdb_addr_list_length(r1->addresses);
78 for (i=0; i < len; i++) {
80 for (j=0; j < r2->num_addresses; j++) {
81 if (strcmp(r1->addresses[i]->address, r2->addresses[j].address) != 0) {
85 if (check_owners && strcmp(r1->addresses[i]->wins_owner, r2->addresses[j].owner) != 0) {
91 if (!found) return False;
97 static BOOL r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
100 size_t len = winsdb_addr_list_length(r1->addresses);
102 for (i=0; i < r2->num_addresses; i++) {
104 for (j=0; j < len; j++) {
105 if (strcmp(r2->addresses[i].address, r1->addresses[j]->address) != 0) {
109 if (check_owners && strcmp(r2->addresses[i].owner, r1->addresses[j]->wins_owner) != 0) {
115 if (!found) return False;
121 static BOOL r_1_is_same_as_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
123 size_t len = winsdb_addr_list_length(r1->addresses);
125 if (len != r2->num_addresses) {
129 return r_1_is_superset_of_2_address_list(r1, r2, check_owners);
132 static BOOL r_contains_addrs_from_owner(struct winsdb_record *r1, const char *owner)
135 size_t len = winsdb_addr_list_length(r1->addresses);
137 for (i=0; i < len; i++) {
138 if (strcmp(r1->addresses[i]->wins_owner, owner) == 0) {
147 UNIQUE,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
148 UNIQUE,ACTIVE vs. UNIQUE,TOMBSTONE with different ip(s) => NOT REPLACE
149 UNIQUE,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
150 UNIQUE,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
151 UNIQUE,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
152 UNIQUE,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
153 UNIQUE,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
154 UNIQUE,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
155 UNIQUE,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
156 UNIQUE,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
157 UNIQUE,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
158 UNIQUE,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
159 UNIQUE,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
160 UNIQUE,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
161 UNIQUE,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
162 UNIQUE,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
163 UNIQUE,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
164 UNIQUE,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
165 UNIQUE,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
166 UNIQUE,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
167 UNIQUE,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
168 UNIQUE,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
169 UNIQUE,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
170 UNIQUE,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
172 static enum _R_ACTION replace_unique_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
174 if (!R_IS_ACTIVE(r1)) {
179 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
185 return R_NOT_REPLACE;
189 GROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
190 GROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
191 GROUP,RELEASED vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
192 GROUP,RELEASED vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
193 GROUP,TOMBSTONE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
194 GROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
195 GROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
196 GROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
197 GROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
198 GROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
199 GROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
200 GROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
201 GROUP,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
202 GROUP,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
203 GROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
204 GROUP,RELEASED vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
205 GROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
206 GROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
207 GROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
208 GROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
209 GROUP,RELEASED vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
210 GROUP,RELEASED vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
211 GROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
212 GROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
214 static enum _R_ACTION replace_group_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
216 if (!R_IS_ACTIVE(r1) && R_IS_GROUP(r2)) {
221 if (R_IS_TOMBSTONE(r1) && !R_IS_UNIQUE(r2)) {
227 return R_NOT_REPLACE;
231 SGROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
232 SGROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
233 SGROUP,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
234 SGROUP,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
235 SGROUP,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
236 SGROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
237 SGROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
238 SGROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
239 SGROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
240 SGROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
241 SGROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
242 SGROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
243 SGROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
244 SGROUP,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
245 SGROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
246 SGROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
247 SGROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
248 SGROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
249 SGROUP,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
250 SGROUP,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
251 SGROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
252 SGROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
254 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
255 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
256 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
257 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
258 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
259 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
261 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
262 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
263 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
264 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
265 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
266 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
268 static enum _R_ACTION replace_sgroup_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
270 if (!R_IS_ACTIVE(r1)) {
275 if (!R_IS_SGROUP(r2) || !R_IS_ACTIVE(r2)) {
277 return R_NOT_REPLACE;
280 if (r2->num_addresses == 0) {
281 if (r_contains_addrs_from_owner(r1, r2->owner)) {
282 /* not handled here: MERGE */
283 return R_DO_SGROUP_MERGE;
287 return R_NOT_REPLACE;
290 if (r_1_is_superset_of_2_address_list(r1, r2, True)) {
292 return R_NOT_REPLACE;
295 if (r_1_is_same_as_2_address_list(r1, r2, False)) {
300 /* not handled here: MERGE */
301 return R_DO_SGROUP_MERGE;
305 MHOMED,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
306 MHOMED,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
307 MHOMED,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
308 MHOMED,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
309 MHOMED,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
310 MHOMED,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
311 MHOMED,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
312 MHOMED,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
313 MHOMED,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
314 MHOMED,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
315 MHOMED,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
316 MHOMED,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
317 MHOMED,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
318 MHOMED,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
319 MHOMED,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
320 MHOMED,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
321 MHOMED,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
322 MHOMED,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
323 MHOMED,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
324 MHOMED,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
325 MHOMED,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
326 MHOMED,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
327 MHOMED,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
328 MHOMED,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
330 static enum _R_ACTION replace_mhomed_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
332 if (!R_IS_ACTIVE(r1)) {
337 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
343 return R_NOT_REPLACE;
348 _UA_UA_SI_U<00> => REPLACE
349 _UA_UA_DI_P<00> => NOT REPLACE
350 _UA_UA_DI_O<00> => NOT REPLACE
351 _UA_UA_DI_N<00> => REPLACE
352 _UA_UT_SI_U<00> => NOT REPLACE
353 _UA_UT_DI_U<00> => NOT REPLACE
354 _UA_GA_SI_R<00> => REPLACE
355 _UA_GA_DI_R<00> => REPLACE
356 _UA_GT_SI_U<00> => NOT REPLACE
357 _UA_GT_DI_U<00> => NOT REPLACE
358 _UA_SA_SI_R<00> => REPLACE
359 _UA_SA_DI_R<00> => REPLACE
360 _UA_ST_SI_U<00> => NOT REPLACE
361 _UA_ST_DI_U<00> => NOT REPLACE
362 _UA_MA_SI_U<00> => REPLACE
363 _UA_MA_SP_U<00> => REPLACE
364 _UA_MA_DI_P<00> => NOT REPLACE
365 _UA_MA_DI_O<00> => NOT REPLACE
366 _UA_MA_DI_N<00> => REPLACE
367 _UA_MT_SI_U<00> => NOT REPLACE
368 _UA_MT_DI_U<00> => NOT REPLACE
369 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
370 _UA_UA_DI_A<00> => MHOMED_MERGE
371 _UA_MA_DI_A<00> => MHOMED_MERGE
374 _UR_UA_SI<00> => REPLACE
375 _UR_UA_DI<00> => REPLACE
376 _UR_UT_SI<00> => REPLACE
377 _UR_UT_DI<00> => REPLACE
378 _UR_GA_SI<00> => REPLACE
379 _UR_GA_DI<00> => REPLACE
380 _UR_GT_SI<00> => REPLACE
381 _UR_GT_DI<00> => REPLACE
382 _UR_SA_SI<00> => REPLACE
383 _UR_SA_DI<00> => REPLACE
384 _UR_ST_SI<00> => REPLACE
385 _UR_ST_DI<00> => REPLACE
386 _UR_MA_SI<00> => REPLACE
387 _UR_MA_DI<00> => REPLACE
388 _UR_MT_SI<00> => REPLACE
389 _UR_MT_DI<00> => REPLACE
391 static enum _R_ACTION replace_unique_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
393 if (!R_IS_ACTIVE(r1)) {
398 if (!R_IS_ACTIVE(r2)) {
400 return R_NOT_REPLACE;
403 if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
404 /* REPLACE and send a release demand to the old name owner */
405 return R_DO_RELEASE_DEMAND;
409 * here we only have unique,active,owned vs.
410 * is unique,active,replica or mhomed,active,replica
413 if (r_1_is_subset_of_2_address_list(r1, r2, False)) {
415 * if r1 has a subset(or same) of the addresses of r2
417 * if r2 has a superset(or same) of the addresses of r1
419 * then replace the record
425 * in any other case, we need to do
426 * a name request to the old name holder
427 * to see if it's still there...
429 return R_DO_CHALLENGE;
434 _GA_UA_SI_U<00> => NOT REPLACE
435 _GA_UA_DI_U<00> => NOT REPLACE
436 _GA_UT_SI_U<00> => NOT REPLACE
437 _GA_UT_DI_U<00> => NOT REPLACE
438 _GA_GA_SI_U<00> => REPLACE
439 _GA_GA_DI_U<00> => REPLACE
440 _GA_GT_SI_U<00> => NOT REPLACE
441 _GA_GT_DI_U<00> => NOT REPLACE
442 _GA_SA_SI_U<00> => NOT REPLACE
443 _GA_SA_DI_U<00> => NOT REPLACE
444 _GA_ST_SI_U<00> => NOT REPLACE
445 _GA_ST_DI_U<00> => NOT REPLACE
446 _GA_MA_SI_U<00> => NOT REPLACE
447 _GA_MA_DI_U<00> => NOT REPLACE
448 _GA_MT_SI_U<00> => NOT REPLACE
449 _GA_MT_DI_U<00> => NOT REPLACE
452 _GR_UA_SI<00> => NOT REPLACE
453 _GR_UA_DI<00> => NOT REPLACE
454 _GR_UT_SI<00> => NOT REPLACE
455 _GR_UT_DI<00> => NOT REPLACE
456 _GR_GA_SI<00> => REPLACE
457 _GR_GA_DI<00> => REPLACE
458 _GR_GT_SI<00> => REPLACE
459 _GR_GT_DI<00> => REPLACE
460 _GR_SA_SI<00> => NOT REPLACE
461 _GR_SA_DI<00> => NOT REPLACE
462 _GR_ST_SI<00> => NOT REPLACE
463 _GR_ST_DI<00> => NOT REPLACE
464 _GR_MA_SI<00> => NOT REPLACE
465 _GR_MA_DI<00> => NOT REPLACE
466 _GR_MT_SI<00> => NOT REPLACE
467 _GR_MT_DI<00> => NOT REPLACE
469 static enum _R_ACTION replace_group_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
471 if (R_IS_GROUP(r1) && R_IS_GROUP(r2)) {
472 if (!R_IS_ACTIVE(r1) || R_IS_ACTIVE(r2)) {
479 return R_NOT_REPLACE;
483 active (not sgroup vs. sgroup yet!):
484 _SA_UA_SI_U<1c> => NOT REPLACE
485 _SA_UA_DI_U<1c> => NOT REPLACE
486 _SA_UT_SI_U<1c> => NOT REPLACE
487 _SA_UT_DI_U<1c> => NOT REPLACE
488 _SA_GA_SI_U<1c> => NOT REPLACE
489 _SA_GA_DI_U<1c> => NOT REPLACE
490 _SA_GT_SI_U<1c> => NOT REPLACE
491 _SA_GT_DI_U<1c> => NOT REPLACE
492 _SA_MA_SI_U<1c> => NOT REPLACE
493 _SA_MA_DI_U<1c> => NOT REPLACE
494 _SA_MT_SI_U<1c> => NOT REPLACE
495 _SA_MT_DI_U<1c> => NOT REPLACE
497 Test Replica vs. owned active: SGROUP vs. SGROUP tests
498 _SA_SA_DI_U<1c> => SGROUP_MERGE
499 _SA_SA_SI_U<1c> => SGROUP_MERGE
500 _SA_SA_SP_U<1c> => SGROUP_MERGE
501 _SA_SA_SB_U<1c> => SGROUP_MERGE
502 _SA_ST_DI_U<1c> => NOT REPLACE
503 _SA_ST_SI_U<1c> => NOT REPLACE
504 _SA_ST_SP_U<1c> => NOT REPLACE
505 _SA_ST_SB_U<1c> => NOT REPLACE
507 SGROUP,ACTIVE vs. SGROUP,* is not handled here!
510 _SR_UA_SI<1c> => REPLACE
511 _SR_UA_DI<1c> => REPLACE
512 _SR_UT_SI<1c> => REPLACE
513 _SR_UT_DI<1c> => REPLACE
514 _SR_GA_SI<1c> => REPLACE
515 _SR_GA_DI<1c> => REPLACE
516 _SR_GT_SI<1c> => REPLACE
517 _SR_GT_DI<1c> => REPLACE
518 _SR_SA_SI<1c> => REPLACE
519 _SR_SA_DI<1c> => REPLACE
520 _SR_ST_SI<1c> => REPLACE
521 _SR_ST_DI<1c> => REPLACE
522 _SR_MA_SI<1c> => REPLACE
523 _SR_MA_DI<1c> => REPLACE
524 _SR_MT_SI<1c> => REPLACE
525 _SR_MT_DI<1c> => REPLACE
527 static enum _R_ACTION replace_sgroup_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
529 if (!R_IS_ACTIVE(r1)) {
534 if (!R_IS_SGROUP(r2) || !R_IS_ACTIVE(r2)) {
536 return R_NOT_REPLACE;
540 * TODO: should we have the same logic here like in
541 * replace_sgroup_replica_vs_X_replica() ?
544 /* not handled here: MERGE */
545 return R_DO_SGROUP_MERGE;
550 _MA_UA_SI_U<00> => REPLACE
551 _MA_UA_DI_P<00> => NOT REPLACE
552 _MA_UA_DI_O<00> => NOT REPLACE
553 _MA_UA_DI_N<00> => REPLACE
554 _MA_UT_SI_U<00> => NOT REPLACE
555 _MA_UT_DI_U<00> => NOT REPLACE
556 _MA_GA_SI_R<00> => REPLACE
557 _MA_GA_DI_R<00> => REPLACE
558 _MA_GT_SI_U<00> => NOT REPLACE
559 _MA_GT_DI_U<00> => NOT REPLACE
560 _MA_SA_SI_R<00> => REPLACE
561 _MA_SA_DI_R<00> => REPLACE
562 _MA_ST_SI_U<00> => NOT REPLACE
563 _MA_ST_DI_U<00> => NOT REPLACE
564 _MA_MA_SI_U<00> => REPLACE
565 _MA_MA_SP_U<00> => REPLACE
566 _MA_MA_DI_P<00> => NOT REPLACE
567 _MA_MA_DI_O<00> => NOT REPLACE
568 _MA_MA_DI_N<00> => REPLACE
569 _MA_MT_SI_U<00> => NOT REPLACE
570 _MA_MT_DI_U<00> => NOT REPLACE
571 Test Replica vs. owned active: some more MHOMED combinations
572 _MA_MA_SP_U<00> => REPLACE
573 _MA_MA_SM_U<00> => REPLACE
574 _MA_MA_SB_P<00> => MHOMED_MERGE
575 _MA_MA_SB_A<00> => MHOMED_MERGE
576 _MA_MA_SB_PRA<00> => NOT REPLACE
577 _MA_MA_SB_O<00> => NOT REPLACE
578 _MA_MA_SB_N<00> => REPLACE
579 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
580 _MA_UA_SB_P<00> => MHOMED_MERGE
583 _MR_UA_SI<00> => REPLACE
584 _MR_UA_DI<00> => REPLACE
585 _MR_UT_SI<00> => REPLACE
586 _MR_UT_DI<00> => REPLACE
587 _MR_GA_SI<00> => REPLACE
588 _MR_GA_DI<00> => REPLACE
589 _MR_GT_SI<00> => REPLACE
590 _MR_GT_DI<00> => REPLACE
591 _MR_SA_SI<00> => REPLACE
592 _MR_SA_DI<00> => REPLACE
593 _MR_ST_SI<00> => REPLACE
594 _MR_ST_DI<00> => REPLACE
595 _MR_MA_SI<00> => REPLACE
596 _MR_MA_DI<00> => REPLACE
597 _MR_MT_SI<00> => REPLACE
598 _MR_MT_DI<00> => REPLACE
600 static enum _R_ACTION replace_mhomed_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
602 if (!R_IS_ACTIVE(r1)) {
607 if (!R_IS_ACTIVE(r2)) {
609 return R_NOT_REPLACE;
612 if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
613 /* REPLACE and send a release demand to the old name owner */
614 return R_DO_RELEASE_DEMAND;
618 * here we only have mhomed,active,owned vs.
619 * is unique,active,replica or mhomed,active,replica
622 if (r_1_is_subset_of_2_address_list(r1, r2, False)) {
624 * if r1 has a subset(or same) of the addresses of r2
626 * if r2 has a superset(or same) of the addresses of r1
628 * then replace the record
634 * in any other case, we need to do
635 * a name request to the old name holder
636 * to see if it's still there...
638 return R_DO_CHALLENGE;
641 static NTSTATUS r_do_add(struct wreplsrv_partner *partner,
643 struct wrepl_wins_owner *owner,
644 struct wrepl_name *replica)
646 struct winsdb_record *rec;
650 rec = talloc(mem_ctx, struct winsdb_record);
651 NT_STATUS_HAVE_NO_MEMORY(rec);
653 rec->name = &replica->name;
654 rec->type = replica->type;
655 rec->state = replica->state;
656 rec->node = replica->node;
657 rec->is_static = replica->is_static;
658 rec->expire_time= time(NULL) + partner->service->config.verify_interval;
659 rec->version = replica->version_id;
660 rec->wins_owner = replica->owner;
661 rec->addresses = winsdb_addr_list_make(rec);
662 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
663 rec->registered_by = NULL;
665 for (i=0; i < replica->num_addresses; i++) {
666 /* TODO: find out if rec->expire_time is correct here */
667 rec->addresses = winsdb_addr_list_add(rec->addresses,
668 replica->addresses[i].address,
669 replica->addresses[i].owner,
671 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
674 ret = winsdb_add(partner->service->wins_db, rec, 0);
675 if (ret != NBT_RCODE_OK) {
676 DEBUG(0,("Failed to add record %s: %u\n",
677 nbt_name_string(mem_ctx, &replica->name), ret));
678 return NT_STATUS_FOOBAR;
681 DEBUG(4,("added record %s\n",
682 nbt_name_string(mem_ctx, &replica->name)));
687 static NTSTATUS r_do_replace(struct wreplsrv_partner *partner,
689 struct winsdb_record *rec,
690 struct wrepl_wins_owner *owner,
691 struct wrepl_name *replica)
696 rec->name = &replica->name;
697 rec->type = replica->type;
698 rec->state = replica->state;
699 rec->node = replica->node;
700 rec->is_static = replica->is_static;
701 rec->expire_time= time(NULL) + partner->service->config.verify_interval;
702 rec->version = replica->version_id;
703 rec->wins_owner = replica->owner;
704 rec->addresses = winsdb_addr_list_make(rec);
705 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
706 rec->registered_by = NULL;
708 for (i=0; i < replica->num_addresses; i++) {
709 /* TODO: find out if rec->expire_time is correct here */
710 rec->addresses = winsdb_addr_list_add(rec->addresses,
711 replica->addresses[i].address,
712 replica->addresses[i].owner,
714 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
717 ret = winsdb_modify(partner->service->wins_db, rec, 0);
718 if (ret != NBT_RCODE_OK) {
719 DEBUG(0,("Failed to replace record %s: %u\n",
720 nbt_name_string(mem_ctx, &replica->name), ret));
721 return NT_STATUS_FOOBAR;
724 DEBUG(4,("replaced record %s\n",
725 nbt_name_string(mem_ctx, &replica->name)));
730 static NTSTATUS r_not_replace(struct wreplsrv_partner *partner,
732 struct winsdb_record *rec,
733 struct wrepl_wins_owner *owner,
734 struct wrepl_name *replica)
736 DEBUG(4,("not replace record %s\n",
737 nbt_name_string(mem_ctx, &replica->name)));
742 Test Replica vs. owned active: some more MHOMED combinations
743 _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
744 _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
745 _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
746 _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
747 _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
748 _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
749 _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
750 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
751 _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
752 _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
753 _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
754 _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
756 static NTSTATUS r_do_mhomed_merge(struct wreplsrv_partner *partner,
758 struct winsdb_record *rec,
759 struct wrepl_wins_owner *owner,
760 struct wrepl_name *replica)
762 struct winsdb_record *merge;
767 merge = talloc(mem_ctx, struct winsdb_record);
768 NT_STATUS_HAVE_NO_MEMORY(merge);
770 merge->name = &replica->name;
771 merge->type = WREPL_TYPE_MHOMED;
772 merge->state = replica->state;
773 merge->node = replica->node;
774 merge->is_static = replica->is_static;
775 merge->expire_time = time(NULL) + partner->service->config.verify_interval;
776 merge->version = replica->version_id;
777 merge->wins_owner = replica->owner;
778 merge->addresses = winsdb_addr_list_make(merge);
779 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
780 merge->registered_by = NULL;
782 for (i=0; i < replica->num_addresses; i++) {
783 /* TODO: find out if rec->expire_time is correct here */
784 merge->addresses = winsdb_addr_list_add(merge->addresses,
785 replica->addresses[i].address,
786 replica->addresses[i].owner,
788 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
791 len = winsdb_addr_list_length(rec->addresses);
793 for (i=0; i < len; i++) {
795 for (j=0; j < replica->num_addresses; j++) {
796 if (strcmp(replica->addresses[j].address, rec->addresses[i]->address) == 0) {
803 /* TODO: find out if rec->expire_time is correct here */
804 merge->addresses = winsdb_addr_list_add(merge->addresses,
805 rec->addresses[i]->address,
806 rec->addresses[i]->wins_owner,
808 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
811 ret = winsdb_modify(partner->service->wins_db, merge, 0);
812 if (ret != NBT_RCODE_OK) {
813 DEBUG(0,("Failed to modify mhomed merge record %s: %u\n",
814 nbt_name_string(mem_ctx, &replica->name), ret));
815 return NT_STATUS_FOOBAR;
818 DEBUG(4,("mhomed merge record %s\n",
819 nbt_name_string(mem_ctx, &replica->name)));
824 struct r_do_challenge_state {
825 struct messaging_context *msg_ctx;
826 struct wreplsrv_partner *partner;
827 struct winsdb_record *rec;
828 struct wrepl_wins_owner owner;
829 struct wrepl_name replica;
830 struct nbtd_proxy_wins_challenge r;
833 static void r_do_late_release_demand_handler(struct irpc_request *ireq)
836 struct r_do_challenge_state *state = talloc_get_type(ireq->async.private,
837 struct r_do_challenge_state);
839 status = irpc_call_recv(ireq);
840 /* don't care about the result */
844 static NTSTATUS r_do_late_release_demand(struct r_do_challenge_state *state)
846 struct irpc_request *ireq;
847 uint32_t *nbt_servers;
848 struct nbtd_proxy_wins_release_demand r;
851 DEBUG(4,("late release demand record %s\n",
852 nbt_name_string(state, &state->replica.name)));
854 nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server");
855 if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
856 return NT_STATUS_INTERNAL_ERROR;
859 r.in.name = state->replica.name;
860 r.in.num_addrs = state->r.out.num_addrs;
861 r.in.addrs = talloc_array(state, struct nbtd_proxy_wins_addr, r.in.num_addrs);
862 NT_STATUS_HAVE_NO_MEMORY(r.in.addrs);
863 /* TODO: fix pidl to handle inline ipv4address arrays */
864 for (i=0; i < r.in.num_addrs; i++) {
865 r.in.addrs[i].addr = state->r.out.addrs[i].addr;
868 ireq = IRPC_CALL_SEND(state->msg_ctx, nbt_servers[0],
869 irpc, NBTD_PROXY_WINS_RELEASE_DEMAND,
871 NT_STATUS_HAVE_NO_MEMORY(ireq);
873 ireq->async.fn = r_do_late_release_demand_handler;
874 ireq->async.private = state;
880 Test Replica vs. owned active: some more MHOMED combinations
881 _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
882 _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
883 _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
884 _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
885 _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
886 _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
887 _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
888 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
889 _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
890 _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
891 _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
892 _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
894 static void r_do_challenge_handler(struct irpc_request *ireq)
897 struct r_do_challenge_state *state = talloc_get_type(ireq->async.private,
898 struct r_do_challenge_state);
899 BOOL old_is_subset = False;
900 BOOL new_is_subset = False;
903 uint32_t num_rec_addrs;
905 status = irpc_call_recv(ireq);
907 DEBUG(4,("r_do_challenge_handler: %s: %s\n",
908 nbt_name_string(state, &state->replica.name), nt_errstr(status)));
910 if (NT_STATUS_EQUAL(NT_STATUS_IO_TIMEOUT, status) ||
911 NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
912 r_do_replace(state->partner, state, state->rec, &state->owner, &state->replica);
917 for (i=0; i < state->replica.num_addresses; i++) {
919 new_is_subset = True;
920 for (j=0; j < state->r.out.num_addrs; j++) {
921 if (strcmp(state->replica.addresses[i].address, state->r.out.addrs[j].addr) == 0) {
928 new_is_subset = False;
932 if (!new_is_subset) {
933 r_not_replace(state->partner, state, state->rec, &state->owner, &state->replica);
938 num_rec_addrs = winsdb_addr_list_length(state->rec->addresses);
939 for (i=0; i < num_rec_addrs; i++) {
941 old_is_subset = True;
942 for (j=0; j < state->r.out.num_addrs; j++) {
943 if (strcmp(state->rec->addresses[i]->address, state->r.out.addrs[j].addr) == 0) {
950 old_is_subset = False;
954 if (!old_is_subset) {
955 r_do_late_release_demand(state);
957 * don't free state here, because we pass it down,
958 * and r_do_late_release_demand() will free it
963 r_do_mhomed_merge(state->partner, state, state->rec, &state->owner, &state->replica);
967 static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner,
969 struct winsdb_record *rec,
970 struct wrepl_wins_owner *owner,
971 struct wrepl_name *replica)
973 struct irpc_request *ireq;
974 struct r_do_challenge_state *state;
975 uint32_t *nbt_servers;
979 DEBUG(4,("challenge record %s\n",
980 nbt_name_string(mem_ctx, &replica->name)));
982 state = talloc_zero(mem_ctx, struct r_do_challenge_state);
983 NT_STATUS_HAVE_NO_MEMORY(state);
984 state->msg_ctx = partner->service->task->msg_ctx;
985 state->partner = partner;
986 state->rec = talloc_steal(state, rec);
987 state->owner = *owner;
988 state->replica = *replica;
989 /* some stuff to have valid memory pointers in the async complete function */
990 state->replica.name = *state->rec->name;
991 talloc_steal(state, replica->owner);
992 talloc_steal(state, replica->addresses);
994 nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server");
995 if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
996 return NT_STATUS_INTERNAL_ERROR;
999 state->r.in.name = *rec->name;
1000 state->r.in.num_addrs = winsdb_addr_list_length(rec->addresses);
1001 state->r.in.addrs = talloc_array(state, struct nbtd_proxy_wins_addr, state->r.in.num_addrs);
1002 NT_STATUS_HAVE_NO_MEMORY(state->r.in.addrs);
1003 /* TODO: fix pidl to handle inline ipv4address arrays */
1004 addrs = winsdb_addr_string_list(state->r.in.addrs, rec->addresses);
1005 NT_STATUS_HAVE_NO_MEMORY(addrs);
1006 for (i=0; i < state->r.in.num_addrs; i++) {
1007 state->r.in.addrs[i].addr = addrs[i];
1010 ireq = IRPC_CALL_SEND(state->msg_ctx, nbt_servers[0],
1011 irpc, NBTD_PROXY_WINS_CHALLENGE,
1013 NT_STATUS_HAVE_NO_MEMORY(ireq);
1015 ireq->async.fn = r_do_challenge_handler;
1016 ireq->async.private = state;
1018 talloc_steal(partner, state);
1019 return NT_STATUS_OK;
1022 static void r_do_release_demand_handler(struct irpc_request *ireq)
1025 status = irpc_call_recv(ireq);
1026 /* don't care about the result */
1029 static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner,
1030 TALLOC_CTX *mem_ctx,
1031 struct winsdb_record *rec,
1032 struct wrepl_wins_owner *owner,
1033 struct wrepl_name *replica)
1036 struct irpc_request *ireq;
1037 uint32_t *nbt_servers;
1039 struct winsdb_addr **addresses;
1040 struct nbtd_proxy_wins_release_demand r;
1044 * we need to get a reference to the old addresses,
1045 * as we need to send a release demand to them after replacing the record
1046 * and r_do_replace() will modify rec->addresses
1048 addresses = rec->addresses;
1050 status = r_do_replace(partner, mem_ctx, rec, owner, replica);
1051 NT_STATUS_NOT_OK_RETURN(status);
1053 DEBUG(4,("release demand record %s\n",
1054 nbt_name_string(mem_ctx, &replica->name)));
1056 nbt_servers = irpc_servers_byname(partner->service->task->msg_ctx, "nbt_server");
1057 if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
1058 return NT_STATUS_INTERNAL_ERROR;
1061 r.in.name = *rec->name;
1062 r.in.num_addrs = winsdb_addr_list_length(addresses);
1063 r.in.addrs = talloc_array(partner, struct nbtd_proxy_wins_addr, r.in.num_addrs);
1064 NT_STATUS_HAVE_NO_MEMORY(r.in.addrs);
1065 /* TODO: fix pidl to handle inline ipv4address arrays */
1066 addrs = winsdb_addr_string_list(r.in.addrs, addresses);
1067 NT_STATUS_HAVE_NO_MEMORY(addrs);
1068 for (i=0; i < r.in.num_addrs; i++) {
1069 r.in.addrs[i].addr = addrs[i];
1072 ireq = IRPC_CALL_SEND(partner->service->task->msg_ctx, nbt_servers[0],
1073 irpc, NBTD_PROXY_WINS_RELEASE_DEMAND,
1075 NT_STATUS_HAVE_NO_MEMORY(ireq);
1077 ireq->async.fn = r_do_release_demand_handler;
1078 ireq->async.private = NULL;
1080 return NT_STATUS_OK;
1084 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
1085 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
1086 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
1087 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
1088 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
1089 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
1091 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
1092 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
1093 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
1094 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
1095 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
1096 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
1098 Test Replica vs. owned active: SGROUP vs. SGROUP tests
1099 _SA_SA_DI_U<1c> => SGROUP_MERGE
1100 _SA_SA_SI_U<1c> => SGROUP_MERGE
1101 _SA_SA_SP_U<1c> => SGROUP_MERGE
1102 _SA_SA_SB_U<1c> => SGROUP_MERGE
1104 static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner,
1105 TALLOC_CTX *mem_ctx,
1106 struct winsdb_record *rec,
1107 struct wrepl_wins_owner *owner,
1108 struct wrepl_name *replica)
1110 struct winsdb_record *merge;
1111 uint32_t modify_flags = 0;
1115 BOOL changed_old_addrs = False;
1116 BOOL become_owner = True;
1118 merge = talloc(mem_ctx, struct winsdb_record);
1119 NT_STATUS_HAVE_NO_MEMORY(merge);
1121 merge->name = &replica->name;
1122 merge->type = replica->type;
1123 merge->state = replica->state;
1124 merge->node = replica->node;
1125 merge->is_static = replica->is_static;
1126 merge->expire_time = time(NULL) + partner->service->config.verify_interval;
1127 merge->version = replica->version_id;
1128 merge->wins_owner = replica->owner;
1129 merge->addresses = winsdb_addr_list_make(merge);
1130 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
1131 merge->registered_by = NULL;
1133 len = winsdb_addr_list_length(rec->addresses);
1135 for (i=0; i < len; i++) {
1138 for (j=0; j < replica->num_addresses; j++) {
1139 if (strcmp(rec->addresses[i]->address, replica->addresses[j].address) != 0) {
1145 if (strcmp(rec->addresses[i]->wins_owner, replica->addresses[j].owner) != 0) {
1146 changed_old_addrs = True;
1152 /* if it's also in the replica, it'll added later */
1153 if (found) continue;
1156 * if the address isn't in the replica and is owned by replicas owner,
1157 * it won't be added to the merged record
1159 if (strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) {
1160 changed_old_addrs = True;
1165 * add the address to the merge result, with the old owner and expire_time
1166 * TODO: check if that's correct for the expire_time
1168 merge->addresses = winsdb_addr_list_add(merge->addresses,
1169 rec->addresses[i]->address,
1170 rec->addresses[i]->wins_owner,
1171 rec->addresses[i]->expire_time);
1172 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
1175 for (i=0; i < replica->num_addresses; i++) {
1176 /* TODO: find out if rec->expire_time is correct here */
1177 merge->addresses = winsdb_addr_list_add(merge->addresses,
1178 replica->addresses[i].address,
1179 replica->addresses[i].owner,
1180 merge->expire_time);
1181 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
1184 /* we the old addresses change changed we don't become the owner */
1185 if (changed_old_addrs) {
1186 become_owner = False;
1189 /* if we're the owner of the old record, we'll be the owner of the new one too */
1190 if (strcmp(rec->wins_owner, WINSDB_OWNER_LOCAL)==0) {
1191 become_owner = True;
1195 * if the result has no addresses we take the ownership
1197 len = winsdb_addr_list_length(merge->addresses);
1199 become_owner = True;
1203 * if addresses of the old record will be changed the replica owner
1204 * will be owner of the merge result, otherwise we take the ownership
1207 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
1210 ret = winsdb_modify(partner->service->wins_db, merge, modify_flags);
1211 if (ret != NBT_RCODE_OK) {
1212 DEBUG(0,("Failed to modify sgroup merge record %s: %u\n",
1213 nbt_name_string(mem_ctx, &replica->name), ret));
1214 return NT_STATUS_FOOBAR;
1217 DEBUG(4,("sgroup merge record %s\n",
1218 nbt_name_string(mem_ctx, &replica->name)));
1220 return NT_STATUS_OK;
1223 static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
1224 TALLOC_CTX *mem_ctx,
1225 struct wrepl_wins_owner *owner,
1226 struct wrepl_name *replica)
1229 struct winsdb_record *rec = NULL;
1230 enum _R_ACTION action = R_INVALID;
1231 BOOL same_owner = False;
1232 BOOL replica_vs_replica = False;
1233 BOOL local_vs_replica = False;
1235 status = winsdb_lookup(partner->service->wins_db,
1236 &replica->name, mem_ctx, &rec);
1237 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
1238 return r_do_add(partner, mem_ctx, owner, replica);
1240 NT_STATUS_NOT_OK_RETURN(status);
1242 if (strcmp(rec->wins_owner, WINSDB_OWNER_LOCAL)==0) {
1243 local_vs_replica = True;
1244 } else if (strcmp(rec->wins_owner, owner->address)==0) {
1247 replica_vs_replica = True;
1250 if (rec->is_static && !same_owner) {
1251 /* TODO: this is just assumed and needs to be tested more */
1252 action = R_NOT_REPLACE;
1253 } else if (same_owner) {
1254 action = replace_same_owner(rec, replica);
1255 } else if (replica_vs_replica) {
1256 switch (rec->type) {
1257 case WREPL_TYPE_UNIQUE:
1258 action = replace_unique_replica_vs_X_replica(rec, replica);
1260 case WREPL_TYPE_GROUP:
1261 action = replace_group_replica_vs_X_replica(rec, replica);
1263 case WREPL_TYPE_SGROUP:
1264 action = replace_sgroup_replica_vs_X_replica(rec, replica);
1266 case WREPL_TYPE_MHOMED:
1267 action = replace_mhomed_replica_vs_X_replica(rec, replica);
1270 } else if (local_vs_replica) {
1271 switch (rec->type) {
1272 case WREPL_TYPE_UNIQUE:
1273 action = replace_unique_owned_vs_X_replica(rec, replica);
1275 case WREPL_TYPE_GROUP:
1276 action = replace_group_owned_vs_X_replica(rec, replica);
1278 case WREPL_TYPE_SGROUP:
1279 action = replace_sgroup_owned_vs_X_replica(rec, replica);
1281 case WREPL_TYPE_MHOMED:
1282 action = replace_mhomed_owned_vs_X_replica(rec, replica);
1287 DEBUG(4,("apply record %s: %s\n",
1288 nbt_name_string(mem_ctx, &replica->name), _R_ACTION_enum_string(action)));
1291 case R_INVALID: break;
1293 return r_do_replace(partner, mem_ctx, rec, owner, replica);
1295 return r_not_replace(partner, mem_ctx, rec, owner, replica);
1296 case R_DO_CHALLENGE:
1297 return r_do_challenge(partner, mem_ctx, rec, owner, replica);
1298 case R_DO_RELEASE_DEMAND:
1299 return r_do_release_demand(partner, mem_ctx, rec, owner, replica);
1300 case R_DO_SGROUP_MERGE:
1301 return r_do_sgroup_merge(partner, mem_ctx, rec, owner, replica);
1304 return NT_STATUS_INTERNAL_ERROR;
1307 NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, struct wreplsrv_pull_names_io *names_io)
1312 DEBUG(4,("apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
1313 names_io->out.num_names, names_io->in.owner.address,
1314 (long long)names_io->in.owner.min_version,
1315 (long long)names_io->in.owner.max_version,
1318 for (i=0; i < names_io->out.num_names; i++) {
1319 TALLOC_CTX *tmp_mem = talloc_new(partner);
1320 NT_STATUS_HAVE_NO_MEMORY(tmp_mem);
1322 status = wreplsrv_apply_one_record(partner, tmp_mem,
1323 &names_io->in.owner,
1324 &names_io->out.names[i]);
1325 talloc_free(tmp_mem);
1326 NT_STATUS_NOT_OK_RETURN(status);
1329 status = wreplsrv_add_table(partner->service,
1331 &partner->service->table,
1332 names_io->in.owner.address,
1333 names_io->in.owner.max_version);
1334 NT_STATUS_NOT_OK_RETURN(status);
1336 return NT_STATUS_OK;