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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "smbd/service_task.h"
24 #include "lib/messaging/irpc.h"
25 #include "librpc/gen_ndr/ndr_irpc.h"
26 #include "librpc/gen_ndr/ndr_winsrepl.h"
27 #include "wrepl_server/wrepl_server.h"
28 #include "nbt_server/wins/winsdb.h"
29 #include "libcli/wrepl/winsrepl.h"
30 #include "system/time.h"
31 #include "librpc/gen_ndr/ndr_nbt.h"
32 #include "param/param.h"
44 static const char *_R_ACTION_enum_string(enum _R_ACTION action
)
47 case R_INVALID
: return "INVALID";
48 case R_DO_REPLACE
: return "REPLACE";
49 case R_NOT_REPLACE
: return "NOT_REPLACE";
50 case R_DO_PROPAGATE
: return "PROPAGATE";
51 case R_DO_CHALLENGE
: return "CHALLEGNE";
52 case R_DO_RELEASE_DEMAND
: return "RELEASE_DEMAND";
53 case R_DO_SGROUP_MERGE
: return "SGROUP_MERGE";
56 return "enum _R_ACTION unknown";
59 #define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
61 #define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
63 #define R_IS_TOMBSTONE(r) ((r)->state == WREPL_STATE_TOMBSTONE)
65 #define R_IS_UNIQUE(r) ((r)->type == WREPL_TYPE_UNIQUE)
66 #define R_IS_GROUP(r) ((r)->type == WREPL_TYPE_GROUP)
67 #define R_IS_SGROUP(r) ((r)->type == WREPL_TYPE_SGROUP)
69 #define R_IS_MHOMED(r) ((r)->type == WREPL_TYPE_MHOMED)
72 /* blindly overwrite records from the same owner in all cases */
73 static enum _R_ACTION
replace_same_owner(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
79 static bool r_1_is_subset_of_2_address_list(struct winsdb_record
*r1
, struct wrepl_name
*r2
, bool check_owners
)
82 size_t len
= winsdb_addr_list_length(r1
->addresses
);
84 for (i
=0; i
< len
; i
++) {
86 for (j
=0; j
< r2
->num_addresses
; j
++) {
87 if (strcmp(r1
->addresses
[i
]->address
, r2
->addresses
[j
].address
) != 0) {
91 if (check_owners
&& strcmp(r1
->addresses
[i
]->wins_owner
, r2
->addresses
[j
].owner
) != 0) {
97 if (!found
) return false;
103 static bool r_1_is_superset_of_2_address_list(struct winsdb_record
*r1
, struct wrepl_name
*r2
, bool check_owners
)
106 size_t len
= winsdb_addr_list_length(r1
->addresses
);
108 for (i
=0; i
< r2
->num_addresses
; i
++) {
110 for (j
=0; j
< len
; j
++) {
111 if (strcmp(r2
->addresses
[i
].address
, r1
->addresses
[j
]->address
) != 0) {
115 if (check_owners
&& strcmp(r2
->addresses
[i
].owner
, r1
->addresses
[j
]->wins_owner
) != 0) {
121 if (!found
) return false;
127 static bool r_1_is_same_as_2_address_list(struct winsdb_record
*r1
, struct wrepl_name
*r2
, bool check_owners
)
129 size_t len
= winsdb_addr_list_length(r1
->addresses
);
131 if (len
!= r2
->num_addresses
) {
135 return r_1_is_superset_of_2_address_list(r1
, r2
, check_owners
);
138 static bool r_contains_addrs_from_owner(struct winsdb_record
*r1
, const char *owner
)
141 size_t len
= winsdb_addr_list_length(r1
->addresses
);
143 for (i
=0; i
< len
; i
++) {
144 if (strcmp(r1
->addresses
[i
]->wins_owner
, owner
) == 0) {
153 UNIQUE,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
154 UNIQUE,ACTIVE vs. UNIQUE,TOMBSTONE with different ip(s) => NOT REPLACE
155 UNIQUE,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
156 UNIQUE,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
157 UNIQUE,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
158 UNIQUE,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
159 UNIQUE,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
160 UNIQUE,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
161 UNIQUE,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
162 UNIQUE,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
163 UNIQUE,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
164 UNIQUE,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
165 UNIQUE,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
166 UNIQUE,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
167 UNIQUE,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
168 UNIQUE,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
169 UNIQUE,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
170 UNIQUE,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
171 UNIQUE,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
172 UNIQUE,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
173 UNIQUE,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
174 UNIQUE,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
175 UNIQUE,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
176 UNIQUE,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
178 static enum _R_ACTION
replace_unique_replica_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
180 if (!R_IS_ACTIVE(r1
)) {
185 if (!R_IS_SGROUP(r2
) && R_IS_ACTIVE(r2
)) {
191 return R_NOT_REPLACE
;
195 GROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
196 GROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
197 GROUP,RELEASED vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
198 GROUP,RELEASED vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
199 GROUP,TOMBSTONE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
200 GROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
201 GROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
202 GROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
203 GROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
204 GROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
205 GROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
206 GROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
207 GROUP,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
208 GROUP,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
209 GROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
210 GROUP,RELEASED vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
211 GROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
212 GROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
213 GROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
214 GROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
215 GROUP,RELEASED vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
216 GROUP,RELEASED vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
217 GROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
218 GROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
220 static enum _R_ACTION
replace_group_replica_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
222 if (!R_IS_ACTIVE(r1
) && R_IS_GROUP(r2
)) {
227 if (R_IS_TOMBSTONE(r1
) && !R_IS_UNIQUE(r2
)) {
233 return R_NOT_REPLACE
;
237 SGROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
238 SGROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
239 SGROUP,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
240 SGROUP,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
241 SGROUP,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
242 SGROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
243 SGROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
244 SGROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
245 SGROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
246 SGROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
247 SGROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
248 SGROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
249 SGROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
250 SGROUP,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
251 SGROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
252 SGROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
253 SGROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
254 SGROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
255 SGROUP,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
256 SGROUP,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
257 SGROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
258 SGROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
260 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
261 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
262 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
263 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
264 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
265 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
267 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
268 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4_X_3_4 => SGROUP_MERGE
269 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
270 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4_OWNER_B => B:A_3_4_OWNER_B_X_3_4 => SGROUP_MERGE
271 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:B_3_4_X_1_2 => C:B_3_4_X_1_2_3_4 => SGROUP_MERGE
272 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
275 this is a bit strange, incoming tombstone replicas always replace old replicas:
277 SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:NULL => B:NULL => REPLACE
278 SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4 => REPLACE
279 SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:B_3_4 => B:B_3_4 => REPLACE
280 SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:B_3_4_X_3_4 => B:B_3_4_X_3_4 => REPLACE
282 static enum _R_ACTION
replace_sgroup_replica_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
284 if (!R_IS_ACTIVE(r1
)) {
289 if (!R_IS_SGROUP(r2
)) {
291 return R_NOT_REPLACE
;
295 * this is strange, but correct
296 * the incoming tombstone replace the current active
299 if (!R_IS_ACTIVE(r2
)) {
304 if (r2
->num_addresses
== 0) {
305 if (r_contains_addrs_from_owner(r1
, r2
->owner
)) {
306 /* not handled here: MERGE */
307 return R_DO_SGROUP_MERGE
;
311 return R_NOT_REPLACE
;
314 if (r_1_is_superset_of_2_address_list(r1
, r2
, true)) {
316 return R_NOT_REPLACE
;
319 if (r_1_is_same_as_2_address_list(r1
, r2
, false)) {
324 /* not handled here: MERGE */
325 return R_DO_SGROUP_MERGE
;
329 MHOMED,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
330 MHOMED,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
331 MHOMED,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
332 MHOMED,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
333 MHOMED,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
334 MHOMED,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
335 MHOMED,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
336 MHOMED,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
337 MHOMED,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
338 MHOMED,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
339 MHOMED,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
340 MHOMED,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
341 MHOMED,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
342 MHOMED,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
343 MHOMED,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
344 MHOMED,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
345 MHOMED,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
346 MHOMED,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
347 MHOMED,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
348 MHOMED,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
349 MHOMED,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
350 MHOMED,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
351 MHOMED,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
352 MHOMED,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
354 static enum _R_ACTION
replace_mhomed_replica_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
356 if (!R_IS_ACTIVE(r1
)) {
361 if (!R_IS_SGROUP(r2
) && R_IS_ACTIVE(r2
)) {
367 return R_NOT_REPLACE
;
372 _UA_UA_SI_U<00> => REPLACE
373 _UA_UA_DI_P<00> => NOT REPLACE
374 _UA_UA_DI_O<00> => NOT REPLACE
375 _UA_UA_DI_N<00> => REPLACE
376 _UA_UT_SI_U<00> => NOT REPLACE
377 _UA_UT_DI_U<00> => NOT REPLACE
378 _UA_GA_SI_R<00> => REPLACE
379 _UA_GA_DI_R<00> => REPLACE
380 _UA_GT_SI_U<00> => NOT REPLACE
381 _UA_GT_DI_U<00> => NOT REPLACE
382 _UA_SA_SI_R<00> => REPLACE
383 _UA_SA_DI_R<00> => REPLACE
384 _UA_ST_SI_U<00> => NOT REPLACE
385 _UA_ST_DI_U<00> => NOT REPLACE
386 _UA_MA_SI_U<00> => REPLACE
387 _UA_MA_SP_U<00> => REPLACE
388 _UA_MA_DI_P<00> => NOT REPLACE
389 _UA_MA_DI_O<00> => NOT REPLACE
390 _UA_MA_DI_N<00> => REPLACE
391 _UA_MT_SI_U<00> => NOT REPLACE
392 _UA_MT_DI_U<00> => NOT REPLACE
393 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
394 _UA_UA_DI_A<00> => MHOMED_MERGE
395 _UA_MA_DI_A<00> => MHOMED_MERGE
398 _UR_UA_SI<00> => REPLACE
399 _UR_UA_DI<00> => REPLACE
400 _UR_UT_SI<00> => REPLACE
401 _UR_UT_DI<00> => REPLACE
402 _UR_GA_SI<00> => REPLACE
403 _UR_GA_DI<00> => REPLACE
404 _UR_GT_SI<00> => REPLACE
405 _UR_GT_DI<00> => REPLACE
406 _UR_SA_SI<00> => REPLACE
407 _UR_SA_DI<00> => REPLACE
408 _UR_ST_SI<00> => REPLACE
409 _UR_ST_DI<00> => REPLACE
410 _UR_MA_SI<00> => REPLACE
411 _UR_MA_DI<00> => REPLACE
412 _UR_MT_SI<00> => REPLACE
413 _UR_MT_DI<00> => REPLACE
415 static enum _R_ACTION
replace_unique_owned_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
417 if (!R_IS_ACTIVE(r1
)) {
422 if (!R_IS_ACTIVE(r2
)) {
423 /* NOT REPLACE, and PROPAGATE */
424 return R_DO_PROPAGATE
;
427 if (R_IS_GROUP(r2
) || R_IS_SGROUP(r2
)) {
428 /* REPLACE and send a release demand to the old name owner */
429 return R_DO_RELEASE_DEMAND
;
433 * here we only have unique,active,owned vs.
434 * is unique,active,replica or mhomed,active,replica
437 if (r_1_is_subset_of_2_address_list(r1
, r2
, false)) {
439 * if r1 has a subset(or same) of the addresses of r2
441 * if r2 has a superset(or same) of the addresses of r1
443 * then replace the record
449 * in any other case, we need to do
450 * a name request to the old name holder
451 * to see if it's still there...
453 return R_DO_CHALLENGE
;
458 _GA_UA_SI_U<00> => NOT REPLACE
459 _GA_UA_DI_U<00> => NOT REPLACE
460 _GA_UT_SI_U<00> => NOT REPLACE
461 _GA_UT_DI_U<00> => NOT REPLACE
462 _GA_GA_SI_U<00> => REPLACE
463 _GA_GA_DI_U<00> => REPLACE
464 _GA_GT_SI_U<00> => NOT REPLACE
465 _GA_GT_DI_U<00> => NOT REPLACE
466 _GA_SA_SI_U<00> => NOT REPLACE
467 _GA_SA_DI_U<00> => NOT REPLACE
468 _GA_ST_SI_U<00> => NOT REPLACE
469 _GA_ST_DI_U<00> => NOT REPLACE
470 _GA_MA_SI_U<00> => NOT REPLACE
471 _GA_MA_DI_U<00> => NOT REPLACE
472 _GA_MT_SI_U<00> => NOT REPLACE
473 _GA_MT_DI_U<00> => NOT REPLACE
476 _GR_UA_SI<00> => NOT REPLACE
477 _GR_UA_DI<00> => NOT REPLACE
478 _GR_UT_SI<00> => NOT REPLACE
479 _GR_UT_DI<00> => NOT REPLACE
480 _GR_GA_SI<00> => REPLACE
481 _GR_GA_DI<00> => REPLACE
482 _GR_GT_SI<00> => REPLACE
483 _GR_GT_DI<00> => REPLACE
484 _GR_SA_SI<00> => NOT REPLACE
485 _GR_SA_DI<00> => NOT REPLACE
486 _GR_ST_SI<00> => NOT REPLACE
487 _GR_ST_DI<00> => NOT REPLACE
488 _GR_MA_SI<00> => NOT REPLACE
489 _GR_MA_DI<00> => NOT REPLACE
490 _GR_MT_SI<00> => NOT REPLACE
491 _GR_MT_DI<00> => NOT REPLACE
493 static enum _R_ACTION
replace_group_owned_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
495 if (R_IS_GROUP(r1
) && R_IS_GROUP(r2
)) {
496 if (!R_IS_ACTIVE(r1
) || R_IS_ACTIVE(r2
)) {
502 /* NOT REPLACE, but PROPAGATE */
503 return R_DO_PROPAGATE
;
507 active (not sgroup vs. sgroup yet!):
508 _SA_UA_SI_U<1c> => NOT REPLACE
509 _SA_UA_DI_U<1c> => NOT REPLACE
510 _SA_UT_SI_U<1c> => NOT REPLACE
511 _SA_UT_DI_U<1c> => NOT REPLACE
512 _SA_GA_SI_U<1c> => NOT REPLACE
513 _SA_GA_DI_U<1c> => NOT REPLACE
514 _SA_GT_SI_U<1c> => NOT REPLACE
515 _SA_GT_DI_U<1c> => NOT REPLACE
516 _SA_MA_SI_U<1c> => NOT REPLACE
517 _SA_MA_DI_U<1c> => NOT REPLACE
518 _SA_MT_SI_U<1c> => NOT REPLACE
519 _SA_MT_DI_U<1c> => NOT REPLACE
521 Test Replica vs. owned active: SGROUP vs. SGROUP tests
522 _SA_SA_DI_U<1c> => SGROUP_MERGE
523 _SA_SA_SI_U<1c> => SGROUP_MERGE
524 _SA_SA_SP_U<1c> => SGROUP_MERGE
525 _SA_SA_SB_U<1c> => SGROUP_MERGE
526 _SA_ST_DI_U<1c> => NOT REPLACE
527 _SA_ST_SI_U<1c> => NOT REPLACE
528 _SA_ST_SP_U<1c> => NOT REPLACE
529 _SA_ST_SB_U<1c> => NOT REPLACE
531 SGROUP,ACTIVE vs. SGROUP,* is not handled here!
534 _SR_UA_SI<1c> => REPLACE
535 _SR_UA_DI<1c> => REPLACE
536 _SR_UT_SI<1c> => REPLACE
537 _SR_UT_DI<1c> => REPLACE
538 _SR_GA_SI<1c> => REPLACE
539 _SR_GA_DI<1c> => REPLACE
540 _SR_GT_SI<1c> => REPLACE
541 _SR_GT_DI<1c> => REPLACE
542 _SR_SA_SI<1c> => REPLACE
543 _SR_SA_DI<1c> => REPLACE
544 _SR_ST_SI<1c> => REPLACE
545 _SR_ST_DI<1c> => REPLACE
546 _SR_MA_SI<1c> => REPLACE
547 _SR_MA_DI<1c> => REPLACE
548 _SR_MT_SI<1c> => REPLACE
549 _SR_MT_DI<1c> => REPLACE
551 static enum _R_ACTION
replace_sgroup_owned_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
553 if (!R_IS_ACTIVE(r1
)) {
558 if (!R_IS_SGROUP(r2
) || !R_IS_ACTIVE(r2
)) {
559 /* NOT REPLACE, but PROPAGATE */
560 return R_DO_PROPAGATE
;
563 if (r_1_is_same_as_2_address_list(r1
, r2
, true)) {
565 * as we're the old owner and the addresses and their
566 * owners are identical
568 return R_NOT_REPLACE
;
571 /* not handled here: MERGE */
572 return R_DO_SGROUP_MERGE
;
577 _MA_UA_SI_U<00> => REPLACE
578 _MA_UA_DI_P<00> => NOT REPLACE
579 _MA_UA_DI_O<00> => NOT REPLACE
580 _MA_UA_DI_N<00> => REPLACE
581 _MA_UT_SI_U<00> => NOT REPLACE
582 _MA_UT_DI_U<00> => NOT REPLACE
583 _MA_GA_SI_R<00> => REPLACE
584 _MA_GA_DI_R<00> => REPLACE
585 _MA_GT_SI_U<00> => NOT REPLACE
586 _MA_GT_DI_U<00> => NOT REPLACE
587 _MA_SA_SI_R<00> => REPLACE
588 _MA_SA_DI_R<00> => REPLACE
589 _MA_ST_SI_U<00> => NOT REPLACE
590 _MA_ST_DI_U<00> => NOT REPLACE
591 _MA_MA_SI_U<00> => REPLACE
592 _MA_MA_SP_U<00> => REPLACE
593 _MA_MA_DI_P<00> => NOT REPLACE
594 _MA_MA_DI_O<00> => NOT REPLACE
595 _MA_MA_DI_N<00> => REPLACE
596 _MA_MT_SI_U<00> => NOT REPLACE
597 _MA_MT_DI_U<00> => NOT REPLACE
598 Test Replica vs. owned active: some more MHOMED combinations
599 _MA_MA_SP_U<00> => REPLACE
600 _MA_MA_SM_U<00> => REPLACE
601 _MA_MA_SB_P<00> => MHOMED_MERGE
602 _MA_MA_SB_A<00> => MHOMED_MERGE
603 _MA_MA_SB_PRA<00> => NOT REPLACE
604 _MA_MA_SB_O<00> => NOT REPLACE
605 _MA_MA_SB_N<00> => REPLACE
606 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
607 _MA_UA_SB_P<00> => MHOMED_MERGE
610 _MR_UA_SI<00> => REPLACE
611 _MR_UA_DI<00> => REPLACE
612 _MR_UT_SI<00> => REPLACE
613 _MR_UT_DI<00> => REPLACE
614 _MR_GA_SI<00> => REPLACE
615 _MR_GA_DI<00> => REPLACE
616 _MR_GT_SI<00> => REPLACE
617 _MR_GT_DI<00> => REPLACE
618 _MR_SA_SI<00> => REPLACE
619 _MR_SA_DI<00> => REPLACE
620 _MR_ST_SI<00> => REPLACE
621 _MR_ST_DI<00> => REPLACE
622 _MR_MA_SI<00> => REPLACE
623 _MR_MA_DI<00> => REPLACE
624 _MR_MT_SI<00> => REPLACE
625 _MR_MT_DI<00> => REPLACE
627 static enum _R_ACTION
replace_mhomed_owned_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
629 if (!R_IS_ACTIVE(r1
)) {
634 if (!R_IS_ACTIVE(r2
)) {
635 /* NOT REPLACE, but PROPAGATE */
636 return R_DO_PROPAGATE
;
639 if (R_IS_GROUP(r2
) || R_IS_SGROUP(r2
)) {
640 /* REPLACE and send a release demand to the old name owner */
641 return R_DO_RELEASE_DEMAND
;
645 * here we only have mhomed,active,owned vs.
646 * is unique,active,replica or mhomed,active,replica
649 if (r_1_is_subset_of_2_address_list(r1
, r2
, false)) {
651 * if r1 has a subset(or same) of the addresses of r2
653 * if r2 has a superset(or same) of the addresses of r1
655 * then replace the record
661 * in any other case, we need to do
662 * a name request to the old name holder
663 * to see if it's still there...
665 return R_DO_CHALLENGE
;
668 static NTSTATUS
r_do_add(struct wreplsrv_partner
*partner
,
670 struct wrepl_wins_owner
*owner
,
671 struct wrepl_name
*replica
)
673 struct winsdb_record
*rec
;
677 rec
= talloc(mem_ctx
, struct winsdb_record
);
678 NT_STATUS_HAVE_NO_MEMORY(rec
);
680 rec
->name
= &replica
->name
;
681 rec
->type
= replica
->type
;
682 rec
->state
= replica
->state
;
683 rec
->node
= replica
->node
;
684 rec
->is_static
= replica
->is_static
;
685 rec
->expire_time
= time(NULL
) + partner
->service
->config
.verify_interval
;
686 rec
->version
= replica
->version_id
;
687 rec
->wins_owner
= replica
->owner
;
688 rec
->addresses
= winsdb_addr_list_make(rec
);
689 NT_STATUS_HAVE_NO_MEMORY(rec
->addresses
);
690 rec
->registered_by
= NULL
;
692 for (i
=0; i
< replica
->num_addresses
; i
++) {
693 /* TODO: find out if rec->expire_time is correct here */
694 rec
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
696 replica
->addresses
[i
].address
,
697 replica
->addresses
[i
].owner
,
700 NT_STATUS_HAVE_NO_MEMORY(rec
->addresses
);
703 ret
= winsdb_add(partner
->service
->wins_db
, rec
, 0);
704 if (ret
!= NBT_RCODE_OK
) {
705 DEBUG(0,("Failed to add record %s: %u\n",
706 nbt_name_string(mem_ctx
, &replica
->name
), ret
));
707 return NT_STATUS_FOOBAR
;
710 DEBUG(4,("added record %s\n",
711 nbt_name_string(mem_ctx
, &replica
->name
)));
716 static NTSTATUS
r_do_replace(struct wreplsrv_partner
*partner
,
718 struct winsdb_record
*rec
,
719 struct wrepl_wins_owner
*owner
,
720 struct wrepl_name
*replica
)
725 rec
->name
= &replica
->name
;
726 rec
->type
= replica
->type
;
727 rec
->state
= replica
->state
;
728 rec
->node
= replica
->node
;
729 rec
->is_static
= replica
->is_static
;
730 rec
->expire_time
= time(NULL
) + partner
->service
->config
.verify_interval
;
731 rec
->version
= replica
->version_id
;
732 rec
->wins_owner
= replica
->owner
;
733 rec
->addresses
= winsdb_addr_list_make(rec
);
734 NT_STATUS_HAVE_NO_MEMORY(rec
->addresses
);
735 rec
->registered_by
= NULL
;
737 for (i
=0; i
< replica
->num_addresses
; i
++) {
738 /* TODO: find out if rec->expire_time is correct here */
739 rec
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
741 replica
->addresses
[i
].address
,
742 replica
->addresses
[i
].owner
,
745 NT_STATUS_HAVE_NO_MEMORY(rec
->addresses
);
748 ret
= winsdb_modify(partner
->service
->wins_db
, rec
, 0);
749 if (ret
!= NBT_RCODE_OK
) {
750 DEBUG(0,("Failed to replace record %s: %u\n",
751 nbt_name_string(mem_ctx
, &replica
->name
), ret
));
752 return NT_STATUS_FOOBAR
;
755 DEBUG(4,("replaced record %s\n",
756 nbt_name_string(mem_ctx
, &replica
->name
)));
761 static NTSTATUS
r_not_replace(struct wreplsrv_partner
*partner
,
763 struct winsdb_record
*rec
,
764 struct wrepl_wins_owner
*owner
,
765 struct wrepl_name
*replica
)
767 DEBUG(4,("not replace record %s\n",
768 nbt_name_string(mem_ctx
, &replica
->name
)));
772 static NTSTATUS
r_do_propagate(struct wreplsrv_partner
*partner
,
774 struct winsdb_record
*rec
,
775 struct wrepl_wins_owner
*owner
,
776 struct wrepl_name
*replica
)
779 uint32_t modify_flags
;
782 * allocate a new version id for the record to that it'll be replicated
784 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
786 ret
= winsdb_modify(partner
->service
->wins_db
, rec
, modify_flags
);
787 if (ret
!= NBT_RCODE_OK
) {
788 DEBUG(0,("Failed to replace record %s: %u\n",
789 nbt_name_string(mem_ctx
, &replica
->name
), ret
));
790 return NT_STATUS_FOOBAR
;
793 DEBUG(4,("propagated record %s\n",
794 nbt_name_string(mem_ctx
, &replica
->name
)));
800 Test Replica vs. owned active: some more MHOMED combinations
801 _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
802 _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
803 _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
804 _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
805 _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
806 _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
807 _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
808 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
809 _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
810 _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
811 _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
812 _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
814 static NTSTATUS
r_do_mhomed_merge(struct wreplsrv_partner
*partner
,
816 struct winsdb_record
*rec
,
817 struct wrepl_wins_owner
*owner
,
818 struct wrepl_name
*replica
)
820 struct winsdb_record
*merge
;
825 merge
= talloc(mem_ctx
, struct winsdb_record
);
826 NT_STATUS_HAVE_NO_MEMORY(merge
);
828 merge
->name
= &replica
->name
;
829 merge
->type
= WREPL_TYPE_MHOMED
;
830 merge
->state
= replica
->state
;
831 merge
->node
= replica
->node
;
832 merge
->is_static
= replica
->is_static
;
833 merge
->expire_time
= time(NULL
) + partner
->service
->config
.verify_interval
;
834 merge
->version
= replica
->version_id
;
835 merge
->wins_owner
= replica
->owner
;
836 merge
->addresses
= winsdb_addr_list_make(merge
);
837 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
838 merge
->registered_by
= NULL
;
840 for (i
=0; i
< replica
->num_addresses
; i
++) {
841 merge
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
842 merge
, merge
->addresses
,
843 replica
->addresses
[i
].address
,
844 replica
->addresses
[i
].owner
,
847 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
850 len
= winsdb_addr_list_length(rec
->addresses
);
852 for (i
=0; i
< len
; i
++) {
854 for (j
=0; j
< replica
->num_addresses
; j
++) {
855 if (strcmp(replica
->addresses
[j
].address
, rec
->addresses
[i
]->address
) == 0) {
862 merge
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
863 merge
, merge
->addresses
,
864 rec
->addresses
[i
]->address
,
865 rec
->addresses
[i
]->wins_owner
,
866 rec
->addresses
[i
]->expire_time
,
868 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
871 ret
= winsdb_modify(partner
->service
->wins_db
, merge
, 0);
872 if (ret
!= NBT_RCODE_OK
) {
873 DEBUG(0,("Failed to modify mhomed merge record %s: %u\n",
874 nbt_name_string(mem_ctx
, &replica
->name
), ret
));
875 return NT_STATUS_FOOBAR
;
878 DEBUG(4,("mhomed merge record %s\n",
879 nbt_name_string(mem_ctx
, &replica
->name
)));
884 struct r_do_challenge_state
{
885 struct messaging_context
*msg_ctx
;
886 struct wreplsrv_partner
*partner
;
887 struct winsdb_record
*rec
;
888 struct wrepl_wins_owner owner
;
889 struct wrepl_name replica
;
890 struct nbtd_proxy_wins_challenge r
;
893 static void r_do_late_release_demand_handler(struct irpc_request
*ireq
)
896 struct r_do_challenge_state
*state
= talloc_get_type(ireq
->async
.private_data
,
897 struct r_do_challenge_state
);
899 status
= irpc_call_recv(ireq
);
900 /* don't care about the result */
904 static NTSTATUS
r_do_late_release_demand(struct r_do_challenge_state
*state
)
906 struct irpc_request
*ireq
;
907 struct server_id
*nbt_servers
;
908 struct nbtd_proxy_wins_release_demand r
;
911 DEBUG(4,("late release demand record %s\n",
912 nbt_name_string(state
, &state
->replica
.name
)));
914 nbt_servers
= irpc_servers_byname(state
->msg_ctx
, state
, "nbt_server");
915 if ((nbt_servers
== NULL
) || (nbt_servers
[0].id
== 0)) {
916 return NT_STATUS_INTERNAL_ERROR
;
919 r
.in
.name
= state
->replica
.name
;
920 r
.in
.num_addrs
= state
->r
.out
.num_addrs
;
921 r
.in
.addrs
= talloc_array(state
, struct nbtd_proxy_wins_addr
, r
.in
.num_addrs
);
922 NT_STATUS_HAVE_NO_MEMORY(r
.in
.addrs
);
923 /* TODO: fix pidl to handle inline ipv4address arrays */
924 for (i
=0; i
< r
.in
.num_addrs
; i
++) {
925 r
.in
.addrs
[i
].addr
= state
->r
.out
.addrs
[i
].addr
;
928 ireq
= IRPC_CALL_SEND(state
->msg_ctx
, nbt_servers
[0],
929 irpc
, NBTD_PROXY_WINS_RELEASE_DEMAND
,
931 NT_STATUS_HAVE_NO_MEMORY(ireq
);
933 ireq
->async
.fn
= r_do_late_release_demand_handler
;
934 ireq
->async
.private_data
= state
;
940 Test Replica vs. owned active: some more MHOMED combinations
941 _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
942 _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
943 _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
944 _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
945 _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
946 _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
947 _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
948 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
949 _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
950 _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
951 _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
952 _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
954 static void r_do_challenge_handler(struct irpc_request
*ireq
)
957 struct r_do_challenge_state
*state
= talloc_get_type(ireq
->async
.private_data
,
958 struct r_do_challenge_state
);
959 bool old_is_subset
= false;
960 bool new_is_subset
= false;
963 uint32_t num_rec_addrs
;
965 status
= irpc_call_recv(ireq
);
967 DEBUG(4,("r_do_challenge_handler: %s: %s\n",
968 nbt_name_string(state
, &state
->replica
.name
), nt_errstr(status
)));
970 if (NT_STATUS_EQUAL(NT_STATUS_IO_TIMEOUT
, status
) ||
971 NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND
, status
)) {
972 r_do_replace(state
->partner
, state
, state
->rec
, &state
->owner
, &state
->replica
);
977 for (i
=0; i
< state
->replica
.num_addresses
; i
++) {
979 new_is_subset
= true;
980 for (j
=0; j
< state
->r
.out
.num_addrs
; j
++) {
981 if (strcmp(state
->replica
.addresses
[i
].address
, state
->r
.out
.addrs
[j
].addr
) == 0) {
988 new_is_subset
= false;
992 if (!new_is_subset
) {
993 r_not_replace(state
->partner
, state
, state
->rec
, &state
->owner
, &state
->replica
);
998 num_rec_addrs
= winsdb_addr_list_length(state
->rec
->addresses
);
999 for (i
=0; i
< num_rec_addrs
; i
++) {
1001 old_is_subset
= true;
1002 for (j
=0; j
< state
->r
.out
.num_addrs
; j
++) {
1003 if (strcmp(state
->rec
->addresses
[i
]->address
, state
->r
.out
.addrs
[j
].addr
) == 0) {
1008 if (found
) continue;
1010 old_is_subset
= false;
1014 if (!old_is_subset
) {
1015 status
= r_do_late_release_demand(state
);
1017 * only free state on error, because we pass it down,
1018 * and r_do_late_release_demand() will free it
1020 if (!NT_STATUS_IS_OK(status
)) {
1026 r_do_mhomed_merge(state
->partner
, state
, state
->rec
, &state
->owner
, &state
->replica
);
1030 static NTSTATUS
r_do_challenge(struct wreplsrv_partner
*partner
,
1031 TALLOC_CTX
*mem_ctx
,
1032 struct winsdb_record
*rec
,
1033 struct wrepl_wins_owner
*owner
,
1034 struct wrepl_name
*replica
)
1036 struct irpc_request
*ireq
;
1037 struct r_do_challenge_state
*state
;
1038 struct server_id
*nbt_servers
;
1042 DEBUG(4,("challenge record %s\n",
1043 nbt_name_string(mem_ctx
, &replica
->name
)));
1045 state
= talloc_zero(mem_ctx
, struct r_do_challenge_state
);
1046 NT_STATUS_HAVE_NO_MEMORY(state
);
1047 state
->msg_ctx
= partner
->service
->task
->msg_ctx
;
1048 state
->partner
= partner
;
1049 state
->rec
= talloc_steal(state
, rec
);
1050 state
->owner
= *owner
;
1051 state
->replica
= *replica
;
1052 /* some stuff to have valid memory pointers in the async complete function */
1053 state
->replica
.name
= *state
->rec
->name
;
1054 talloc_steal(state
, replica
->owner
);
1055 talloc_steal(state
, replica
->addresses
);
1057 nbt_servers
= irpc_servers_byname(state
->msg_ctx
, state
, "nbt_server");
1058 if ((nbt_servers
== NULL
) || (nbt_servers
[0].id
== 0)) {
1059 return NT_STATUS_INTERNAL_ERROR
;
1062 state
->r
.in
.name
= *rec
->name
;
1063 state
->r
.in
.num_addrs
= winsdb_addr_list_length(rec
->addresses
);
1064 state
->r
.in
.addrs
= talloc_array(state
, struct nbtd_proxy_wins_addr
, state
->r
.in
.num_addrs
);
1065 NT_STATUS_HAVE_NO_MEMORY(state
->r
.in
.addrs
);
1066 /* TODO: fix pidl to handle inline ipv4address arrays */
1067 addrs
= winsdb_addr_string_list(state
->r
.in
.addrs
, rec
->addresses
);
1068 NT_STATUS_HAVE_NO_MEMORY(addrs
);
1069 for (i
=0; i
< state
->r
.in
.num_addrs
; i
++) {
1070 state
->r
.in
.addrs
[i
].addr
= addrs
[i
];
1073 ireq
= IRPC_CALL_SEND(state
->msg_ctx
, nbt_servers
[0],
1074 irpc
, NBTD_PROXY_WINS_CHALLENGE
,
1076 NT_STATUS_HAVE_NO_MEMORY(ireq
);
1078 ireq
->async
.fn
= r_do_challenge_handler
;
1079 ireq
->async
.private_data
= state
;
1081 talloc_steal(partner
, state
);
1082 return NT_STATUS_OK
;
1085 struct r_do_release_demand_state
{
1086 struct messaging_context
*msg_ctx
;
1087 struct nbtd_proxy_wins_release_demand r
;
1090 static void r_do_release_demand_handler(struct irpc_request
*ireq
)
1093 struct r_do_release_demand_state
*state
= talloc_get_type(ireq
->async
.private_data
,
1094 struct r_do_release_demand_state
);
1096 status
= irpc_call_recv(ireq
);
1097 /* don't care about the result */
1101 static NTSTATUS
r_do_release_demand(struct wreplsrv_partner
*partner
,
1102 TALLOC_CTX
*mem_ctx
,
1103 struct winsdb_record
*rec
,
1104 struct wrepl_wins_owner
*owner
,
1105 struct wrepl_name
*replica
)
1108 struct irpc_request
*ireq
;
1109 struct server_id
*nbt_servers
;
1111 struct winsdb_addr
**addresses
;
1112 struct r_do_release_demand_state
*state
;
1116 * we need to get a reference to the old addresses,
1117 * as we need to send a release demand to them after replacing the record
1118 * and r_do_replace() will modify rec->addresses
1120 addresses
= rec
->addresses
;
1122 status
= r_do_replace(partner
, mem_ctx
, rec
, owner
, replica
);
1123 NT_STATUS_NOT_OK_RETURN(status
);
1125 DEBUG(4,("release demand record %s\n",
1126 nbt_name_string(mem_ctx
, &replica
->name
)));
1128 state
= talloc_zero(mem_ctx
, struct r_do_release_demand_state
);
1129 NT_STATUS_HAVE_NO_MEMORY(state
);
1130 state
->msg_ctx
= partner
->service
->task
->msg_ctx
;
1132 nbt_servers
= irpc_servers_byname(state
->msg_ctx
, state
, "nbt_server");
1133 if ((nbt_servers
== NULL
) || (nbt_servers
[0].id
== 0)) {
1134 return NT_STATUS_INTERNAL_ERROR
;
1137 state
->r
.in
.name
= *rec
->name
;
1138 state
->r
.in
.num_addrs
= winsdb_addr_list_length(addresses
);
1139 state
->r
.in
.addrs
= talloc_array(state
, struct nbtd_proxy_wins_addr
,
1140 state
->r
.in
.num_addrs
);
1141 NT_STATUS_HAVE_NO_MEMORY(state
->r
.in
.addrs
);
1142 /* TODO: fix pidl to handle inline ipv4address arrays */
1143 addrs
= winsdb_addr_string_list(state
->r
.in
.addrs
, addresses
);
1144 NT_STATUS_HAVE_NO_MEMORY(addrs
);
1145 for (i
=0; i
< state
->r
.in
.num_addrs
; i
++) {
1146 state
->r
.in
.addrs
[i
].addr
= addrs
[i
];
1149 ireq
= IRPC_CALL_SEND(state
->msg_ctx
, nbt_servers
[0],
1150 irpc
, NBTD_PROXY_WINS_RELEASE_DEMAND
,
1152 NT_STATUS_HAVE_NO_MEMORY(ireq
);
1154 ireq
->async
.fn
= r_do_release_demand_handler
;
1155 ireq
->async
.private_data
= state
;
1157 talloc_steal(partner
, state
);
1158 return NT_STATUS_OK
;
1162 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
1163 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
1164 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
1165 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
1166 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
1167 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
1169 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
1170 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4_X_3_4 => SGROUP_MERGE
1171 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
1172 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4_OWNER_B => B:A_3_4_OWNER_B_X_3_4 => SGROUP_MERGE
1173 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:B_3_4_X_1_2 => C:B_3_4_X_1_2_3_4 => SGROUP_MERGE
1174 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
1176 Test Replica vs. owned active: SGROUP vs. SGROUP tests
1177 _SA_SA_DI_U<1c> => SGROUP_MERGE
1178 _SA_SA_SI_U<1c> => SGROUP_MERGE
1179 _SA_SA_SP_U<1c> => SGROUP_MERGE
1180 _SA_SA_SB_U<1c> => SGROUP_MERGE
1182 static NTSTATUS
r_do_sgroup_merge(struct wreplsrv_partner
*partner
,
1183 TALLOC_CTX
*mem_ctx
,
1184 struct winsdb_record
*rec
,
1185 struct wrepl_wins_owner
*owner
,
1186 struct wrepl_name
*replica
)
1188 struct winsdb_record
*merge
;
1189 uint32_t modify_flags
= 0;
1193 bool changed_old_addrs
= false;
1194 bool skip_replica_owned_by_us
= false;
1195 bool become_owner
= true;
1196 bool propagate
= lp_parm_bool(partner
->service
->task
->lp_ctx
, NULL
, "wreplsrv", "propagate name releases", false);
1197 const char *local_owner
= partner
->service
->wins_db
->local_owner
;
1199 merge
= talloc(mem_ctx
, struct winsdb_record
);
1200 NT_STATUS_HAVE_NO_MEMORY(merge
);
1202 merge
->name
= &replica
->name
;
1203 merge
->type
= replica
->type
;
1204 merge
->state
= replica
->state
;
1205 merge
->node
= replica
->node
;
1206 merge
->is_static
= replica
->is_static
;
1207 merge
->expire_time
= time(NULL
) + partner
->service
->config
.verify_interval
;
1208 merge
->version
= replica
->version_id
;
1209 merge
->wins_owner
= replica
->owner
;
1210 merge
->addresses
= winsdb_addr_list_make(merge
);
1211 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
1212 merge
->registered_by
= NULL
;
1214 len
= winsdb_addr_list_length(rec
->addresses
);
1216 for (i
=0; i
< len
; i
++) {
1219 for (j
=0; j
< replica
->num_addresses
; j
++) {
1220 if (strcmp(rec
->addresses
[i
]->address
, replica
->addresses
[j
].address
) != 0) {
1226 if (strcmp(rec
->addresses
[i
]->wins_owner
, replica
->addresses
[j
].owner
) != 0) {
1227 changed_old_addrs
= true;
1234 * if the address isn't in the replica and is owned by replicas owner,
1235 * it won't be added to the merged record
1237 if (!found
&& strcmp(rec
->addresses
[i
]->wins_owner
, owner
->address
) == 0) {
1238 changed_old_addrs
= true;
1243 * add the address to the merge result, with the old owner and expire_time,
1244 * the owner and expire_time will be overwritten later if the address is
1245 * in the replica too
1247 merge
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
1248 merge
, merge
->addresses
,
1249 rec
->addresses
[i
]->address
,
1250 rec
->addresses
[i
]->wins_owner
,
1251 rec
->addresses
[i
]->expire_time
,
1253 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
1256 for (i
=0; i
< replica
->num_addresses
; i
++) {
1258 strcmp(replica
->addresses
[i
].owner
, local_owner
) == 0) {
1259 const struct winsdb_addr
*a
;
1262 * NOTE: this is different to the windows behavior
1263 * and off by default, but it better propagated
1266 a
= winsdb_addr_list_check(merge
->addresses
,
1267 replica
->addresses
[i
].address
);
1269 /* don't add addresses owned by us */
1270 skip_replica_owned_by_us
= true;
1274 merge
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
1275 merge
, merge
->addresses
,
1276 replica
->addresses
[i
].address
,
1277 replica
->addresses
[i
].owner
,
1280 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
1283 /* we the old addresses change changed we don't become the owner */
1284 if (changed_old_addrs
) {
1285 become_owner
= false;
1289 * when we notice another server believes an address
1290 * is owned by us and that's not the case
1291 * we propagate the result
1293 if (skip_replica_owned_by_us
) {
1294 become_owner
= true;
1297 /* if we're the owner of the old record, we'll be the owner of the new one too */
1298 if (strcmp(rec
->wins_owner
, local_owner
)==0) {
1299 become_owner
= true;
1303 * if the result has no addresses we take the ownership
1305 len
= winsdb_addr_list_length(merge
->addresses
);
1307 become_owner
= true;
1311 * if addresses of the old record will be changed the replica owner
1312 * will be owner of the merge result, otherwise we take the ownership
1317 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
1320 * if we're the owner, the expire time becomes the highest
1321 * expire time of owned addresses
1323 len
= winsdb_addr_list_length(merge
->addresses
);
1325 for (i
=0; i
< len
; i
++) {
1326 if (strcmp(merge
->addresses
[i
]->wins_owner
, local_owner
)==0) {
1327 lh
= MAX(lh
, merge
->addresses
[i
]->expire_time
);
1332 merge
->expire_time
= lh
;
1336 ret
= winsdb_modify(partner
->service
->wins_db
, merge
, modify_flags
);
1337 if (ret
!= NBT_RCODE_OK
) {
1338 DEBUG(0,("Failed to modify sgroup merge record %s: %u\n",
1339 nbt_name_string(mem_ctx
, &replica
->name
), ret
));
1340 return NT_STATUS_FOOBAR
;
1343 DEBUG(4,("sgroup merge record %s\n",
1344 nbt_name_string(mem_ctx
, &replica
->name
)));
1346 return NT_STATUS_OK
;
1349 static NTSTATUS
wreplsrv_apply_one_record(struct wreplsrv_partner
*partner
,
1350 TALLOC_CTX
*mem_ctx
,
1351 struct wrepl_wins_owner
*owner
,
1352 struct wrepl_name
*replica
)
1355 struct winsdb_record
*rec
= NULL
;
1356 enum _R_ACTION action
= R_INVALID
;
1357 bool same_owner
= false;
1358 bool replica_vs_replica
= false;
1359 bool local_vs_replica
= false;
1361 if (replica
->name
.scope
) {
1366 * Windows 2008 truncates the scope to 237 bytes,
1369 parent
= talloc_parent(replica
->name
.scope
);
1370 scope
= talloc_strndup(parent
, replica
->name
.scope
, 237);
1371 NT_STATUS_HAVE_NO_MEMORY(scope
);
1372 replica
->name
.scope
= scope
;
1375 status
= winsdb_lookup(partner
->service
->wins_db
,
1376 &replica
->name
, mem_ctx
, &rec
);
1377 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND
, status
)) {
1378 return r_do_add(partner
, mem_ctx
, owner
, replica
);
1380 NT_STATUS_NOT_OK_RETURN(status
);
1382 if (strcmp(rec
->wins_owner
, partner
->service
->wins_db
->local_owner
)==0) {
1383 local_vs_replica
= true;
1384 } else if (strcmp(rec
->wins_owner
, owner
->address
)==0) {
1387 replica_vs_replica
= true;
1390 if (rec
->is_static
&& !same_owner
) {
1391 action
= R_NOT_REPLACE
;
1394 * if we own the local record, then propagate it back to
1395 * the other wins servers.
1396 * to prevent ping-pong with other servers, we don't do this
1397 * if the replica is static too.
1399 * It seems that w2k3 doesn't do this, but I thing that's a bug
1400 * and doing propagation helps to have consistent data on all servers
1402 if (local_vs_replica
&& !replica
->is_static
) {
1403 action
= R_DO_PROPAGATE
;
1405 } else if (replica
->is_static
&& !rec
->is_static
&& !same_owner
) {
1406 action
= R_DO_REPLACE
;
1407 } else if (same_owner
) {
1408 action
= replace_same_owner(rec
, replica
);
1409 } else if (replica_vs_replica
) {
1410 switch (rec
->type
) {
1411 case WREPL_TYPE_UNIQUE
:
1412 action
= replace_unique_replica_vs_X_replica(rec
, replica
);
1414 case WREPL_TYPE_GROUP
:
1415 action
= replace_group_replica_vs_X_replica(rec
, replica
);
1417 case WREPL_TYPE_SGROUP
:
1418 action
= replace_sgroup_replica_vs_X_replica(rec
, replica
);
1420 case WREPL_TYPE_MHOMED
:
1421 action
= replace_mhomed_replica_vs_X_replica(rec
, replica
);
1424 } else if (local_vs_replica
) {
1425 switch (rec
->type
) {
1426 case WREPL_TYPE_UNIQUE
:
1427 action
= replace_unique_owned_vs_X_replica(rec
, replica
);
1429 case WREPL_TYPE_GROUP
:
1430 action
= replace_group_owned_vs_X_replica(rec
, replica
);
1432 case WREPL_TYPE_SGROUP
:
1433 action
= replace_sgroup_owned_vs_X_replica(rec
, replica
);
1435 case WREPL_TYPE_MHOMED
:
1436 action
= replace_mhomed_owned_vs_X_replica(rec
, replica
);
1441 DEBUG(4,("apply record %s: %s\n",
1442 nbt_name_string(mem_ctx
, &replica
->name
), _R_ACTION_enum_string(action
)));
1445 case R_INVALID
: break;
1447 return r_do_replace(partner
, mem_ctx
, rec
, owner
, replica
);
1449 return r_not_replace(partner
, mem_ctx
, rec
, owner
, replica
);
1450 case R_DO_PROPAGATE
:
1451 return r_do_propagate(partner
, mem_ctx
, rec
, owner
, replica
);
1452 case R_DO_CHALLENGE
:
1453 return r_do_challenge(partner
, mem_ctx
, rec
, owner
, replica
);
1454 case R_DO_RELEASE_DEMAND
:
1455 return r_do_release_demand(partner
, mem_ctx
, rec
, owner
, replica
);
1456 case R_DO_SGROUP_MERGE
:
1457 return r_do_sgroup_merge(partner
, mem_ctx
, rec
, owner
, replica
);
1460 return NT_STATUS_INTERNAL_ERROR
;
1463 NTSTATUS
wreplsrv_apply_records(struct wreplsrv_partner
*partner
,
1464 struct wrepl_wins_owner
*owner
,
1465 uint32_t num_names
, struct wrepl_name
*names
)
1470 DEBUG(4,("apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
1471 num_names
, owner
->address
,
1472 (long long)owner
->min_version
,
1473 (long long)owner
->max_version
,
1476 for (i
=0; i
< num_names
; i
++) {
1477 TALLOC_CTX
*tmp_mem
= talloc_new(partner
);
1478 NT_STATUS_HAVE_NO_MEMORY(tmp_mem
);
1480 status
= wreplsrv_apply_one_record(partner
, tmp_mem
,
1482 talloc_free(tmp_mem
);
1483 NT_STATUS_NOT_OK_RETURN(status
);
1486 status
= wreplsrv_add_table(partner
->service
,
1488 &partner
->service
->table
,
1490 owner
->max_version
);
1491 NT_STATUS_NOT_OK_RETURN(status
);
1493 return NT_STATUS_OK
;