Improve the Gemand pam_winbind translation.
[Samba/bb.git] / source4 / wrepl_server / wrepl_apply_records.c
blob380b77517fc557cac8c058c195b9edd91a77ca2f
1 /*
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/>.
22 #include "includes.h"
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"
33 enum _R_ACTION {
34 R_INVALID,
35 R_DO_REPLACE,
36 R_NOT_REPLACE,
37 R_DO_PROPAGATE,
38 R_DO_CHALLENGE,
39 R_DO_RELEASE_DEMAND,
40 R_DO_SGROUP_MERGE
43 static const char *_R_ACTION_enum_string(enum _R_ACTION action)
45 switch (action) {
46 case R_INVALID: return "INVALID";
47 case R_DO_REPLACE: return "REPLACE";
48 case R_NOT_REPLACE: return "NOT_REPLACE";
49 case R_DO_PROPAGATE: return "PROPAGATE";
50 case R_DO_CHALLENGE: return "CHALLEGNE";
51 case R_DO_RELEASE_DEMAND: return "RELEASE_DEMAND";
52 case R_DO_SGROUP_MERGE: return "SGROUP_MERGE";
55 return "enum _R_ACTION unknown";
58 #define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
59 #if 0 /* unused */
60 #define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
61 #endif
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)
67 #if 0 /* unused */
68 #define R_IS_MHOMED(r) ((r)->type == WREPL_TYPE_MHOMED)
69 #endif
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)
74 /* REPLACE */
75 return R_DO_REPLACE;
78 static bool r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
80 uint32_t i,j;
81 size_t len = winsdb_addr_list_length(r1->addresses);
83 for (i=0; i < len; i++) {
84 bool found = false;
85 for (j=0; j < r2->num_addresses; j++) {
86 if (strcmp(r1->addresses[i]->address, r2->addresses[j].address) != 0) {
87 continue;
90 if (check_owners && strcmp(r1->addresses[i]->wins_owner, r2->addresses[j].owner) != 0) {
91 return false;
93 found = true;
94 break;
96 if (!found) return false;
99 return true;
102 static bool r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
104 uint32_t i,j;
105 size_t len = winsdb_addr_list_length(r1->addresses);
107 for (i=0; i < r2->num_addresses; i++) {
108 bool found = false;
109 for (j=0; j < len; j++) {
110 if (strcmp(r2->addresses[i].address, r1->addresses[j]->address) != 0) {
111 continue;
114 if (check_owners && strcmp(r2->addresses[i].owner, r1->addresses[j]->wins_owner) != 0) {
115 return false;
117 found = true;
118 break;
120 if (!found) return false;
123 return true;
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) {
131 return false;
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)
139 uint32_t i;
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) {
144 return true;
148 return false;
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)) {
180 /* REPLACE */
181 return R_DO_REPLACE;
184 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
185 /* REPLACE */
186 return R_DO_REPLACE;
189 /* NOT REPLACE */
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)) {
222 /* REPLACE */
223 return R_DO_REPLACE;
226 if (R_IS_TOMBSTONE(r1) && !R_IS_UNIQUE(r2)) {
227 /* REPLACE */
228 return R_DO_REPLACE;
231 /* NOT REPLACE */
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)) {
284 /* REPLACE */
285 return R_DO_REPLACE;
288 if (!R_IS_SGROUP(r2)) {
289 /* NOT REPLACE */
290 return R_NOT_REPLACE;
294 * this is strange, but correct
295 * the incoming tombstone replace the current active
296 * record
298 if (!R_IS_ACTIVE(r2)) {
299 /* REPLACE */
300 return R_DO_REPLACE;
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;
309 /* NOT REPLACE */
310 return R_NOT_REPLACE;
313 if (r_1_is_superset_of_2_address_list(r1, r2, true)) {
314 /* NOT REPLACE */
315 return R_NOT_REPLACE;
318 if (r_1_is_same_as_2_address_list(r1, r2, false)) {
319 /* REPLACE */
320 return R_DO_REPLACE;
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)) {
356 /* REPLACE */
357 return R_DO_REPLACE;
360 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
361 /* REPLACE */
362 return R_DO_REPLACE;
365 /* NOT REPLACE */
366 return R_NOT_REPLACE;
370 active:
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
396 released:
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)) {
417 /* REPLACE */
418 return R_DO_REPLACE;
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
439 * <=>
440 * if r2 has a superset(or same) of the addresses of r1
442 * then replace the record
444 return R_DO_REPLACE;
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;
456 active:
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
474 released:
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)) {
496 /* REPLACE */
497 return R_DO_REPLACE;
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!
532 released:
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)) {
553 /* REPLACE */
554 return R_DO_REPLACE;
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;
575 active:
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
608 released:
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)) {
629 /* REPLACE */
630 return R_DO_REPLACE;
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
651 * <=>
652 * if r2 has a superset(or same) of the addresses of r1
654 * then replace the record
656 return R_DO_REPLACE;
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,
668 TALLOC_CTX *mem_ctx,
669 struct wrepl_wins_owner *owner,
670 struct wrepl_name *replica)
672 struct winsdb_record *rec;
673 uint32_t i;
674 uint8_t ret;
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,
694 rec, rec->addresses,
695 replica->addresses[i].address,
696 replica->addresses[i].owner,
697 rec->expire_time,
698 false);
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)));
712 return NT_STATUS_OK;
715 static NTSTATUS r_do_replace(struct wreplsrv_partner *partner,
716 TALLOC_CTX *mem_ctx,
717 struct winsdb_record *rec,
718 struct wrepl_wins_owner *owner,
719 struct wrepl_name *replica)
721 uint32_t i;
722 uint8_t ret;
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,
739 rec, rec->addresses,
740 replica->addresses[i].address,
741 replica->addresses[i].owner,
742 rec->expire_time,
743 false);
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)));
757 return NT_STATUS_OK;
760 static NTSTATUS r_not_replace(struct wreplsrv_partner *partner,
761 TALLOC_CTX *mem_ctx,
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)));
768 return NT_STATUS_OK;
771 static NTSTATUS r_do_propagate(struct wreplsrv_partner *partner,
772 TALLOC_CTX *mem_ctx,
773 struct winsdb_record *rec,
774 struct wrepl_wins_owner *owner,
775 struct wrepl_name *replica)
777 uint8_t ret;
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)));
795 return NT_STATUS_OK;
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,
814 TALLOC_CTX *mem_ctx,
815 struct winsdb_record *rec,
816 struct wrepl_wins_owner *owner,
817 struct wrepl_name *replica)
819 struct winsdb_record *merge;
820 uint32_t i,j;
821 uint8_t ret;
822 size_t len;
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,
844 merge->expire_time,
845 false);
846 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
849 len = winsdb_addr_list_length(rec->addresses);
851 for (i=0; i < len; i++) {
852 bool found = false;
853 for (j=0; j < replica->num_addresses; j++) {
854 if (strcmp(replica->addresses[j].address, rec->addresses[i]->address) == 0) {
855 found = true;
856 break;
859 if (found) continue;
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,
866 false);
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)));
880 return NT_STATUS_OK;
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)
894 NTSTATUS status;
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 */
900 talloc_free(state);
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;
908 uint32_t i;
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,
929 &r, state);
930 NT_STATUS_HAVE_NO_MEMORY(ireq);
932 ireq->async.fn = r_do_late_release_demand_handler;
933 ireq->async.private = state;
935 return NT_STATUS_OK;
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)
955 NTSTATUS status;
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;
960 bool found = false;
961 uint32_t i,j;
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);
972 talloc_free(state);
973 return;
976 for (i=0; i < state->replica.num_addresses; i++) {
977 found = false;
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) {
981 found = true;
982 break;
985 if (found) continue;
987 new_is_subset = false;
988 break;
991 if (!new_is_subset) {
992 r_not_replace(state->partner, state, state->rec, &state->owner, &state->replica);
993 talloc_free(state);
994 return;
997 num_rec_addrs = winsdb_addr_list_length(state->rec->addresses);
998 for (i=0; i < num_rec_addrs; i++) {
999 found = false;
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) {
1003 found = true;
1004 break;
1007 if (found) continue;
1009 old_is_subset = false;
1010 break;
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)) {
1020 talloc_free(state);
1022 return;
1025 r_do_mhomed_merge(state->partner, state, state->rec, &state->owner, &state->replica);
1026 talloc_free(state);
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;
1038 const char **addrs;
1039 uint32_t i;
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,
1074 &state->r, state);
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)
1091 NTSTATUS status;
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 */
1097 talloc_free(state);
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)
1106 NTSTATUS status;
1107 struct irpc_request *ireq;
1108 struct server_id *nbt_servers;
1109 const char **addrs;
1110 struct winsdb_addr **addresses;
1111 struct r_do_release_demand_state *state;
1112 uint32_t i;
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,
1150 &state->r, state);
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;
1189 uint32_t i,j;
1190 uint8_t ret;
1191 size_t len;
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++) {
1213 bool found = false;
1215 for (j=0; j < replica->num_addresses; j++) {
1216 if (strcmp(rec->addresses[i]->address, replica->addresses[j].address) != 0) {
1217 continue;
1220 found = true;
1222 if (strcmp(rec->addresses[i]->wins_owner, replica->addresses[j].owner) != 0) {
1223 changed_old_addrs = true;
1224 break;
1226 break;
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;
1235 continue;
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,
1248 false);
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,
1257 merge->expire_time,
1258 false);
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);
1276 if (len == 0) {
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
1284 if (become_owner) {
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)
1306 NTSTATUS status;
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) {
1323 same_owner = true;
1324 } else {
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);
1351 break;
1352 case WREPL_TYPE_GROUP:
1353 action = replace_group_replica_vs_X_replica(rec, replica);
1354 break;
1355 case WREPL_TYPE_SGROUP:
1356 action = replace_sgroup_replica_vs_X_replica(rec, replica);
1357 break;
1358 case WREPL_TYPE_MHOMED:
1359 action = replace_mhomed_replica_vs_X_replica(rec, replica);
1360 break;
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);
1366 break;
1367 case WREPL_TYPE_GROUP:
1368 action = replace_group_owned_vs_X_replica(rec, replica);
1369 break;
1370 case WREPL_TYPE_SGROUP:
1371 action = replace_sgroup_owned_vs_X_replica(rec, replica);
1372 break;
1373 case WREPL_TYPE_MHOMED:
1374 action = replace_mhomed_owned_vs_X_replica(rec, replica);
1375 break;
1379 DEBUG(4,("apply record %s: %s\n",
1380 nbt_name_string(mem_ctx, &replica->name), _R_ACTION_enum_string(action)));
1382 switch (action) {
1383 case R_INVALID: break;
1384 case R_DO_REPLACE:
1385 return r_do_replace(partner, mem_ctx, rec, owner, replica);
1386 case R_NOT_REPLACE:
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)
1405 NTSTATUS status;
1406 uint32_t i;
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,
1412 partner->address));
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,
1419 owner, &names[i]);
1420 talloc_free(tmp_mem);
1421 NT_STATUS_NOT_OK_RETURN(status);
1424 status = wreplsrv_add_table(partner->service,
1425 partner->service,
1426 &partner->service->table,
1427 owner->address,
1428 owner->max_version);
1429 NT_STATUS_NOT_OK_RETURN(status);
1431 return NT_STATUS_OK;