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"
43 static const char *_R_ACTION_enum_string(enum _R_ACTION action
)
46 case R_INVALID
: return "INVALID";
47 case R_DO_REPLACE
: return "REPLACE";
48 case R_NOT_REPLACE
: return "NOT_REPLACE";
49 case R_DO_PROPAGATE
: return "PROPAGATE";
50 case R_DO_CHALLENGE
: return "CHALLEGNE";
51 case R_DO_RELEASE_DEMAND
: return "RELEASE_DEMAND";
52 case R_DO_SGROUP_MERGE
: return "SGROUP_MERGE";
55 return "enum _R_ACTION unknown";
58 #define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
60 #define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
62 #define R_IS_TOMBSTONE(r) ((r)->state == WREPL_STATE_TOMBSTONE)
64 #define R_IS_UNIQUE(r) ((r)->type == WREPL_TYPE_UNIQUE)
65 #define R_IS_GROUP(r) ((r)->type == WREPL_TYPE_GROUP)
66 #define R_IS_SGROUP(r) ((r)->type == WREPL_TYPE_SGROUP)
68 #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
274 this is a bit strange, incoming tombstone replicas always replace old replicas:
276 SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:NULL => B:NULL => REPLACE
277 SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4 => REPLACE
278 SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:B_3_4 => B:B_3_4 => REPLACE
279 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
281 static enum _R_ACTION
replace_sgroup_replica_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
283 if (!R_IS_ACTIVE(r1
)) {
288 if (!R_IS_SGROUP(r2
)) {
290 return R_NOT_REPLACE
;
294 * this is strange, but correct
295 * the incoming tombstone replace the current active
298 if (!R_IS_ACTIVE(r2
)) {
303 if (r2
->num_addresses
== 0) {
304 if (r_contains_addrs_from_owner(r1
, r2
->owner
)) {
305 /* not handled here: MERGE */
306 return R_DO_SGROUP_MERGE
;
310 return R_NOT_REPLACE
;
313 if (r_1_is_superset_of_2_address_list(r1
, r2
, true)) {
315 return R_NOT_REPLACE
;
318 if (r_1_is_same_as_2_address_list(r1
, r2
, false)) {
323 /* not handled here: MERGE */
324 return R_DO_SGROUP_MERGE
;
328 MHOMED,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
329 MHOMED,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
330 MHOMED,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
331 MHOMED,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
332 MHOMED,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
333 MHOMED,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
334 MHOMED,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
335 MHOMED,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
336 MHOMED,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
337 MHOMED,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
338 MHOMED,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
339 MHOMED,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
340 MHOMED,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
341 MHOMED,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
342 MHOMED,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
343 MHOMED,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
344 MHOMED,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
345 MHOMED,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
346 MHOMED,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
347 MHOMED,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
348 MHOMED,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
349 MHOMED,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
350 MHOMED,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
351 MHOMED,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
353 static enum _R_ACTION
replace_mhomed_replica_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
355 if (!R_IS_ACTIVE(r1
)) {
360 if (!R_IS_SGROUP(r2
) && R_IS_ACTIVE(r2
)) {
366 return R_NOT_REPLACE
;
371 _UA_UA_SI_U<00> => REPLACE
372 _UA_UA_DI_P<00> => NOT REPLACE
373 _UA_UA_DI_O<00> => NOT REPLACE
374 _UA_UA_DI_N<00> => REPLACE
375 _UA_UT_SI_U<00> => NOT REPLACE
376 _UA_UT_DI_U<00> => NOT REPLACE
377 _UA_GA_SI_R<00> => REPLACE
378 _UA_GA_DI_R<00> => REPLACE
379 _UA_GT_SI_U<00> => NOT REPLACE
380 _UA_GT_DI_U<00> => NOT REPLACE
381 _UA_SA_SI_R<00> => REPLACE
382 _UA_SA_DI_R<00> => REPLACE
383 _UA_ST_SI_U<00> => NOT REPLACE
384 _UA_ST_DI_U<00> => NOT REPLACE
385 _UA_MA_SI_U<00> => REPLACE
386 _UA_MA_SP_U<00> => REPLACE
387 _UA_MA_DI_P<00> => NOT REPLACE
388 _UA_MA_DI_O<00> => NOT REPLACE
389 _UA_MA_DI_N<00> => REPLACE
390 _UA_MT_SI_U<00> => NOT REPLACE
391 _UA_MT_DI_U<00> => NOT REPLACE
392 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
393 _UA_UA_DI_A<00> => MHOMED_MERGE
394 _UA_MA_DI_A<00> => MHOMED_MERGE
397 _UR_UA_SI<00> => REPLACE
398 _UR_UA_DI<00> => REPLACE
399 _UR_UT_SI<00> => REPLACE
400 _UR_UT_DI<00> => REPLACE
401 _UR_GA_SI<00> => REPLACE
402 _UR_GA_DI<00> => REPLACE
403 _UR_GT_SI<00> => REPLACE
404 _UR_GT_DI<00> => REPLACE
405 _UR_SA_SI<00> => REPLACE
406 _UR_SA_DI<00> => REPLACE
407 _UR_ST_SI<00> => REPLACE
408 _UR_ST_DI<00> => REPLACE
409 _UR_MA_SI<00> => REPLACE
410 _UR_MA_DI<00> => REPLACE
411 _UR_MT_SI<00> => REPLACE
412 _UR_MT_DI<00> => REPLACE
414 static enum _R_ACTION
replace_unique_owned_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
416 if (!R_IS_ACTIVE(r1
)) {
421 if (!R_IS_ACTIVE(r2
)) {
422 /* NOT REPLACE, and PROPAGATE */
423 return R_DO_PROPAGATE
;
426 if (R_IS_GROUP(r2
) || R_IS_SGROUP(r2
)) {
427 /* REPLACE and send a release demand to the old name owner */
428 return R_DO_RELEASE_DEMAND
;
432 * here we only have unique,active,owned vs.
433 * is unique,active,replica or mhomed,active,replica
436 if (r_1_is_subset_of_2_address_list(r1
, r2
, false)) {
438 * if r1 has a subset(or same) of the addresses of r2
440 * if r2 has a superset(or same) of the addresses of r1
442 * then replace the record
448 * in any other case, we need to do
449 * a name request to the old name holder
450 * to see if it's still there...
452 return R_DO_CHALLENGE
;
457 _GA_UA_SI_U<00> => NOT REPLACE
458 _GA_UA_DI_U<00> => NOT REPLACE
459 _GA_UT_SI_U<00> => NOT REPLACE
460 _GA_UT_DI_U<00> => NOT REPLACE
461 _GA_GA_SI_U<00> => REPLACE
462 _GA_GA_DI_U<00> => REPLACE
463 _GA_GT_SI_U<00> => NOT REPLACE
464 _GA_GT_DI_U<00> => NOT REPLACE
465 _GA_SA_SI_U<00> => NOT REPLACE
466 _GA_SA_DI_U<00> => NOT REPLACE
467 _GA_ST_SI_U<00> => NOT REPLACE
468 _GA_ST_DI_U<00> => NOT REPLACE
469 _GA_MA_SI_U<00> => NOT REPLACE
470 _GA_MA_DI_U<00> => NOT REPLACE
471 _GA_MT_SI_U<00> => NOT REPLACE
472 _GA_MT_DI_U<00> => NOT REPLACE
475 _GR_UA_SI<00> => NOT REPLACE
476 _GR_UA_DI<00> => NOT REPLACE
477 _GR_UT_SI<00> => NOT REPLACE
478 _GR_UT_DI<00> => NOT REPLACE
479 _GR_GA_SI<00> => REPLACE
480 _GR_GA_DI<00> => REPLACE
481 _GR_GT_SI<00> => REPLACE
482 _GR_GT_DI<00> => REPLACE
483 _GR_SA_SI<00> => NOT REPLACE
484 _GR_SA_DI<00> => NOT REPLACE
485 _GR_ST_SI<00> => NOT REPLACE
486 _GR_ST_DI<00> => NOT REPLACE
487 _GR_MA_SI<00> => NOT REPLACE
488 _GR_MA_DI<00> => NOT REPLACE
489 _GR_MT_SI<00> => NOT REPLACE
490 _GR_MT_DI<00> => NOT REPLACE
492 static enum _R_ACTION
replace_group_owned_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
494 if (R_IS_GROUP(r1
) && R_IS_GROUP(r2
)) {
495 if (!R_IS_ACTIVE(r1
) || R_IS_ACTIVE(r2
)) {
501 /* NOT REPLACE, but PROPAGATE */
502 return R_DO_PROPAGATE
;
506 active (not sgroup vs. sgroup yet!):
507 _SA_UA_SI_U<1c> => NOT REPLACE
508 _SA_UA_DI_U<1c> => NOT REPLACE
509 _SA_UT_SI_U<1c> => NOT REPLACE
510 _SA_UT_DI_U<1c> => NOT REPLACE
511 _SA_GA_SI_U<1c> => NOT REPLACE
512 _SA_GA_DI_U<1c> => NOT REPLACE
513 _SA_GT_SI_U<1c> => NOT REPLACE
514 _SA_GT_DI_U<1c> => NOT REPLACE
515 _SA_MA_SI_U<1c> => NOT REPLACE
516 _SA_MA_DI_U<1c> => NOT REPLACE
517 _SA_MT_SI_U<1c> => NOT REPLACE
518 _SA_MT_DI_U<1c> => NOT REPLACE
520 Test Replica vs. owned active: SGROUP vs. SGROUP tests
521 _SA_SA_DI_U<1c> => SGROUP_MERGE
522 _SA_SA_SI_U<1c> => SGROUP_MERGE
523 _SA_SA_SP_U<1c> => SGROUP_MERGE
524 _SA_SA_SB_U<1c> => SGROUP_MERGE
525 _SA_ST_DI_U<1c> => NOT REPLACE
526 _SA_ST_SI_U<1c> => NOT REPLACE
527 _SA_ST_SP_U<1c> => NOT REPLACE
528 _SA_ST_SB_U<1c> => NOT REPLACE
530 SGROUP,ACTIVE vs. SGROUP,* is not handled here!
533 _SR_UA_SI<1c> => REPLACE
534 _SR_UA_DI<1c> => REPLACE
535 _SR_UT_SI<1c> => REPLACE
536 _SR_UT_DI<1c> => REPLACE
537 _SR_GA_SI<1c> => REPLACE
538 _SR_GA_DI<1c> => REPLACE
539 _SR_GT_SI<1c> => REPLACE
540 _SR_GT_DI<1c> => REPLACE
541 _SR_SA_SI<1c> => REPLACE
542 _SR_SA_DI<1c> => REPLACE
543 _SR_ST_SI<1c> => REPLACE
544 _SR_ST_DI<1c> => REPLACE
545 _SR_MA_SI<1c> => REPLACE
546 _SR_MA_DI<1c> => REPLACE
547 _SR_MT_SI<1c> => REPLACE
548 _SR_MT_DI<1c> => REPLACE
550 static enum _R_ACTION
replace_sgroup_owned_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
552 if (!R_IS_ACTIVE(r1
)) {
557 if (!R_IS_SGROUP(r2
) || !R_IS_ACTIVE(r2
)) {
558 /* NOT REPLACE, but PROPAGATE */
559 return R_DO_PROPAGATE
;
562 if (r_1_is_same_as_2_address_list(r1
, r2
, true)) {
564 * as we're the old owner and the addresses and their
565 * owners are identical
567 return R_NOT_REPLACE
;
570 /* not handled here: MERGE */
571 return R_DO_SGROUP_MERGE
;
576 _MA_UA_SI_U<00> => REPLACE
577 _MA_UA_DI_P<00> => NOT REPLACE
578 _MA_UA_DI_O<00> => NOT REPLACE
579 _MA_UA_DI_N<00> => REPLACE
580 _MA_UT_SI_U<00> => NOT REPLACE
581 _MA_UT_DI_U<00> => NOT REPLACE
582 _MA_GA_SI_R<00> => REPLACE
583 _MA_GA_DI_R<00> => REPLACE
584 _MA_GT_SI_U<00> => NOT REPLACE
585 _MA_GT_DI_U<00> => NOT REPLACE
586 _MA_SA_SI_R<00> => REPLACE
587 _MA_SA_DI_R<00> => REPLACE
588 _MA_ST_SI_U<00> => NOT REPLACE
589 _MA_ST_DI_U<00> => NOT REPLACE
590 _MA_MA_SI_U<00> => REPLACE
591 _MA_MA_SP_U<00> => REPLACE
592 _MA_MA_DI_P<00> => NOT REPLACE
593 _MA_MA_DI_O<00> => NOT REPLACE
594 _MA_MA_DI_N<00> => REPLACE
595 _MA_MT_SI_U<00> => NOT REPLACE
596 _MA_MT_DI_U<00> => NOT REPLACE
597 Test Replica vs. owned active: some more MHOMED combinations
598 _MA_MA_SP_U<00> => REPLACE
599 _MA_MA_SM_U<00> => REPLACE
600 _MA_MA_SB_P<00> => MHOMED_MERGE
601 _MA_MA_SB_A<00> => MHOMED_MERGE
602 _MA_MA_SB_PRA<00> => NOT REPLACE
603 _MA_MA_SB_O<00> => NOT REPLACE
604 _MA_MA_SB_N<00> => REPLACE
605 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
606 _MA_UA_SB_P<00> => MHOMED_MERGE
609 _MR_UA_SI<00> => REPLACE
610 _MR_UA_DI<00> => REPLACE
611 _MR_UT_SI<00> => REPLACE
612 _MR_UT_DI<00> => REPLACE
613 _MR_GA_SI<00> => REPLACE
614 _MR_GA_DI<00> => REPLACE
615 _MR_GT_SI<00> => REPLACE
616 _MR_GT_DI<00> => REPLACE
617 _MR_SA_SI<00> => REPLACE
618 _MR_SA_DI<00> => REPLACE
619 _MR_ST_SI<00> => REPLACE
620 _MR_ST_DI<00> => REPLACE
621 _MR_MA_SI<00> => REPLACE
622 _MR_MA_DI<00> => REPLACE
623 _MR_MT_SI<00> => REPLACE
624 _MR_MT_DI<00> => REPLACE
626 static enum _R_ACTION
replace_mhomed_owned_vs_X_replica(struct winsdb_record
*r1
, struct wrepl_name
*r2
)
628 if (!R_IS_ACTIVE(r1
)) {
633 if (!R_IS_ACTIVE(r2
)) {
634 /* NOT REPLACE, but PROPAGATE */
635 return R_DO_PROPAGATE
;
638 if (R_IS_GROUP(r2
) || R_IS_SGROUP(r2
)) {
639 /* REPLACE and send a release demand to the old name owner */
640 return R_DO_RELEASE_DEMAND
;
644 * here we only have mhomed,active,owned vs.
645 * is unique,active,replica or mhomed,active,replica
648 if (r_1_is_subset_of_2_address_list(r1
, r2
, false)) {
650 * if r1 has a subset(or same) of the addresses of r2
652 * if r2 has a superset(or same) of the addresses of r1
654 * then replace the record
660 * in any other case, we need to do
661 * a name request to the old name holder
662 * to see if it's still there...
664 return R_DO_CHALLENGE
;
667 static NTSTATUS
r_do_add(struct wreplsrv_partner
*partner
,
669 struct wrepl_wins_owner
*owner
,
670 struct wrepl_name
*replica
)
672 struct winsdb_record
*rec
;
676 rec
= talloc(mem_ctx
, struct winsdb_record
);
677 NT_STATUS_HAVE_NO_MEMORY(rec
);
679 rec
->name
= &replica
->name
;
680 rec
->type
= replica
->type
;
681 rec
->state
= replica
->state
;
682 rec
->node
= replica
->node
;
683 rec
->is_static
= replica
->is_static
;
684 rec
->expire_time
= time(NULL
) + partner
->service
->config
.verify_interval
;
685 rec
->version
= replica
->version_id
;
686 rec
->wins_owner
= replica
->owner
;
687 rec
->addresses
= winsdb_addr_list_make(rec
);
688 NT_STATUS_HAVE_NO_MEMORY(rec
->addresses
);
689 rec
->registered_by
= NULL
;
691 for (i
=0; i
< replica
->num_addresses
; i
++) {
692 /* TODO: find out if rec->expire_time is correct here */
693 rec
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
695 replica
->addresses
[i
].address
,
696 replica
->addresses
[i
].owner
,
699 NT_STATUS_HAVE_NO_MEMORY(rec
->addresses
);
702 ret
= winsdb_add(partner
->service
->wins_db
, rec
, 0);
703 if (ret
!= NBT_RCODE_OK
) {
704 DEBUG(0,("Failed to add record %s: %u\n",
705 nbt_name_string(mem_ctx
, &replica
->name
), ret
));
706 return NT_STATUS_FOOBAR
;
709 DEBUG(4,("added record %s\n",
710 nbt_name_string(mem_ctx
, &replica
->name
)));
715 static NTSTATUS
r_do_replace(struct wreplsrv_partner
*partner
,
717 struct winsdb_record
*rec
,
718 struct wrepl_wins_owner
*owner
,
719 struct wrepl_name
*replica
)
724 rec
->name
= &replica
->name
;
725 rec
->type
= replica
->type
;
726 rec
->state
= replica
->state
;
727 rec
->node
= replica
->node
;
728 rec
->is_static
= replica
->is_static
;
729 rec
->expire_time
= time(NULL
) + partner
->service
->config
.verify_interval
;
730 rec
->version
= replica
->version_id
;
731 rec
->wins_owner
= replica
->owner
;
732 rec
->addresses
= winsdb_addr_list_make(rec
);
733 NT_STATUS_HAVE_NO_MEMORY(rec
->addresses
);
734 rec
->registered_by
= NULL
;
736 for (i
=0; i
< replica
->num_addresses
; i
++) {
737 /* TODO: find out if rec->expire_time is correct here */
738 rec
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
740 replica
->addresses
[i
].address
,
741 replica
->addresses
[i
].owner
,
744 NT_STATUS_HAVE_NO_MEMORY(rec
->addresses
);
747 ret
= winsdb_modify(partner
->service
->wins_db
, rec
, 0);
748 if (ret
!= NBT_RCODE_OK
) {
749 DEBUG(0,("Failed to replace record %s: %u\n",
750 nbt_name_string(mem_ctx
, &replica
->name
), ret
));
751 return NT_STATUS_FOOBAR
;
754 DEBUG(4,("replaced record %s\n",
755 nbt_name_string(mem_ctx
, &replica
->name
)));
760 static NTSTATUS
r_not_replace(struct wreplsrv_partner
*partner
,
762 struct winsdb_record
*rec
,
763 struct wrepl_wins_owner
*owner
,
764 struct wrepl_name
*replica
)
766 DEBUG(4,("not replace record %s\n",
767 nbt_name_string(mem_ctx
, &replica
->name
)));
771 static NTSTATUS
r_do_propagate(struct wreplsrv_partner
*partner
,
773 struct winsdb_record
*rec
,
774 struct wrepl_wins_owner
*owner
,
775 struct wrepl_name
*replica
)
778 uint32_t modify_flags
;
781 * allocate a new version id for the record to that it'll be replicated
783 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
785 ret
= winsdb_modify(partner
->service
->wins_db
, rec
, modify_flags
);
786 if (ret
!= NBT_RCODE_OK
) {
787 DEBUG(0,("Failed to replace record %s: %u\n",
788 nbt_name_string(mem_ctx
, &replica
->name
), ret
));
789 return NT_STATUS_FOOBAR
;
792 DEBUG(4,("propagated record %s\n",
793 nbt_name_string(mem_ctx
, &replica
->name
)));
799 Test Replica vs. owned active: some more MHOMED combinations
800 _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
801 _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
802 _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
803 _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
804 _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
805 _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
806 _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
807 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
808 _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
809 _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
810 _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
811 _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
813 static NTSTATUS
r_do_mhomed_merge(struct wreplsrv_partner
*partner
,
815 struct winsdb_record
*rec
,
816 struct wrepl_wins_owner
*owner
,
817 struct wrepl_name
*replica
)
819 struct winsdb_record
*merge
;
824 merge
= talloc(mem_ctx
, struct winsdb_record
);
825 NT_STATUS_HAVE_NO_MEMORY(merge
);
827 merge
->name
= &replica
->name
;
828 merge
->type
= WREPL_TYPE_MHOMED
;
829 merge
->state
= replica
->state
;
830 merge
->node
= replica
->node
;
831 merge
->is_static
= replica
->is_static
;
832 merge
->expire_time
= time(NULL
) + partner
->service
->config
.verify_interval
;
833 merge
->version
= replica
->version_id
;
834 merge
->wins_owner
= replica
->owner
;
835 merge
->addresses
= winsdb_addr_list_make(merge
);
836 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
837 merge
->registered_by
= NULL
;
839 for (i
=0; i
< replica
->num_addresses
; i
++) {
840 merge
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
841 merge
, merge
->addresses
,
842 replica
->addresses
[i
].address
,
843 replica
->addresses
[i
].owner
,
846 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
849 len
= winsdb_addr_list_length(rec
->addresses
);
851 for (i
=0; i
< len
; i
++) {
853 for (j
=0; j
< replica
->num_addresses
; j
++) {
854 if (strcmp(replica
->addresses
[j
].address
, rec
->addresses
[i
]->address
) == 0) {
861 merge
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
862 merge
, merge
->addresses
,
863 rec
->addresses
[i
]->address
,
864 rec
->addresses
[i
]->wins_owner
,
865 rec
->addresses
[i
]->expire_time
,
867 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
870 ret
= winsdb_modify(partner
->service
->wins_db
, merge
, 0);
871 if (ret
!= NBT_RCODE_OK
) {
872 DEBUG(0,("Failed to modify mhomed merge record %s: %u\n",
873 nbt_name_string(mem_ctx
, &replica
->name
), ret
));
874 return NT_STATUS_FOOBAR
;
877 DEBUG(4,("mhomed merge record %s\n",
878 nbt_name_string(mem_ctx
, &replica
->name
)));
883 struct r_do_challenge_state
{
884 struct messaging_context
*msg_ctx
;
885 struct wreplsrv_partner
*partner
;
886 struct winsdb_record
*rec
;
887 struct wrepl_wins_owner owner
;
888 struct wrepl_name replica
;
889 struct nbtd_proxy_wins_challenge r
;
892 static void r_do_late_release_demand_handler(struct irpc_request
*ireq
)
895 struct r_do_challenge_state
*state
= talloc_get_type(ireq
->async
.private,
896 struct r_do_challenge_state
);
898 status
= irpc_call_recv(ireq
);
899 /* don't care about the result */
903 static NTSTATUS
r_do_late_release_demand(struct r_do_challenge_state
*state
)
905 struct irpc_request
*ireq
;
906 struct server_id
*nbt_servers
;
907 struct nbtd_proxy_wins_release_demand r
;
910 DEBUG(4,("late release demand record %s\n",
911 nbt_name_string(state
, &state
->replica
.name
)));
913 nbt_servers
= irpc_servers_byname(state
->msg_ctx
, state
, "nbt_server");
914 if ((nbt_servers
== NULL
) || (nbt_servers
[0].id
== 0)) {
915 return NT_STATUS_INTERNAL_ERROR
;
918 r
.in
.name
= state
->replica
.name
;
919 r
.in
.num_addrs
= state
->r
.out
.num_addrs
;
920 r
.in
.addrs
= talloc_array(state
, struct nbtd_proxy_wins_addr
, r
.in
.num_addrs
);
921 NT_STATUS_HAVE_NO_MEMORY(r
.in
.addrs
);
922 /* TODO: fix pidl to handle inline ipv4address arrays */
923 for (i
=0; i
< r
.in
.num_addrs
; i
++) {
924 r
.in
.addrs
[i
].addr
= state
->r
.out
.addrs
[i
].addr
;
927 ireq
= IRPC_CALL_SEND(state
->msg_ctx
, nbt_servers
[0],
928 irpc
, NBTD_PROXY_WINS_RELEASE_DEMAND
,
930 NT_STATUS_HAVE_NO_MEMORY(ireq
);
932 ireq
->async
.fn
= r_do_late_release_demand_handler
;
933 ireq
->async
.private = state
;
939 Test Replica vs. owned active: some more MHOMED combinations
940 _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
941 _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
942 _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
943 _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
944 _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
945 _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
946 _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
947 Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
948 _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
949 _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
950 _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
951 _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
953 static void r_do_challenge_handler(struct irpc_request
*ireq
)
956 struct r_do_challenge_state
*state
= talloc_get_type(ireq
->async
.private,
957 struct r_do_challenge_state
);
958 bool old_is_subset
= false;
959 bool new_is_subset
= false;
962 uint32_t num_rec_addrs
;
964 status
= irpc_call_recv(ireq
);
966 DEBUG(4,("r_do_challenge_handler: %s: %s\n",
967 nbt_name_string(state
, &state
->replica
.name
), nt_errstr(status
)));
969 if (NT_STATUS_EQUAL(NT_STATUS_IO_TIMEOUT
, status
) ||
970 NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND
, status
)) {
971 r_do_replace(state
->partner
, state
, state
->rec
, &state
->owner
, &state
->replica
);
976 for (i
=0; i
< state
->replica
.num_addresses
; i
++) {
978 new_is_subset
= true;
979 for (j
=0; j
< state
->r
.out
.num_addrs
; j
++) {
980 if (strcmp(state
->replica
.addresses
[i
].address
, state
->r
.out
.addrs
[j
].addr
) == 0) {
987 new_is_subset
= false;
991 if (!new_is_subset
) {
992 r_not_replace(state
->partner
, state
, state
->rec
, &state
->owner
, &state
->replica
);
997 num_rec_addrs
= winsdb_addr_list_length(state
->rec
->addresses
);
998 for (i
=0; i
< num_rec_addrs
; i
++) {
1000 old_is_subset
= true;
1001 for (j
=0; j
< state
->r
.out
.num_addrs
; j
++) {
1002 if (strcmp(state
->rec
->addresses
[i
]->address
, state
->r
.out
.addrs
[j
].addr
) == 0) {
1007 if (found
) continue;
1009 old_is_subset
= false;
1013 if (!old_is_subset
) {
1014 status
= r_do_late_release_demand(state
);
1016 * only free state on error, because we pass it down,
1017 * and r_do_late_release_demand() will free it
1019 if (!NT_STATUS_IS_OK(status
)) {
1025 r_do_mhomed_merge(state
->partner
, state
, state
->rec
, &state
->owner
, &state
->replica
);
1029 static NTSTATUS
r_do_challenge(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
)
1035 struct irpc_request
*ireq
;
1036 struct r_do_challenge_state
*state
;
1037 struct server_id
*nbt_servers
;
1041 DEBUG(4,("challenge record %s\n",
1042 nbt_name_string(mem_ctx
, &replica
->name
)));
1044 state
= talloc_zero(mem_ctx
, struct r_do_challenge_state
);
1045 NT_STATUS_HAVE_NO_MEMORY(state
);
1046 state
->msg_ctx
= partner
->service
->task
->msg_ctx
;
1047 state
->partner
= partner
;
1048 state
->rec
= talloc_steal(state
, rec
);
1049 state
->owner
= *owner
;
1050 state
->replica
= *replica
;
1051 /* some stuff to have valid memory pointers in the async complete function */
1052 state
->replica
.name
= *state
->rec
->name
;
1053 talloc_steal(state
, replica
->owner
);
1054 talloc_steal(state
, replica
->addresses
);
1056 nbt_servers
= irpc_servers_byname(state
->msg_ctx
, state
, "nbt_server");
1057 if ((nbt_servers
== NULL
) || (nbt_servers
[0].id
== 0)) {
1058 return NT_STATUS_INTERNAL_ERROR
;
1061 state
->r
.in
.name
= *rec
->name
;
1062 state
->r
.in
.num_addrs
= winsdb_addr_list_length(rec
->addresses
);
1063 state
->r
.in
.addrs
= talloc_array(state
, struct nbtd_proxy_wins_addr
, state
->r
.in
.num_addrs
);
1064 NT_STATUS_HAVE_NO_MEMORY(state
->r
.in
.addrs
);
1065 /* TODO: fix pidl to handle inline ipv4address arrays */
1066 addrs
= winsdb_addr_string_list(state
->r
.in
.addrs
, rec
->addresses
);
1067 NT_STATUS_HAVE_NO_MEMORY(addrs
);
1068 for (i
=0; i
< state
->r
.in
.num_addrs
; i
++) {
1069 state
->r
.in
.addrs
[i
].addr
= addrs
[i
];
1072 ireq
= IRPC_CALL_SEND(state
->msg_ctx
, nbt_servers
[0],
1073 irpc
, NBTD_PROXY_WINS_CHALLENGE
,
1075 NT_STATUS_HAVE_NO_MEMORY(ireq
);
1077 ireq
->async
.fn
= r_do_challenge_handler
;
1078 ireq
->async
.private = state
;
1080 talloc_steal(partner
, state
);
1081 return NT_STATUS_OK
;
1084 struct r_do_release_demand_state
{
1085 struct messaging_context
*msg_ctx
;
1086 struct nbtd_proxy_wins_release_demand r
;
1089 static void r_do_release_demand_handler(struct irpc_request
*ireq
)
1092 struct r_do_release_demand_state
*state
= talloc_get_type(ireq
->async
.private,
1093 struct r_do_release_demand_state
);
1095 status
= irpc_call_recv(ireq
);
1096 /* don't care about the result */
1100 static NTSTATUS
r_do_release_demand(struct wreplsrv_partner
*partner
,
1101 TALLOC_CTX
*mem_ctx
,
1102 struct winsdb_record
*rec
,
1103 struct wrepl_wins_owner
*owner
,
1104 struct wrepl_name
*replica
)
1107 struct irpc_request
*ireq
;
1108 struct server_id
*nbt_servers
;
1110 struct winsdb_addr
**addresses
;
1111 struct r_do_release_demand_state
*state
;
1115 * we need to get a reference to the old addresses,
1116 * as we need to send a release demand to them after replacing the record
1117 * and r_do_replace() will modify rec->addresses
1119 addresses
= rec
->addresses
;
1121 status
= r_do_replace(partner
, mem_ctx
, rec
, owner
, replica
);
1122 NT_STATUS_NOT_OK_RETURN(status
);
1124 DEBUG(4,("release demand record %s\n",
1125 nbt_name_string(mem_ctx
, &replica
->name
)));
1127 state
= talloc_zero(mem_ctx
, struct r_do_release_demand_state
);
1128 NT_STATUS_HAVE_NO_MEMORY(state
);
1129 state
->msg_ctx
= partner
->service
->task
->msg_ctx
;
1131 nbt_servers
= irpc_servers_byname(state
->msg_ctx
, state
, "nbt_server");
1132 if ((nbt_servers
== NULL
) || (nbt_servers
[0].id
== 0)) {
1133 return NT_STATUS_INTERNAL_ERROR
;
1136 state
->r
.in
.name
= *rec
->name
;
1137 state
->r
.in
.num_addrs
= winsdb_addr_list_length(addresses
);
1138 state
->r
.in
.addrs
= talloc_array(state
, struct nbtd_proxy_wins_addr
,
1139 state
->r
.in
.num_addrs
);
1140 NT_STATUS_HAVE_NO_MEMORY(state
->r
.in
.addrs
);
1141 /* TODO: fix pidl to handle inline ipv4address arrays */
1142 addrs
= winsdb_addr_string_list(state
->r
.in
.addrs
, addresses
);
1143 NT_STATUS_HAVE_NO_MEMORY(addrs
);
1144 for (i
=0; i
< state
->r
.in
.num_addrs
; i
++) {
1145 state
->r
.in
.addrs
[i
].addr
= addrs
[i
];
1148 ireq
= IRPC_CALL_SEND(state
->msg_ctx
, nbt_servers
[0],
1149 irpc
, NBTD_PROXY_WINS_RELEASE_DEMAND
,
1151 NT_STATUS_HAVE_NO_MEMORY(ireq
);
1153 ireq
->async
.fn
= r_do_release_demand_handler
;
1154 ireq
->async
.private = state
;
1156 talloc_steal(partner
, state
);
1157 return NT_STATUS_OK
;
1161 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
1162 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
1163 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
1164 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
1165 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
1166 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
1168 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
1169 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
1170 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
1171 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
1172 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
1173 SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
1175 Test Replica vs. owned active: SGROUP vs. SGROUP tests
1176 _SA_SA_DI_U<1c> => SGROUP_MERGE
1177 _SA_SA_SI_U<1c> => SGROUP_MERGE
1178 _SA_SA_SP_U<1c> => SGROUP_MERGE
1179 _SA_SA_SB_U<1c> => SGROUP_MERGE
1181 static NTSTATUS
r_do_sgroup_merge(struct wreplsrv_partner
*partner
,
1182 TALLOC_CTX
*mem_ctx
,
1183 struct winsdb_record
*rec
,
1184 struct wrepl_wins_owner
*owner
,
1185 struct wrepl_name
*replica
)
1187 struct winsdb_record
*merge
;
1188 uint32_t modify_flags
= 0;
1192 bool changed_old_addrs
= false;
1193 bool become_owner
= true;
1195 merge
= talloc(mem_ctx
, struct winsdb_record
);
1196 NT_STATUS_HAVE_NO_MEMORY(merge
);
1198 merge
->name
= &replica
->name
;
1199 merge
->type
= replica
->type
;
1200 merge
->state
= replica
->state
;
1201 merge
->node
= replica
->node
;
1202 merge
->is_static
= replica
->is_static
;
1203 merge
->expire_time
= time(NULL
) + partner
->service
->config
.verify_interval
;
1204 merge
->version
= replica
->version_id
;
1205 merge
->wins_owner
= replica
->owner
;
1206 merge
->addresses
= winsdb_addr_list_make(merge
);
1207 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
1208 merge
->registered_by
= NULL
;
1210 len
= winsdb_addr_list_length(rec
->addresses
);
1212 for (i
=0; i
< len
; i
++) {
1215 for (j
=0; j
< replica
->num_addresses
; j
++) {
1216 if (strcmp(rec
->addresses
[i
]->address
, replica
->addresses
[j
].address
) != 0) {
1222 if (strcmp(rec
->addresses
[i
]->wins_owner
, replica
->addresses
[j
].owner
) != 0) {
1223 changed_old_addrs
= true;
1230 * if the address isn't in the replica and is owned by replicas owner,
1231 * it won't be added to the merged record
1233 if (!found
&& strcmp(rec
->addresses
[i
]->wins_owner
, owner
->address
) == 0) {
1234 changed_old_addrs
= true;
1239 * add the address to the merge result, with the old owner and expire_time,
1240 * the owner and expire_time will be overwritten later if the address is
1241 * in the replica too
1243 merge
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
1244 merge
, merge
->addresses
,
1245 rec
->addresses
[i
]->address
,
1246 rec
->addresses
[i
]->wins_owner
,
1247 rec
->addresses
[i
]->expire_time
,
1249 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
1252 for (i
=0; i
< replica
->num_addresses
; i
++) {
1253 merge
->addresses
= winsdb_addr_list_add(partner
->service
->wins_db
,
1254 merge
, merge
->addresses
,
1255 replica
->addresses
[i
].address
,
1256 replica
->addresses
[i
].owner
,
1259 NT_STATUS_HAVE_NO_MEMORY(merge
->addresses
);
1262 /* we the old addresses change changed we don't become the owner */
1263 if (changed_old_addrs
) {
1264 become_owner
= false;
1267 /* if we're the owner of the old record, we'll be the owner of the new one too */
1268 if (strcmp(rec
->wins_owner
, partner
->service
->wins_db
->local_owner
)==0) {
1269 become_owner
= true;
1273 * if the result has no addresses we take the ownership
1275 len
= winsdb_addr_list_length(merge
->addresses
);
1277 become_owner
= true;
1281 * if addresses of the old record will be changed the replica owner
1282 * will be owner of the merge result, otherwise we take the ownership
1285 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
1288 ret
= winsdb_modify(partner
->service
->wins_db
, merge
, modify_flags
);
1289 if (ret
!= NBT_RCODE_OK
) {
1290 DEBUG(0,("Failed to modify sgroup merge record %s: %u\n",
1291 nbt_name_string(mem_ctx
, &replica
->name
), ret
));
1292 return NT_STATUS_FOOBAR
;
1295 DEBUG(4,("sgroup merge record %s\n",
1296 nbt_name_string(mem_ctx
, &replica
->name
)));
1298 return NT_STATUS_OK
;
1301 static NTSTATUS
wreplsrv_apply_one_record(struct wreplsrv_partner
*partner
,
1302 TALLOC_CTX
*mem_ctx
,
1303 struct wrepl_wins_owner
*owner
,
1304 struct wrepl_name
*replica
)
1307 struct winsdb_record
*rec
= NULL
;
1308 enum _R_ACTION action
= R_INVALID
;
1309 bool same_owner
= false;
1310 bool replica_vs_replica
= false;
1311 bool local_vs_replica
= false;
1313 status
= winsdb_lookup(partner
->service
->wins_db
,
1314 &replica
->name
, mem_ctx
, &rec
);
1315 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND
, status
)) {
1316 return r_do_add(partner
, mem_ctx
, owner
, replica
);
1318 NT_STATUS_NOT_OK_RETURN(status
);
1320 if (strcmp(rec
->wins_owner
, partner
->service
->wins_db
->local_owner
)==0) {
1321 local_vs_replica
= true;
1322 } else if (strcmp(rec
->wins_owner
, owner
->address
)==0) {
1325 replica_vs_replica
= true;
1328 if (rec
->is_static
&& !same_owner
) {
1329 action
= R_NOT_REPLACE
;
1332 * if we own the local record, then propagate it back to
1333 * the other wins servers.
1334 * to prevent ping-pong with other servers, we don't do this
1335 * if the replica is static too.
1337 * It seems that w2k3 doesn't do this, but I thing that's a bug
1338 * and doing propagation helps to have consistent data on all servers
1340 if (local_vs_replica
&& !replica
->is_static
) {
1341 action
= R_DO_PROPAGATE
;
1343 } else if (replica
->is_static
&& !rec
->is_static
&& !same_owner
) {
1344 action
= R_DO_REPLACE
;
1345 } else if (same_owner
) {
1346 action
= replace_same_owner(rec
, replica
);
1347 } else if (replica_vs_replica
) {
1348 switch (rec
->type
) {
1349 case WREPL_TYPE_UNIQUE
:
1350 action
= replace_unique_replica_vs_X_replica(rec
, replica
);
1352 case WREPL_TYPE_GROUP
:
1353 action
= replace_group_replica_vs_X_replica(rec
, replica
);
1355 case WREPL_TYPE_SGROUP
:
1356 action
= replace_sgroup_replica_vs_X_replica(rec
, replica
);
1358 case WREPL_TYPE_MHOMED
:
1359 action
= replace_mhomed_replica_vs_X_replica(rec
, replica
);
1362 } else if (local_vs_replica
) {
1363 switch (rec
->type
) {
1364 case WREPL_TYPE_UNIQUE
:
1365 action
= replace_unique_owned_vs_X_replica(rec
, replica
);
1367 case WREPL_TYPE_GROUP
:
1368 action
= replace_group_owned_vs_X_replica(rec
, replica
);
1370 case WREPL_TYPE_SGROUP
:
1371 action
= replace_sgroup_owned_vs_X_replica(rec
, replica
);
1373 case WREPL_TYPE_MHOMED
:
1374 action
= replace_mhomed_owned_vs_X_replica(rec
, replica
);
1379 DEBUG(4,("apply record %s: %s\n",
1380 nbt_name_string(mem_ctx
, &replica
->name
), _R_ACTION_enum_string(action
)));
1383 case R_INVALID
: break;
1385 return r_do_replace(partner
, mem_ctx
, rec
, owner
, replica
);
1387 return r_not_replace(partner
, mem_ctx
, rec
, owner
, replica
);
1388 case R_DO_PROPAGATE
:
1389 return r_do_propagate(partner
, mem_ctx
, rec
, owner
, replica
);
1390 case R_DO_CHALLENGE
:
1391 return r_do_challenge(partner
, mem_ctx
, rec
, owner
, replica
);
1392 case R_DO_RELEASE_DEMAND
:
1393 return r_do_release_demand(partner
, mem_ctx
, rec
, owner
, replica
);
1394 case R_DO_SGROUP_MERGE
:
1395 return r_do_sgroup_merge(partner
, mem_ctx
, rec
, owner
, replica
);
1398 return NT_STATUS_INTERNAL_ERROR
;
1401 NTSTATUS
wreplsrv_apply_records(struct wreplsrv_partner
*partner
,
1402 struct wrepl_wins_owner
*owner
,
1403 uint32_t num_names
, struct wrepl_name
*names
)
1408 DEBUG(4,("apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
1409 num_names
, owner
->address
,
1410 (long long)owner
->min_version
,
1411 (long long)owner
->max_version
,
1414 for (i
=0; i
< num_names
; i
++) {
1415 TALLOC_CTX
*tmp_mem
= talloc_new(partner
);
1416 NT_STATUS_HAVE_NO_MEMORY(tmp_mem
);
1418 status
= wreplsrv_apply_one_record(partner
, tmp_mem
,
1420 talloc_free(tmp_mem
);
1421 NT_STATUS_NOT_OK_RETURN(status
);
1424 status
= wreplsrv_add_table(partner
->service
,
1426 &partner
->service
->table
,
1428 owner
->max_version
);
1429 NT_STATUS_NOT_OK_RETURN(status
);
1431 return NT_STATUS_OK
;