/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- _R_ACTION_enum_string
- replace_same_owner
- r_1_is_subset_of_2_address_list
- r_1_is_superset_of_2_address_list
- r_1_is_same_as_2_address_list
- r_contains_addrs_from_owner
- replace_unique_replica_vs_X_replica
- replace_group_replica_vs_X_replica
- replace_sgroup_replica_vs_X_replica
- replace_mhomed_replica_vs_X_replica
- replace_unique_owned_vs_X_replica
- replace_group_owned_vs_X_replica
- replace_sgroup_owned_vs_X_replica
- replace_mhomed_owned_vs_X_replica
- r_do_add
- r_do_replace
- r_not_replace
- r_do_propagate
- r_do_mhomed_merge
- r_do_late_release_demand_handler
- r_do_late_release_demand
- r_do_challenge_handler
- r_do_challenge
- r_do_release_demand_handler
- r_do_release_demand
- r_do_sgroup_merge
- wreplsrv_apply_one_record
- wreplsrv_apply_records
1 /*
2 Unix SMB/CIFS implementation.
3
4 WINS Replication server
5
6 Copyright (C) Stefan Metzmacher 2005
7
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.
12
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.
17
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/>.
20 */
21
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"
32 #include "param/param.h"
33
34 enum _R_ACTION {
35 R_INVALID,
36 R_DO_REPLACE,
37 R_NOT_REPLACE,
38 R_DO_PROPAGATE,
39 R_DO_CHALLENGE,
40 R_DO_RELEASE_DEMAND,
41 R_DO_SGROUP_MERGE
42 };
43
44 static const char *_R_ACTION_enum_string(enum _R_ACTION action)
/* [<][>][^][v][top][bottom][index][help] */
45 {
46 switch (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";
54 }
55
56 return "enum _R_ACTION unknown";
57 }
58
59 #define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
60 #if 0 /* unused */
61 #define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
62 #endif
63 #define R_IS_TOMBSTONE(r) ((r)->state == WREPL_STATE_TOMBSTONE)
64
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)
68 #if 0 /* unused */
69 #define R_IS_MHOMED(r) ((r)->type == WREPL_TYPE_MHOMED)
70 #endif
71
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)
/* [<][>][^][v][top][bottom][index][help] */
74 {
75 /* REPLACE */
76 return R_DO_REPLACE;
77 }
78
79 static bool r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
/* [<][>][^][v][top][bottom][index][help] */
80 {
81 uint32_t i,j;
82 size_t len = winsdb_addr_list_length(r1->addresses);
83
84 for (i=0; i < len; i++) {
85 bool found = false;
86 for (j=0; j < r2->num_addresses; j++) {
87 if (strcmp(r1->addresses[i]->address, r2->addresses[j].address) != 0) {
88 continue;
89 }
90
91 if (check_owners && strcmp(r1->addresses[i]->wins_owner, r2->addresses[j].owner) != 0) {
92 return false;
93 }
94 found = true;
95 break;
96 }
97 if (!found) return false;
98 }
99
100 return true;
101 }
102
103 static bool r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
/* [<][>][^][v][top][bottom][index][help] */
104 {
105 uint32_t i,j;
106 size_t len = winsdb_addr_list_length(r1->addresses);
107
108 for (i=0; i < r2->num_addresses; i++) {
109 bool found = false;
110 for (j=0; j < len; j++) {
111 if (strcmp(r2->addresses[i].address, r1->addresses[j]->address) != 0) {
112 continue;
113 }
114
115 if (check_owners && strcmp(r2->addresses[i].owner, r1->addresses[j]->wins_owner) != 0) {
116 return false;
117 }
118 found = true;
119 break;
120 }
121 if (!found) return false;
122 }
123
124 return true;
125 }
126
127 static bool r_1_is_same_as_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
/* [<][>][^][v][top][bottom][index][help] */
128 {
129 size_t len = winsdb_addr_list_length(r1->addresses);
130
131 if (len != r2->num_addresses) {
132 return false;
133 }
134
135 return r_1_is_superset_of_2_address_list(r1, r2, check_owners);
136 }
137
138 static bool r_contains_addrs_from_owner(struct winsdb_record *r1, const char *owner)
/* [<][>][^][v][top][bottom][index][help] */
139 {
140 uint32_t i;
141 size_t len = winsdb_addr_list_length(r1->addresses);
142
143 for (i=0; i < len; i++) {
144 if (strcmp(r1->addresses[i]->wins_owner, owner) == 0) {
145 return true;
146 }
147 }
148
149 return false;
150 }
151
152 /*
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
177 */
178 static enum _R_ACTION replace_unique_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
/* [<][>][^][v][top][bottom][index][help] */
179 {
180 if (!R_IS_ACTIVE(r1)) {
181 /* REPLACE */
182 return R_DO_REPLACE;
183 }
184
185 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
186 /* REPLACE */
187 return R_DO_REPLACE;
188 }
189
190 /* NOT REPLACE */
191 return R_NOT_REPLACE;
192 }
193
194 /*
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
219 */
220 static enum _R_ACTION replace_group_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
/* [<][>][^][v][top][bottom][index][help] */
221 {
222 if (!R_IS_ACTIVE(r1) && R_IS_GROUP(r2)) {
223 /* REPLACE */
224 return R_DO_REPLACE;
225 }
226
227 if (R_IS_TOMBSTONE(r1) && !R_IS_UNIQUE(r2)) {
228 /* REPLACE */
229 return R_DO_REPLACE;
230 }
231
232 /* NOT REPLACE */
233 return R_NOT_REPLACE;
234 }
235
236 /*
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
259
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
266
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
273
274
275 this is a bit strange, incoming tombstone replicas always replace old replicas:
276
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
281 */
282 static enum _R_ACTION replace_sgroup_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
/* [<][>][^][v][top][bottom][index][help] */
283 {
284 if (!R_IS_ACTIVE(r1)) {
285 /* REPLACE */
286 return R_DO_REPLACE;
287 }
288
289 if (!R_IS_SGROUP(r2)) {
290 /* NOT REPLACE */
291 return R_NOT_REPLACE;
292 }
293
294 /*
295 * this is strange, but correct
296 * the incoming tombstone replace the current active
297 * record
298 */
299 if (!R_IS_ACTIVE(r2)) {
300 /* REPLACE */
301 return R_DO_REPLACE;
302 }
303
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;
308 }
309
310 /* NOT REPLACE */
311 return R_NOT_REPLACE;
312 }
313
314 if (r_1_is_superset_of_2_address_list(r1, r2, true)) {
315 /* NOT REPLACE */
316 return R_NOT_REPLACE;
317 }
318
319 if (r_1_is_same_as_2_address_list(r1, r2, false)) {
320 /* REPLACE */
321 return R_DO_REPLACE;
322 }
323
324 /* not handled here: MERGE */
325 return R_DO_SGROUP_MERGE;
326 }
327
328 /*
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
353 */
354 static enum _R_ACTION replace_mhomed_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
/* [<][>][^][v][top][bottom][index][help] */
355 {
356 if (!R_IS_ACTIVE(r1)) {
357 /* REPLACE */
358 return R_DO_REPLACE;
359 }
360
361 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
362 /* REPLACE */
363 return R_DO_REPLACE;
364 }
365
366 /* NOT REPLACE */
367 return R_NOT_REPLACE;
368 }
369
370 /*
371 active:
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
396
397 released:
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
414 */
415 static enum _R_ACTION replace_unique_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
/* [<][>][^][v][top][bottom][index][help] */
416 {
417 if (!R_IS_ACTIVE(r1)) {
418 /* REPLACE */
419 return R_DO_REPLACE;
420 }
421
422 if (!R_IS_ACTIVE(r2)) {
423 /* NOT REPLACE, and PROPAGATE */
424 return R_DO_PROPAGATE;
425 }
426
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;
430 }
431
432 /*
433 * here we only have unique,active,owned vs.
434 * is unique,active,replica or mhomed,active,replica
435 */
436
437 if (r_1_is_subset_of_2_address_list(r1, r2, false)) {
438 /*
439 * if r1 has a subset(or same) of the addresses of r2
440 * <=>
441 * if r2 has a superset(or same) of the addresses of r1
442 *
443 * then replace the record
444 */
445 return R_DO_REPLACE;
446 }
447
448 /*
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...
452 */
453 return R_DO_CHALLENGE;
454 }
455
456 /*
457 active:
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
474
475 released:
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
492 */
493 static enum _R_ACTION replace_group_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
/* [<][>][^][v][top][bottom][index][help] */
494 {
495 if (R_IS_GROUP(r1) && R_IS_GROUP(r2)) {
496 if (!R_IS_ACTIVE(r1) || R_IS_ACTIVE(r2)) {
497 /* REPLACE */
498 return R_DO_REPLACE;
499 }
500 }
501
502 /* NOT REPLACE, but PROPAGATE */
503 return R_DO_PROPAGATE;
504 }
505
506 /*
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
520
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
530
531 SGROUP,ACTIVE vs. SGROUP,* is not handled here!
532
533 released:
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
550 */
551 static enum _R_ACTION replace_sgroup_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
/* [<][>][^][v][top][bottom][index][help] */
552 {
553 if (!R_IS_ACTIVE(r1)) {
554 /* REPLACE */
555 return R_DO_REPLACE;
556 }
557
558 if (!R_IS_SGROUP(r2) || !R_IS_ACTIVE(r2)) {
559 /* NOT REPLACE, but PROPAGATE */
560 return R_DO_PROPAGATE;
561 }
562
563 if (r_1_is_same_as_2_address_list(r1, r2, true)) {
564 /*
565 * as we're the old owner and the addresses and their
566 * owners are identical
567 */
568 return R_NOT_REPLACE;
569 }
570
571 /* not handled here: MERGE */
572 return R_DO_SGROUP_MERGE;
573 }
574
575 /*
576 active:
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
608
609 released:
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
626 */
627 static enum _R_ACTION replace_mhomed_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
/* [<][>][^][v][top][bottom][index][help] */
628 {
629 if (!R_IS_ACTIVE(r1)) {
630 /* REPLACE */
631 return R_DO_REPLACE;
632 }
633
634 if (!R_IS_ACTIVE(r2)) {
635 /* NOT REPLACE, but PROPAGATE */
636 return R_DO_PROPAGATE;
637 }
638
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;
642 }
643
644 /*
645 * here we only have mhomed,active,owned vs.
646 * is unique,active,replica or mhomed,active,replica
647 */
648
649 if (r_1_is_subset_of_2_address_list(r1, r2, false)) {
650 /*
651 * if r1 has a subset(or same) of the addresses of r2
652 * <=>
653 * if r2 has a superset(or same) of the addresses of r1
654 *
655 * then replace the record
656 */
657 return R_DO_REPLACE;
658 }
659
660 /*
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...
664 */
665 return R_DO_CHALLENGE;
666 }
667
668 static NTSTATUS r_do_add(struct wreplsrv_partner *partner,
/* [<][>][^][v][top][bottom][index][help] */
669 TALLOC_CTX *mem_ctx,
670 struct wrepl_wins_owner *owner,
671 struct wrepl_name *replica)
672 {
673 struct winsdb_record *rec;
674 uint32_t i;
675 uint8_t ret;
676
677 rec = talloc(mem_ctx, struct winsdb_record);
678 NT_STATUS_HAVE_NO_MEMORY(rec);
679
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;
691
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,
695 rec, rec->addresses,
696 replica->addresses[i].address,
697 replica->addresses[i].owner,
698 rec->expire_time,
699 false);
700 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
701 }
702
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;
708 }
709
710 DEBUG(4,("added record %s\n",
711 nbt_name_string(mem_ctx, &replica->name)));
712
713 return NT_STATUS_OK;
714 }
715
716 static NTSTATUS r_do_replace(struct wreplsrv_partner *partner,
/* [<][>][^][v][top][bottom][index][help] */
717 TALLOC_CTX *mem_ctx,
718 struct winsdb_record *rec,
719 struct wrepl_wins_owner *owner,
720 struct wrepl_name *replica)
721 {
722 uint32_t i;
723 uint8_t ret;
724
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;
736
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,
740 rec, rec->addresses,
741 replica->addresses[i].address,
742 replica->addresses[i].owner,
743 rec->expire_time,
744 false);
745 NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
746 }
747
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;
753 }
754
755 DEBUG(4,("replaced record %s\n",
756 nbt_name_string(mem_ctx, &replica->name)));
757
758 return NT_STATUS_OK;
759 }
760
761 static NTSTATUS r_not_replace(struct wreplsrv_partner *partner,
/* [<][>][^][v][top][bottom][index][help] */
762 TALLOC_CTX *mem_ctx,
763 struct winsdb_record *rec,
764 struct wrepl_wins_owner *owner,
765 struct wrepl_name *replica)
766 {
767 DEBUG(4,("not replace record %s\n",
768 nbt_name_string(mem_ctx, &replica->name)));
769 return NT_STATUS_OK;
770 }
771
772 static NTSTATUS r_do_propagate(struct wreplsrv_partner *partner,
/* [<][>][^][v][top][bottom][index][help] */
773 TALLOC_CTX *mem_ctx,
774 struct winsdb_record *rec,
775 struct wrepl_wins_owner *owner,
776 struct wrepl_name *replica)
777 {
778 uint8_t ret;
779 uint32_t modify_flags;
780
781 /*
782 * allocate a new version id for the record to that it'll be replicated
783 */
784 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
785
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;
791 }
792
793 DEBUG(4,("propagated record %s\n",
794 nbt_name_string(mem_ctx, &replica->name)));
795
796 return NT_STATUS_OK;
797 }
798
799 /*
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
813 */
814 static NTSTATUS r_do_mhomed_merge(struct wreplsrv_partner *partner,
/* [<][>][^][v][top][bottom][index][help] */
815 TALLOC_CTX *mem_ctx,
816 struct winsdb_record *rec,
817 struct wrepl_wins_owner *owner,
818 struct wrepl_name *replica)
819 {
820 struct winsdb_record *merge;
821 uint32_t i,j;
822 uint8_t ret;
823 size_t len;
824
825 merge = talloc(mem_ctx, struct winsdb_record);
826 NT_STATUS_HAVE_NO_MEMORY(merge);
827
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;
839
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,
845 merge->expire_time,
846 false);
847 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
848 }
849
850 len = winsdb_addr_list_length(rec->addresses);
851
852 for (i=0; i < len; i++) {
853 bool found = false;
854 for (j=0; j < replica->num_addresses; j++) {
855 if (strcmp(replica->addresses[j].address, rec->addresses[i]->address) == 0) {
856 found = true;
857 break;
858 }
859 }
860 if (found) continue;
861
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,
867 false);
868 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
869 }
870
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;
876 }
877
878 DEBUG(4,("mhomed merge record %s\n",
879 nbt_name_string(mem_ctx, &replica->name)));
880
881 return NT_STATUS_OK;
882 }
883
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;
891 };
892
893 static void r_do_late_release_demand_handler(struct irpc_request *ireq)
/* [<][>][^][v][top][bottom][index][help] */
894 {
895 NTSTATUS status;
896 struct r_do_challenge_state *state = talloc_get_type(ireq->async.private_data,
897 struct r_do_challenge_state);
898
899 status = irpc_call_recv(ireq);
900 /* don't care about the result */
901 talloc_free(state);
902 }
903
904 static NTSTATUS r_do_late_release_demand(struct r_do_challenge_state *state)
/* [<][>][^][v][top][bottom][index][help] */
905 {
906 struct irpc_request *ireq;
907 struct server_id *nbt_servers;
908 struct nbtd_proxy_wins_release_demand r;
909 uint32_t i;
910
911 DEBUG(4,("late release demand record %s\n",
912 nbt_name_string(state, &state->replica.name)));
913
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;
917 }
918
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;
926 }
927
928 ireq = IRPC_CALL_SEND(state->msg_ctx, nbt_servers[0],
929 irpc, NBTD_PROXY_WINS_RELEASE_DEMAND,
930 &r, state);
931 NT_STATUS_HAVE_NO_MEMORY(ireq);
932
933 ireq->async.fn = r_do_late_release_demand_handler;
934 ireq->async.private_data= state;
935
936 return NT_STATUS_OK;
937 }
938
939 /*
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
953 */
954 static void r_do_challenge_handler(struct irpc_request *ireq)
/* [<][>][^][v][top][bottom][index][help] */
955 {
956 NTSTATUS status;
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;
961 bool found = false;
962 uint32_t i,j;
963 uint32_t num_rec_addrs;
964
965 status = irpc_call_recv(ireq);
966
967 DEBUG(4,("r_do_challenge_handler: %s: %s\n",
968 nbt_name_string(state, &state->replica.name), nt_errstr(status)));
969
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);
973 talloc_free(state);
974 return;
975 }
976
977 for (i=0; i < state->replica.num_addresses; i++) {
978 found = false;
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) {
982 found = true;
983 break;
984 }
985 }
986 if (found) continue;
987
988 new_is_subset = false;
989 break;
990 }
991
992 if (!new_is_subset) {
993 r_not_replace(state->partner, state, state->rec, &state->owner, &state->replica);
994 talloc_free(state);
995 return;
996 }
997
998 num_rec_addrs = winsdb_addr_list_length(state->rec->addresses);
999 for (i=0; i < num_rec_addrs; i++) {
1000 found = false;
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) {
1004 found = true;
1005 break;
1006 }
1007 }
1008 if (found) continue;
1009
1010 old_is_subset = false;
1011 break;
1012 }
1013
1014 if (!old_is_subset) {
1015 status = r_do_late_release_demand(state);
1016 /*
1017 * only free state on error, because we pass it down,
1018 * and r_do_late_release_demand() will free it
1019 */
1020 if (!NT_STATUS_IS_OK(status)) {
1021 talloc_free(state);
1022 }
1023 return;
1024 }
1025
1026 r_do_mhomed_merge(state->partner, state, state->rec, &state->owner, &state->replica);
1027 talloc_free(state);
1028 }
1029
1030 static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner,
/* [<][>][^][v][top][bottom][index][help] */
1031 TALLOC_CTX *mem_ctx,
1032 struct winsdb_record *rec,
1033 struct wrepl_wins_owner *owner,
1034 struct wrepl_name *replica)
1035 {
1036 struct irpc_request *ireq;
1037 struct r_do_challenge_state *state;
1038 struct server_id *nbt_servers;
1039 const char **addrs;
1040 uint32_t i;
1041
1042 DEBUG(4,("challenge record %s\n",
1043 nbt_name_string(mem_ctx, &replica->name)));
1044
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);
1056
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;
1060 }
1061
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];
1071 }
1072
1073 ireq = IRPC_CALL_SEND(state->msg_ctx, nbt_servers[0],
1074 irpc, NBTD_PROXY_WINS_CHALLENGE,
1075 &state->r, state);
1076 NT_STATUS_HAVE_NO_MEMORY(ireq);
1077
1078 ireq->async.fn = r_do_challenge_handler;
1079 ireq->async.private_data= state;
1080
1081 talloc_steal(partner, state);
1082 return NT_STATUS_OK;
1083 }
1084
1085 struct r_do_release_demand_state {
1086 struct messaging_context *msg_ctx;
1087 struct nbtd_proxy_wins_release_demand r;
1088 };
1089
1090 static void r_do_release_demand_handler(struct irpc_request *ireq)
/* [<][>][^][v][top][bottom][index][help] */
1091 {
1092 NTSTATUS status;
1093 struct r_do_release_demand_state *state = talloc_get_type(ireq->async.private_data,
1094 struct r_do_release_demand_state);
1095
1096 status = irpc_call_recv(ireq);
1097 /* don't care about the result */
1098 talloc_free(state);
1099 }
1100
1101 static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner,
/* [<][>][^][v][top][bottom][index][help] */
1102 TALLOC_CTX *mem_ctx,
1103 struct winsdb_record *rec,
1104 struct wrepl_wins_owner *owner,
1105 struct wrepl_name *replica)
1106 {
1107 NTSTATUS status;
1108 struct irpc_request *ireq;
1109 struct server_id *nbt_servers;
1110 const char **addrs;
1111 struct winsdb_addr **addresses;
1112 struct r_do_release_demand_state *state;
1113 uint32_t i;
1114
1115 /*
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
1119 */
1120 addresses = rec->addresses;
1121
1122 status = r_do_replace(partner, mem_ctx, rec, owner, replica);
1123 NT_STATUS_NOT_OK_RETURN(status);
1124
1125 DEBUG(4,("release demand record %s\n",
1126 nbt_name_string(mem_ctx, &replica->name)));
1127
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;
1131
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;
1135 }
1136
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];
1147 }
1148
1149 ireq = IRPC_CALL_SEND(state->msg_ctx, nbt_servers[0],
1150 irpc, NBTD_PROXY_WINS_RELEASE_DEMAND,
1151 &state->r, state);
1152 NT_STATUS_HAVE_NO_MEMORY(ireq);
1153
1154 ireq->async.fn = r_do_release_demand_handler;
1155 ireq->async.private_data= state;
1156
1157 talloc_steal(partner, state);
1158 return NT_STATUS_OK;
1159 }
1160
1161 /*
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
1168
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
1175
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
1181 */
1182 static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner,
/* [<][>][^][v][top][bottom][index][help] */
1183 TALLOC_CTX *mem_ctx,
1184 struct winsdb_record *rec,
1185 struct wrepl_wins_owner *owner,
1186 struct wrepl_name *replica)
1187 {
1188 struct winsdb_record *merge;
1189 uint32_t modify_flags = 0;
1190 uint32_t i,j;
1191 uint8_t ret;
1192 size_t len;
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;
1198
1199 merge = talloc(mem_ctx, struct winsdb_record);
1200 NT_STATUS_HAVE_NO_MEMORY(merge);
1201
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;
1213
1214 len = winsdb_addr_list_length(rec->addresses);
1215
1216 for (i=0; i < len; i++) {
1217 bool found = false;
1218
1219 for (j=0; j < replica->num_addresses; j++) {
1220 if (strcmp(rec->addresses[i]->address, replica->addresses[j].address) != 0) {
1221 continue;
1222 }
1223
1224 found = true;
1225
1226 if (strcmp(rec->addresses[i]->wins_owner, replica->addresses[j].owner) != 0) {
1227 changed_old_addrs = true;
1228 break;
1229 }
1230 break;
1231 }
1232
1233 /*
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
1236 */
1237 if (!found && strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) {
1238 changed_old_addrs = true;
1239 continue;
1240 }
1241
1242 /*
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
1246 */
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,
1252 false);
1253 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
1254 }
1255
1256 for (i=0; i < replica->num_addresses; i++) {
1257 if (propagate &&
1258 strcmp(replica->addresses[i].owner, local_owner) == 0) {
1259 const struct winsdb_addr *a;
1260
1261 /*
1262 * NOTE: this is different to the windows behavior
1263 * and off by default, but it better propagated
1264 * name releases
1265 */
1266 a = winsdb_addr_list_check(merge->addresses,
1267 replica->addresses[i].address);
1268 if (!a) {
1269 /* don't add addresses owned by us */
1270 skip_replica_owned_by_us = true;
1271 }
1272 continue;
1273 }
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,
1278 merge->expire_time,
1279 false);
1280 NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
1281 }
1282
1283 /* we the old addresses change changed we don't become the owner */
1284 if (changed_old_addrs) {
1285 become_owner = false;
1286 }
1287
1288 /*
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
1292 */
1293 if (skip_replica_owned_by_us) {
1294 become_owner = true;
1295 }
1296
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;
1300 }
1301
1302 /*
1303 * if the result has no addresses we take the ownership
1304 */
1305 len = winsdb_addr_list_length(merge->addresses);
1306 if (len == 0) {
1307 become_owner = true;
1308 }
1309
1310 /*
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
1313 */
1314 if (become_owner) {
1315 time_t lh = 0;
1316
1317 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
1318
1319 /*
1320 * if we're the owner, the expire time becomes the highest
1321 * expire time of owned addresses
1322 */
1323 len = winsdb_addr_list_length(merge->addresses);
1324
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);
1328 }
1329 }
1330
1331 if (lh != 0) {
1332 merge->expire_time = lh;
1333 }
1334 }
1335
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;
1341 }
1342
1343 DEBUG(4,("sgroup merge record %s\n",
1344 nbt_name_string(mem_ctx, &replica->name)));
1345
1346 return NT_STATUS_OK;
1347 }
1348
1349 static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
/* [<][>][^][v][top][bottom][index][help] */
1350 TALLOC_CTX *mem_ctx,
1351 struct wrepl_wins_owner *owner,
1352 struct wrepl_name *replica)
1353 {
1354 NTSTATUS status;
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;
1360
1361 status = winsdb_lookup(partner->service->wins_db,
1362 &replica->name, mem_ctx, &rec);
1363 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
1364 return r_do_add(partner, mem_ctx, owner, replica);
1365 }
1366 NT_STATUS_NOT_OK_RETURN(status);
1367
1368 if (strcmp(rec->wins_owner, partner->service->wins_db->local_owner)==0) {
1369 local_vs_replica = true;
1370 } else if (strcmp(rec->wins_owner, owner->address)==0) {
1371 same_owner = true;
1372 } else {
1373 replica_vs_replica = true;
1374 }
1375
1376 if (rec->is_static && !same_owner) {
1377 action = R_NOT_REPLACE;
1378
1379 /*
1380 * if we own the local record, then propagate it back to
1381 * the other wins servers.
1382 * to prevent ping-pong with other servers, we don't do this
1383 * if the replica is static too.
1384 *
1385 * It seems that w2k3 doesn't do this, but I thing that's a bug
1386 * and doing propagation helps to have consistent data on all servers
1387 */
1388 if (local_vs_replica && !replica->is_static) {
1389 action = R_DO_PROPAGATE;
1390 }
1391 } else if (replica->is_static && !rec->is_static && !same_owner) {
1392 action = R_DO_REPLACE;
1393 } else if (same_owner) {
1394 action = replace_same_owner(rec, replica);
1395 } else if (replica_vs_replica) {
1396 switch (rec->type) {
1397 case WREPL_TYPE_UNIQUE:
1398 action = replace_unique_replica_vs_X_replica(rec, replica);
1399 break;
1400 case WREPL_TYPE_GROUP:
1401 action = replace_group_replica_vs_X_replica(rec, replica);
1402 break;
1403 case WREPL_TYPE_SGROUP:
1404 action = replace_sgroup_replica_vs_X_replica(rec, replica);
1405 break;
1406 case WREPL_TYPE_MHOMED:
1407 action = replace_mhomed_replica_vs_X_replica(rec, replica);
1408 break;
1409 }
1410 } else if (local_vs_replica) {
1411 switch (rec->type) {
1412 case WREPL_TYPE_UNIQUE:
1413 action = replace_unique_owned_vs_X_replica(rec, replica);
1414 break;
1415 case WREPL_TYPE_GROUP:
1416 action = replace_group_owned_vs_X_replica(rec, replica);
1417 break;
1418 case WREPL_TYPE_SGROUP:
1419 action = replace_sgroup_owned_vs_X_replica(rec, replica);
1420 break;
1421 case WREPL_TYPE_MHOMED:
1422 action = replace_mhomed_owned_vs_X_replica(rec, replica);
1423 break;
1424 }
1425 }
1426
1427 DEBUG(4,("apply record %s: %s\n",
1428 nbt_name_string(mem_ctx, &replica->name), _R_ACTION_enum_string(action)));
1429
1430 switch (action) {
1431 case R_INVALID: break;
1432 case R_DO_REPLACE:
1433 return r_do_replace(partner, mem_ctx, rec, owner, replica);
1434 case R_NOT_REPLACE:
1435 return r_not_replace(partner, mem_ctx, rec, owner, replica);
1436 case R_DO_PROPAGATE:
1437 return r_do_propagate(partner, mem_ctx, rec, owner, replica);
1438 case R_DO_CHALLENGE:
1439 return r_do_challenge(partner, mem_ctx, rec, owner, replica);
1440 case R_DO_RELEASE_DEMAND:
1441 return r_do_release_demand(partner, mem_ctx, rec, owner, replica);
1442 case R_DO_SGROUP_MERGE:
1443 return r_do_sgroup_merge(partner, mem_ctx, rec, owner, replica);
1444 }
1445
1446 return NT_STATUS_INTERNAL_ERROR;
1447 }
1448
1449 NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner,
/* [<][>][^][v][top][bottom][index][help] */
1450 struct wrepl_wins_owner *owner,
1451 uint32_t num_names, struct wrepl_name *names)
1452 {
1453 NTSTATUS status;
1454 uint32_t i;
1455
1456 DEBUG(4,("apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
1457 num_names, owner->address,
1458 (long long)owner->min_version,
1459 (long long)owner->max_version,
1460 partner->address));
1461
1462 for (i=0; i < num_names; i++) {
1463 TALLOC_CTX *tmp_mem = talloc_new(partner);
1464 NT_STATUS_HAVE_NO_MEMORY(tmp_mem);
1465
1466 status = wreplsrv_apply_one_record(partner, tmp_mem,
1467 owner, &names[i]);
1468 talloc_free(tmp_mem);
1469 NT_STATUS_NOT_OK_RETURN(status);
1470 }
1471
1472 status = wreplsrv_add_table(partner->service,
1473 partner->service,
1474 &partner->service->table,
1475 owner->address,
1476 owner->max_version);
1477 NT_STATUS_NOT_OK_RETURN(status);
1478
1479 return NT_STATUS_OK;
1480 }