Line data Source code
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 <tevent.h>
24 : #include "samba/service_task.h"
25 : #include "lib/messaging/irpc.h"
26 : #include "librpc/gen_ndr/ndr_irpc_c.h"
27 : #include "librpc/gen_ndr/ndr_winsrepl.h"
28 : #include "wrepl_server/wrepl_server.h"
29 : #include "nbt_server/wins/winsdb.h"
30 : #include "libcli/wrepl/winsrepl.h"
31 : #include "system/time.h"
32 : #include "librpc/gen_ndr/ndr_nbt.h"
33 : #include "param/param.h"
34 :
35 : enum _R_ACTION {
36 : R_INVALID,
37 : R_DO_REPLACE,
38 : R_NOT_REPLACE,
39 : R_DO_PROPAGATE,
40 : R_DO_CHALLENGE,
41 : R_DO_RELEASE_DEMAND,
42 : R_DO_SGROUP_MERGE
43 : };
44 :
45 0 : static const char *_R_ACTION_enum_string(enum _R_ACTION action)
46 : {
47 0 : switch (action) {
48 0 : case R_INVALID: return "INVALID";
49 0 : case R_DO_REPLACE: return "REPLACE";
50 0 : case R_NOT_REPLACE: return "NOT_REPLACE";
51 0 : case R_DO_PROPAGATE: return "PROPAGATE";
52 0 : case R_DO_CHALLENGE: return "CHALLEGNE";
53 0 : case R_DO_RELEASE_DEMAND: return "RELEASE_DEMAND";
54 0 : case R_DO_SGROUP_MERGE: return "SGROUP_MERGE";
55 : }
56 :
57 0 : return "enum _R_ACTION unknown";
58 : }
59 :
60 : #define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
61 : #if 0 /* unused */
62 : #define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
63 : #endif
64 : #define R_IS_TOMBSTONE(r) ((r)->state == WREPL_STATE_TOMBSTONE)
65 :
66 : #define R_IS_UNIQUE(r) ((r)->type == WREPL_TYPE_UNIQUE)
67 : #define R_IS_GROUP(r) ((r)->type == WREPL_TYPE_GROUP)
68 : #define R_IS_SGROUP(r) ((r)->type == WREPL_TYPE_SGROUP)
69 : #if 0 /* unused */
70 : #define R_IS_MHOMED(r) ((r)->type == WREPL_TYPE_MHOMED)
71 : #endif
72 :
73 : /* blindly overwrite records from the same owner in all cases */
74 350 : static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_name *r2)
75 : {
76 : /* REPLACE */
77 350 : return R_DO_REPLACE;
78 : }
79 :
80 29 : static bool r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
81 : {
82 0 : uint32_t i,j;
83 29 : size_t len = winsdb_addr_list_length(r1->addresses);
84 :
85 45 : for (i=0; i < len; i++) {
86 37 : bool found = false;
87 66 : for (j=0; j < r2->num_addresses; j++) {
88 45 : if (strcmp(r1->addresses[i]->address, r2->addresses[j].address) != 0) {
89 29 : continue;
90 : }
91 :
92 16 : if (check_owners && strcmp(r1->addresses[i]->wins_owner, r2->addresses[j].owner) != 0) {
93 0 : return false;
94 : }
95 16 : found = true;
96 16 : break;
97 : }
98 37 : if (!found) return false;
99 : }
100 :
101 8 : return true;
102 : }
103 :
104 18 : static bool r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
105 : {
106 0 : uint32_t i,j;
107 18 : size_t len = winsdb_addr_list_length(r1->addresses);
108 :
109 30 : for (i=0; i < r2->num_addresses; i++) {
110 26 : bool found = false;
111 58 : for (j=0; j < len; j++) {
112 48 : if (strcmp(r2->addresses[i].address, r1->addresses[j]->address) != 0) {
113 32 : continue;
114 : }
115 :
116 16 : if (check_owners && strcmp(r2->addresses[i].owner, r1->addresses[j]->wins_owner) != 0) {
117 4 : return false;
118 : }
119 12 : found = true;
120 12 : break;
121 : }
122 22 : if (!found) return false;
123 : }
124 :
125 4 : return true;
126 : }
127 :
128 20 : static bool r_1_is_same_as_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
129 : {
130 20 : size_t len = winsdb_addr_list_length(r1->addresses);
131 :
132 20 : if (len != r2->num_addresses) {
133 12 : return false;
134 : }
135 :
136 8 : return r_1_is_superset_of_2_address_list(r1, r2, check_owners);
137 : }
138 :
139 8 : static bool r_contains_addrs_from_owner(struct winsdb_record *r1, const char *owner)
140 : {
141 0 : uint32_t i;
142 8 : size_t len = winsdb_addr_list_length(r1->addresses);
143 :
144 16 : for (i=0; i < len; i++) {
145 13 : if (strcmp(r1->addresses[i]->wins_owner, owner) == 0) {
146 5 : return true;
147 : }
148 : }
149 :
150 3 : return false;
151 : }
152 :
153 : /*
154 : UNIQUE,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
155 : UNIQUE,ACTIVE vs. UNIQUE,TOMBSTONE with different ip(s) => NOT REPLACE
156 : UNIQUE,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
157 : UNIQUE,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
158 : UNIQUE,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
159 : UNIQUE,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
160 : UNIQUE,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
161 : UNIQUE,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
162 : UNIQUE,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
163 : UNIQUE,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
164 : UNIQUE,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
165 : UNIQUE,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
166 : UNIQUE,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
167 : UNIQUE,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
168 : UNIQUE,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
169 : UNIQUE,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
170 : UNIQUE,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
171 : UNIQUE,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
172 : UNIQUE,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
173 : UNIQUE,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
174 : UNIQUE,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
175 : UNIQUE,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
176 : UNIQUE,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
177 : UNIQUE,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
178 : */
179 28 : static enum _R_ACTION replace_unique_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
180 : {
181 28 : if (!R_IS_ACTIVE(r1)) {
182 : /* REPLACE */
183 20 : return R_DO_REPLACE;
184 : }
185 :
186 8 : if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
187 : /* REPLACE */
188 3 : return R_DO_REPLACE;
189 : }
190 :
191 : /* NOT REPLACE */
192 5 : return R_NOT_REPLACE;
193 : }
194 :
195 : /*
196 : GROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
197 : GROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
198 : GROUP,RELEASED vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
199 : GROUP,RELEASED vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
200 : GROUP,TOMBSTONE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
201 : GROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
202 : GROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
203 : GROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
204 : GROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
205 : GROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
206 : GROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
207 : GROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
208 : GROUP,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
209 : GROUP,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
210 : GROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
211 : GROUP,RELEASED vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
212 : GROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
213 : GROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
214 : GROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
215 : GROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
216 : GROUP,RELEASED vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
217 : GROUP,RELEASED vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
218 : GROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
219 : GROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
220 : */
221 25 : static enum _R_ACTION replace_group_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
222 : {
223 25 : if (!R_IS_ACTIVE(r1) && R_IS_GROUP(r2)) {
224 : /* REPLACE */
225 3 : return R_DO_REPLACE;
226 : }
227 :
228 22 : if (R_IS_TOMBSTONE(r1) && !R_IS_UNIQUE(r2)) {
229 : /* REPLACE */
230 5 : return R_DO_REPLACE;
231 : }
232 :
233 : /* NOT REPLACE */
234 17 : return R_NOT_REPLACE;
235 : }
236 :
237 : /*
238 : SGROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
239 : SGROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
240 : SGROUP,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
241 : SGROUP,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
242 : SGROUP,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
243 : SGROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
244 : SGROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
245 : SGROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
246 : SGROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
247 : SGROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
248 : SGROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
249 : SGROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
250 : SGROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
251 : SGROUP,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
252 : SGROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
253 : SGROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
254 : SGROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
255 : SGROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
256 : SGROUP,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
257 : SGROUP,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
258 : SGROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
259 : SGROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
260 :
261 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
262 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
263 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
264 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
265 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
266 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
267 :
268 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
269 : 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
270 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
271 : 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
272 : 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
273 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
274 :
275 :
276 : this is a bit strange, incoming tombstone replicas always replace old replicas:
277 :
278 : SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:NULL => B:NULL => REPLACE
279 : SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4 => REPLACE
280 : SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:B_3_4 => B:B_3_4 => REPLACE
281 : SGROUP,ACTIVE vs. SGROUP,TOMBSTONE A:B_3_4_X_3_4 vs. B:B_3_4_X_3_4 => B:B_3_4_X_3_4 => REPLACE
282 : */
283 63 : static enum _R_ACTION replace_sgroup_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
284 : {
285 63 : if (!R_IS_ACTIVE(r1)) {
286 : /* REPLACE */
287 35 : return R_DO_REPLACE;
288 : }
289 :
290 28 : if (!R_IS_SGROUP(r2)) {
291 : /* NOT REPLACE */
292 6 : return R_NOT_REPLACE;
293 : }
294 :
295 : /*
296 : * this is strange, but correct
297 : * the incoming tombstone replace the current active
298 : * record
299 : */
300 22 : if (!R_IS_ACTIVE(r2)) {
301 : /* REPLACE */
302 4 : return R_DO_REPLACE;
303 : }
304 :
305 18 : if (r2->num_addresses == 0) {
306 8 : if (r_contains_addrs_from_owner(r1, r2->owner)) {
307 : /* not handled here: MERGE */
308 5 : return R_DO_SGROUP_MERGE;
309 : }
310 :
311 : /* NOT REPLACE */
312 3 : return R_NOT_REPLACE;
313 : }
314 :
315 10 : if (r_1_is_superset_of_2_address_list(r1, r2, true)) {
316 : /* NOT REPLACE */
317 2 : return R_NOT_REPLACE;
318 : }
319 :
320 8 : if (r_1_is_same_as_2_address_list(r1, r2, false)) {
321 : /* REPLACE */
322 2 : return R_DO_REPLACE;
323 : }
324 :
325 : /* not handled here: MERGE */
326 6 : return R_DO_SGROUP_MERGE;
327 : }
328 :
329 : /*
330 : MHOMED,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
331 : MHOMED,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
332 : MHOMED,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
333 : MHOMED,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
334 : MHOMED,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
335 : MHOMED,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
336 : MHOMED,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
337 : MHOMED,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
338 : MHOMED,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
339 : MHOMED,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
340 : MHOMED,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
341 : MHOMED,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
342 : MHOMED,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
343 : MHOMED,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
344 : MHOMED,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
345 : MHOMED,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
346 : MHOMED,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
347 : MHOMED,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
348 : MHOMED,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
349 : MHOMED,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
350 : MHOMED,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
351 : MHOMED,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
352 : MHOMED,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
353 : MHOMED,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
354 : */
355 25 : static enum _R_ACTION replace_mhomed_replica_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
356 : {
357 25 : if (!R_IS_ACTIVE(r1)) {
358 : /* REPLACE */
359 16 : return R_DO_REPLACE;
360 : }
361 :
362 9 : if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
363 : /* REPLACE */
364 3 : return R_DO_REPLACE;
365 : }
366 :
367 : /* NOT REPLACE */
368 6 : return R_NOT_REPLACE;
369 : }
370 :
371 : /*
372 : active:
373 : _UA_UA_SI_U<00> => REPLACE
374 : _UA_UA_DI_P<00> => NOT REPLACE
375 : _UA_UA_DI_O<00> => NOT REPLACE
376 : _UA_UA_DI_N<00> => REPLACE
377 : _UA_UT_SI_U<00> => NOT REPLACE
378 : _UA_UT_DI_U<00> => NOT REPLACE
379 : _UA_GA_SI_R<00> => REPLACE
380 : _UA_GA_DI_R<00> => REPLACE
381 : _UA_GT_SI_U<00> => NOT REPLACE
382 : _UA_GT_DI_U<00> => NOT REPLACE
383 : _UA_SA_SI_R<00> => REPLACE
384 : _UA_SA_DI_R<00> => REPLACE
385 : _UA_ST_SI_U<00> => NOT REPLACE
386 : _UA_ST_DI_U<00> => NOT REPLACE
387 : _UA_MA_SI_U<00> => REPLACE
388 : _UA_MA_SP_U<00> => REPLACE
389 : _UA_MA_DI_P<00> => NOT REPLACE
390 : _UA_MA_DI_O<00> => NOT REPLACE
391 : _UA_MA_DI_N<00> => REPLACE
392 : _UA_MT_SI_U<00> => NOT REPLACE
393 : _UA_MT_DI_U<00> => NOT REPLACE
394 : Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
395 : _UA_UA_DI_A<00> => MHOMED_MERGE
396 : _UA_MA_DI_A<00> => MHOMED_MERGE
397 :
398 : released:
399 : _UR_UA_SI<00> => REPLACE
400 : _UR_UA_DI<00> => REPLACE
401 : _UR_UT_SI<00> => REPLACE
402 : _UR_UT_DI<00> => REPLACE
403 : _UR_GA_SI<00> => REPLACE
404 : _UR_GA_DI<00> => REPLACE
405 : _UR_GT_SI<00> => REPLACE
406 : _UR_GT_DI<00> => REPLACE
407 : _UR_SA_SI<00> => REPLACE
408 : _UR_SA_DI<00> => REPLACE
409 : _UR_ST_SI<00> => REPLACE
410 : _UR_ST_DI<00> => REPLACE
411 : _UR_MA_SI<00> => REPLACE
412 : _UR_MA_DI<00> => REPLACE
413 : _UR_MT_SI<00> => REPLACE
414 : _UR_MT_DI<00> => REPLACE
415 : */
416 40 : static enum _R_ACTION replace_unique_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
417 : {
418 40 : if (!R_IS_ACTIVE(r1)) {
419 : /* REPLACE */
420 16 : return R_DO_REPLACE;
421 : }
422 :
423 24 : if (!R_IS_ACTIVE(r2)) {
424 : /* NOT REPLACE, and PROPAGATE */
425 8 : return R_DO_PROPAGATE;
426 : }
427 :
428 16 : if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
429 : /* REPLACE and send a release demand to the old name owner */
430 4 : return R_DO_RELEASE_DEMAND;
431 : }
432 :
433 : /*
434 : * here we only have unique,active,owned vs.
435 : * is unique,active,replica or mhomed,active,replica
436 : */
437 :
438 12 : if (r_1_is_subset_of_2_address_list(r1, r2, false)) {
439 : /*
440 : * if r1 has a subset(or same) of the addresses of r2
441 : * <=>
442 : * if r2 has a superset(or same) of the addresses of r1
443 : *
444 : * then replace the record
445 : */
446 3 : return R_DO_REPLACE;
447 : }
448 :
449 : /*
450 : * in any other case, we need to do
451 : * a name request to the old name holder
452 : * to see if it's still there...
453 : */
454 9 : return R_DO_CHALLENGE;
455 : }
456 :
457 : /*
458 : active:
459 : _GA_UA_SI_U<00> => NOT REPLACE
460 : _GA_UA_DI_U<00> => NOT REPLACE
461 : _GA_UT_SI_U<00> => NOT REPLACE
462 : _GA_UT_DI_U<00> => NOT REPLACE
463 : _GA_GA_SI_U<00> => REPLACE
464 : _GA_GA_DI_U<00> => REPLACE
465 : _GA_GT_SI_U<00> => NOT REPLACE
466 : _GA_GT_DI_U<00> => NOT REPLACE
467 : _GA_SA_SI_U<00> => NOT REPLACE
468 : _GA_SA_DI_U<00> => NOT REPLACE
469 : _GA_ST_SI_U<00> => NOT REPLACE
470 : _GA_ST_DI_U<00> => NOT REPLACE
471 : _GA_MA_SI_U<00> => NOT REPLACE
472 : _GA_MA_DI_U<00> => NOT REPLACE
473 : _GA_MT_SI_U<00> => NOT REPLACE
474 : _GA_MT_DI_U<00> => NOT REPLACE
475 :
476 : released:
477 : _GR_UA_SI<00> => NOT REPLACE
478 : _GR_UA_DI<00> => NOT REPLACE
479 : _GR_UT_SI<00> => NOT REPLACE
480 : _GR_UT_DI<00> => NOT REPLACE
481 : _GR_GA_SI<00> => REPLACE
482 : _GR_GA_DI<00> => REPLACE
483 : _GR_GT_SI<00> => REPLACE
484 : _GR_GT_DI<00> => REPLACE
485 : _GR_SA_SI<00> => NOT REPLACE
486 : _GR_SA_DI<00> => NOT REPLACE
487 : _GR_ST_SI<00> => NOT REPLACE
488 : _GR_ST_DI<00> => NOT REPLACE
489 : _GR_MA_SI<00> => NOT REPLACE
490 : _GR_MA_DI<00> => NOT REPLACE
491 : _GR_MT_SI<00> => NOT REPLACE
492 : _GR_MT_DI<00> => NOT REPLACE
493 : */
494 32 : static enum _R_ACTION replace_group_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
495 : {
496 32 : if (R_IS_GROUP(r1) && R_IS_GROUP(r2)) {
497 8 : if (!R_IS_ACTIVE(r1) || R_IS_ACTIVE(r2)) {
498 : /* REPLACE */
499 6 : return R_DO_REPLACE;
500 : }
501 : }
502 :
503 : /* NOT REPLACE, but PROPAGATE */
504 26 : return R_DO_PROPAGATE;
505 : }
506 :
507 : /*
508 : active (not sgroup vs. sgroup yet!):
509 : _SA_UA_SI_U<1c> => NOT REPLACE
510 : _SA_UA_DI_U<1c> => NOT REPLACE
511 : _SA_UT_SI_U<1c> => NOT REPLACE
512 : _SA_UT_DI_U<1c> => NOT REPLACE
513 : _SA_GA_SI_U<1c> => NOT REPLACE
514 : _SA_GA_DI_U<1c> => NOT REPLACE
515 : _SA_GT_SI_U<1c> => NOT REPLACE
516 : _SA_GT_DI_U<1c> => NOT REPLACE
517 : _SA_MA_SI_U<1c> => NOT REPLACE
518 : _SA_MA_DI_U<1c> => NOT REPLACE
519 : _SA_MT_SI_U<1c> => NOT REPLACE
520 : _SA_MT_DI_U<1c> => NOT REPLACE
521 :
522 : Test Replica vs. owned active: SGROUP vs. SGROUP tests
523 : _SA_SA_DI_U<1c> => SGROUP_MERGE
524 : _SA_SA_SI_U<1c> => SGROUP_MERGE
525 : _SA_SA_SP_U<1c> => SGROUP_MERGE
526 : _SA_SA_SB_U<1c> => SGROUP_MERGE
527 : _SA_ST_DI_U<1c> => NOT REPLACE
528 : _SA_ST_SI_U<1c> => NOT REPLACE
529 : _SA_ST_SP_U<1c> => NOT REPLACE
530 : _SA_ST_SB_U<1c> => NOT REPLACE
531 :
532 : SGROUP,ACTIVE vs. SGROUP,* is not handled here!
533 :
534 : released:
535 : _SR_UA_SI<1c> => REPLACE
536 : _SR_UA_DI<1c> => REPLACE
537 : _SR_UT_SI<1c> => REPLACE
538 : _SR_UT_DI<1c> => REPLACE
539 : _SR_GA_SI<1c> => REPLACE
540 : _SR_GA_DI<1c> => REPLACE
541 : _SR_GT_SI<1c> => REPLACE
542 : _SR_GT_DI<1c> => REPLACE
543 : _SR_SA_SI<1c> => REPLACE
544 : _SR_SA_DI<1c> => REPLACE
545 : _SR_ST_SI<1c> => REPLACE
546 : _SR_ST_DI<1c> => REPLACE
547 : _SR_MA_SI<1c> => REPLACE
548 : _SR_MA_DI<1c> => REPLACE
549 : _SR_MT_SI<1c> => REPLACE
550 : _SR_MT_DI<1c> => REPLACE
551 : */
552 54 : static enum _R_ACTION replace_sgroup_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
553 : {
554 54 : if (!R_IS_ACTIVE(r1)) {
555 : /* REPLACE */
556 26 : return R_DO_REPLACE;
557 : }
558 :
559 28 : if (!R_IS_SGROUP(r2) || !R_IS_ACTIVE(r2)) {
560 : /* NOT REPLACE, but PROPAGATE */
561 16 : return R_DO_PROPAGATE;
562 : }
563 :
564 12 : if (r_1_is_same_as_2_address_list(r1, r2, true)) {
565 : /*
566 : * as we're the old owner and the addresses and their
567 : * owners are identical
568 : */
569 0 : return R_NOT_REPLACE;
570 : }
571 :
572 : /* not handled here: MERGE */
573 12 : return R_DO_SGROUP_MERGE;
574 : }
575 :
576 : /*
577 : active:
578 : _MA_UA_SI_U<00> => REPLACE
579 : _MA_UA_DI_P<00> => NOT REPLACE
580 : _MA_UA_DI_O<00> => NOT REPLACE
581 : _MA_UA_DI_N<00> => REPLACE
582 : _MA_UT_SI_U<00> => NOT REPLACE
583 : _MA_UT_DI_U<00> => NOT REPLACE
584 : _MA_GA_SI_R<00> => REPLACE
585 : _MA_GA_DI_R<00> => REPLACE
586 : _MA_GT_SI_U<00> => NOT REPLACE
587 : _MA_GT_DI_U<00> => NOT REPLACE
588 : _MA_SA_SI_R<00> => REPLACE
589 : _MA_SA_DI_R<00> => REPLACE
590 : _MA_ST_SI_U<00> => NOT REPLACE
591 : _MA_ST_DI_U<00> => NOT REPLACE
592 : _MA_MA_SI_U<00> => REPLACE
593 : _MA_MA_SP_U<00> => REPLACE
594 : _MA_MA_DI_P<00> => NOT REPLACE
595 : _MA_MA_DI_O<00> => NOT REPLACE
596 : _MA_MA_DI_N<00> => REPLACE
597 : _MA_MT_SI_U<00> => NOT REPLACE
598 : _MA_MT_DI_U<00> => NOT REPLACE
599 : Test Replica vs. owned active: some more MHOMED combinations
600 : _MA_MA_SP_U<00> => REPLACE
601 : _MA_MA_SM_U<00> => REPLACE
602 : _MA_MA_SB_P<00> => MHOMED_MERGE
603 : _MA_MA_SB_A<00> => MHOMED_MERGE
604 : _MA_MA_SB_PRA<00> => NOT REPLACE
605 : _MA_MA_SB_O<00> => NOT REPLACE
606 : _MA_MA_SB_N<00> => REPLACE
607 : Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
608 : _MA_UA_SB_P<00> => MHOMED_MERGE
609 :
610 : released:
611 : _MR_UA_SI<00> => REPLACE
612 : _MR_UA_DI<00> => REPLACE
613 : _MR_UT_SI<00> => REPLACE
614 : _MR_UT_DI<00> => REPLACE
615 : _MR_GA_SI<00> => REPLACE
616 : _MR_GA_DI<00> => REPLACE
617 : _MR_GT_SI<00> => REPLACE
618 : _MR_GT_DI<00> => REPLACE
619 : _MR_SA_SI<00> => REPLACE
620 : _MR_SA_DI<00> => REPLACE
621 : _MR_ST_SI<00> => REPLACE
622 : _MR_ST_DI<00> => REPLACE
623 : _MR_MA_SI<00> => REPLACE
624 : _MR_MA_DI<00> => REPLACE
625 : _MR_MT_SI<00> => REPLACE
626 : _MR_MT_DI<00> => REPLACE
627 : */
628 45 : static enum _R_ACTION replace_mhomed_owned_vs_X_replica(struct winsdb_record *r1, struct wrepl_name *r2)
629 : {
630 45 : if (!R_IS_ACTIVE(r1)) {
631 : /* REPLACE */
632 16 : return R_DO_REPLACE;
633 : }
634 :
635 29 : if (!R_IS_ACTIVE(r2)) {
636 : /* NOT REPLACE, but PROPAGATE */
637 8 : return R_DO_PROPAGATE;
638 : }
639 :
640 21 : if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
641 : /* REPLACE and send a release demand to the old name owner */
642 4 : return R_DO_RELEASE_DEMAND;
643 : }
644 :
645 : /*
646 : * here we only have mhomed,active,owned vs.
647 : * is unique,active,replica or mhomed,active,replica
648 : */
649 :
650 17 : if (r_1_is_subset_of_2_address_list(r1, r2, false)) {
651 : /*
652 : * if r1 has a subset(or same) of the addresses of r2
653 : * <=>
654 : * if r2 has a superset(or same) of the addresses of r1
655 : *
656 : * then replace the record
657 : */
658 5 : return R_DO_REPLACE;
659 : }
660 :
661 : /*
662 : * in any other case, we need to do
663 : * a name request to the old name holder
664 : * to see if it's still there...
665 : */
666 12 : return R_DO_CHALLENGE;
667 : }
668 :
669 13 : static NTSTATUS r_do_add(struct wreplsrv_partner *partner,
670 : TALLOC_CTX *mem_ctx,
671 : struct wrepl_wins_owner *owner,
672 : struct wrepl_name *replica)
673 : {
674 0 : struct winsdb_record *rec;
675 0 : uint32_t i;
676 0 : uint8_t ret;
677 :
678 13 : rec = talloc(mem_ctx, struct winsdb_record);
679 13 : NT_STATUS_HAVE_NO_MEMORY(rec);
680 :
681 13 : rec->name = &replica->name;
682 13 : rec->type = replica->type;
683 13 : rec->state = replica->state;
684 13 : rec->node = replica->node;
685 13 : rec->is_static = replica->is_static;
686 13 : rec->expire_time= time(NULL) + partner->service->config.verify_interval;
687 13 : rec->version = replica->version_id;
688 13 : rec->wins_owner = replica->owner;
689 13 : rec->addresses = winsdb_addr_list_make(rec);
690 13 : NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
691 13 : rec->registered_by = NULL;
692 :
693 26 : for (i=0; i < replica->num_addresses; i++) {
694 : /* TODO: find out if rec->expire_time is correct here */
695 26 : rec->addresses = winsdb_addr_list_add(partner->service->wins_db,
696 : rec, rec->addresses,
697 13 : replica->addresses[i].address,
698 13 : replica->addresses[i].owner,
699 : rec->expire_time,
700 : false);
701 13 : NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
702 : }
703 :
704 13 : ret = winsdb_add(partner->service->wins_db, rec, 0);
705 13 : if (ret != NBT_RCODE_OK) {
706 0 : DEBUG(0,("Failed to add record %s: %u\n",
707 : nbt_name_string(mem_ctx, &replica->name), ret));
708 0 : return NT_STATUS_FOOBAR;
709 : }
710 :
711 13 : DEBUG(4,("added record %s\n",
712 : nbt_name_string(mem_ctx, &replica->name)));
713 :
714 13 : return NT_STATUS_OK;
715 : }
716 :
717 526 : static NTSTATUS r_do_replace(struct wreplsrv_partner *partner,
718 : TALLOC_CTX *mem_ctx,
719 : struct winsdb_record *rec,
720 : struct wrepl_wins_owner *owner,
721 : struct wrepl_name *replica)
722 : {
723 0 : uint32_t i;
724 0 : uint8_t ret;
725 :
726 526 : rec->name = &replica->name;
727 526 : rec->type = replica->type;
728 526 : rec->state = replica->state;
729 526 : rec->node = replica->node;
730 526 : rec->is_static = replica->is_static;
731 526 : rec->expire_time= time(NULL) + partner->service->config.verify_interval;
732 526 : rec->version = replica->version_id;
733 526 : rec->wins_owner = replica->owner;
734 526 : rec->addresses = winsdb_addr_list_make(rec);
735 526 : NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
736 526 : rec->registered_by = NULL;
737 :
738 1145 : for (i=0; i < replica->num_addresses; i++) {
739 : /* TODO: find out if rec->expire_time is correct here */
740 1238 : rec->addresses = winsdb_addr_list_add(partner->service->wins_db,
741 : rec, rec->addresses,
742 619 : replica->addresses[i].address,
743 619 : replica->addresses[i].owner,
744 : rec->expire_time,
745 : false);
746 619 : NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
747 : }
748 :
749 526 : ret = winsdb_modify(partner->service->wins_db, rec, 0);
750 526 : if (ret != NBT_RCODE_OK) {
751 0 : DEBUG(0,("Failed to replace record %s: %u\n",
752 : nbt_name_string(mem_ctx, &replica->name), ret));
753 0 : return NT_STATUS_FOOBAR;
754 : }
755 :
756 526 : DEBUG(4,("replaced record %s\n",
757 : nbt_name_string(mem_ctx, &replica->name)));
758 :
759 526 : return NT_STATUS_OK;
760 : }
761 :
762 48 : static NTSTATUS r_not_replace(struct wreplsrv_partner *partner,
763 : TALLOC_CTX *mem_ctx,
764 : struct winsdb_record *rec,
765 : struct wrepl_wins_owner *owner,
766 : struct wrepl_name *replica)
767 : {
768 48 : DEBUG(4,("not replace record %s\n",
769 : nbt_name_string(mem_ctx, &replica->name)));
770 48 : return NT_STATUS_OK;
771 : }
772 :
773 58 : static NTSTATUS r_do_propagate(struct wreplsrv_partner *partner,
774 : TALLOC_CTX *mem_ctx,
775 : struct winsdb_record *rec,
776 : struct wrepl_wins_owner *owner,
777 : struct wrepl_name *replica)
778 : {
779 0 : uint8_t ret;
780 0 : uint32_t modify_flags;
781 :
782 : /*
783 : * allocate a new version id for the record to that it'll be replicated
784 : */
785 58 : modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
786 :
787 58 : ret = winsdb_modify(partner->service->wins_db, rec, modify_flags);
788 58 : if (ret != NBT_RCODE_OK) {
789 0 : DEBUG(0,("Failed to replace record %s: %u\n",
790 : nbt_name_string(mem_ctx, &replica->name), ret));
791 0 : return NT_STATUS_FOOBAR;
792 : }
793 :
794 58 : DEBUG(4,("propagated record %s\n",
795 : nbt_name_string(mem_ctx, &replica->name)));
796 :
797 58 : return NT_STATUS_OK;
798 : }
799 :
800 : /*
801 : Test Replica vs. owned active: some more MHOMED combinations
802 : _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
803 : _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
804 : _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
805 : _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
806 : _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
807 : _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
808 : _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
809 : Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
810 : _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
811 : _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
812 : _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
813 : _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
814 : */
815 5 : static NTSTATUS r_do_mhomed_merge(struct wreplsrv_partner *partner,
816 : TALLOC_CTX *mem_ctx,
817 : struct winsdb_record *rec,
818 : struct wrepl_wins_owner *owner,
819 : struct wrepl_name *replica)
820 : {
821 0 : struct winsdb_record *merge;
822 0 : uint32_t i,j;
823 0 : uint8_t ret;
824 0 : size_t len;
825 :
826 5 : merge = talloc(mem_ctx, struct winsdb_record);
827 5 : NT_STATUS_HAVE_NO_MEMORY(merge);
828 :
829 5 : merge->name = &replica->name;
830 5 : merge->type = WREPL_TYPE_MHOMED;
831 5 : merge->state = replica->state;
832 5 : merge->node = replica->node;
833 5 : merge->is_static = replica->is_static;
834 5 : merge->expire_time = time(NULL) + partner->service->config.verify_interval;
835 5 : merge->version = replica->version_id;
836 5 : merge->wins_owner = replica->owner;
837 5 : merge->addresses = winsdb_addr_list_make(merge);
838 5 : NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
839 5 : merge->registered_by = NULL;
840 :
841 10 : for (i=0; i < replica->num_addresses; i++) {
842 10 : merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
843 : merge, merge->addresses,
844 5 : replica->addresses[i].address,
845 5 : replica->addresses[i].owner,
846 : merge->expire_time,
847 : false);
848 5 : NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
849 : }
850 :
851 5 : len = winsdb_addr_list_length(rec->addresses);
852 :
853 13 : for (i=0; i < len; i++) {
854 8 : bool found = false;
855 13 : for (j=0; j < replica->num_addresses; j++) {
856 8 : if (strcmp(replica->addresses[j].address, rec->addresses[i]->address) == 0) {
857 3 : found = true;
858 3 : break;
859 : }
860 : }
861 8 : if (found) continue;
862 :
863 10 : merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
864 : merge, merge->addresses,
865 5 : rec->addresses[i]->address,
866 5 : rec->addresses[i]->wins_owner,
867 5 : rec->addresses[i]->expire_time,
868 : false);
869 5 : NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
870 : }
871 :
872 5 : ret = winsdb_modify(partner->service->wins_db, merge, 0);
873 5 : if (ret != NBT_RCODE_OK) {
874 0 : DEBUG(0,("Failed to modify mhomed merge record %s: %u\n",
875 : nbt_name_string(mem_ctx, &replica->name), ret));
876 0 : return NT_STATUS_FOOBAR;
877 : }
878 :
879 5 : DEBUG(4,("mhomed merge record %s\n",
880 : nbt_name_string(mem_ctx, &replica->name)));
881 :
882 5 : return NT_STATUS_OK;
883 : }
884 :
885 : struct r_do_challenge_state {
886 : struct dcerpc_binding_handle *irpc_handle;
887 : struct wreplsrv_partner *partner;
888 : struct winsdb_record *rec;
889 : struct wrepl_wins_owner owner;
890 : struct wrepl_name replica;
891 : struct nbtd_proxy_wins_challenge r;
892 : struct nbtd_proxy_wins_release_demand dr;
893 : };
894 :
895 2 : static void r_do_late_release_demand_handler(struct tevent_req *subreq)
896 : {
897 0 : NTSTATUS status;
898 0 : struct r_do_challenge_state *state =
899 2 : tevent_req_callback_data(subreq,
900 : struct r_do_challenge_state);
901 :
902 2 : status = dcerpc_nbtd_proxy_wins_release_demand_r_recv(subreq, state);
903 2 : TALLOC_FREE(subreq);
904 :
905 : /* don't care about the result */
906 0 : (void)status;
907 2 : talloc_free(state);
908 2 : }
909 :
910 2 : static NTSTATUS r_do_late_release_demand(struct r_do_challenge_state *state)
911 : {
912 0 : struct tevent_req *subreq;
913 0 : uint32_t i;
914 :
915 2 : DEBUG(4,("late release demand record %s\n",
916 : nbt_name_string(state, &state->replica.name)));
917 :
918 2 : state->dr.in.name = state->replica.name;
919 2 : state->dr.in.num_addrs = state->r.out.num_addrs;
920 2 : state->dr.in.addrs = talloc_array(state,
921 : struct nbtd_proxy_wins_addr,
922 : state->dr.in.num_addrs);
923 2 : NT_STATUS_HAVE_NO_MEMORY(state->dr.in.addrs);
924 : /* TODO: fix pidl to handle inline ipv4address arrays */
925 4 : for (i=0; i < state->dr.in.num_addrs; i++) {
926 2 : state->dr.in.addrs[i].addr = state->r.out.addrs[i].addr;
927 : }
928 :
929 2 : subreq = dcerpc_nbtd_proxy_wins_release_demand_r_send(state,
930 2 : state->partner->service->task->event_ctx,
931 : state->irpc_handle,
932 : &state->dr);
933 2 : NT_STATUS_HAVE_NO_MEMORY(subreq);
934 :
935 2 : tevent_req_set_callback(subreq, r_do_late_release_demand_handler, state);
936 :
937 2 : return NT_STATUS_OK;
938 : }
939 :
940 : /*
941 : Test Replica vs. owned active: some more MHOMED combinations
942 : _MA_MA_SP_U<00>: C:MHOMED vs. B:ALL => B:ALL => REPLACE
943 : _MA_MA_SM_U<00>: C:MHOMED vs. B:MHOMED => B:MHOMED => REPLACE
944 : _MA_MA_SB_P<00>: C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
945 : _MA_MA_SB_A<00>: C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED => MHOMED_MERGE
946 : _MA_MA_SB_PRA<00>: C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED => NOT REPLACE
947 : _MA_MA_SB_O<00>: C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED => NOT REPLACE
948 : _MA_MA_SB_N<00>: C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST => REPLACE
949 : Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
950 : _MA_UA_SB_P<00>: C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED => MHOMED_MERGE
951 : _UA_UA_DI_PRA<00>: C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST => NOT REPLACE
952 : _UA_UA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
953 : _UA_MA_DI_A<00>: C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED => MHOMED_MERGE
954 : */
955 21 : static void r_do_challenge_handler(struct tevent_req *subreq)
956 : {
957 0 : NTSTATUS status;
958 0 : struct r_do_challenge_state *state =
959 21 : tevent_req_callback_data(subreq,
960 : struct r_do_challenge_state);
961 21 : bool old_is_subset = false;
962 21 : bool new_is_subset = false;
963 21 : bool found = false;
964 0 : uint32_t i,j;
965 0 : uint32_t num_rec_addrs;
966 :
967 21 : status = dcerpc_nbtd_proxy_wins_challenge_r_recv(subreq, state);
968 21 : TALLOC_FREE(subreq);
969 :
970 21 : DEBUG(4,("r_do_challenge_handler: %s: %s\n",
971 : nbt_name_string(state, &state->replica.name), nt_errstr(status)));
972 :
973 21 : if (NT_STATUS_EQUAL(NT_STATUS_IO_TIMEOUT, status) ||
974 21 : NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
975 5 : r_do_replace(state->partner, state, state->rec, &state->owner, &state->replica);
976 5 : talloc_free(state);
977 5 : return;
978 : }
979 :
980 23 : for (i=0; i < state->replica.num_addresses; i++) {
981 16 : found = false;
982 16 : new_is_subset = true;
983 32 : for (j=0; j < state->r.out.num_addrs; j++) {
984 23 : if (strcmp(state->replica.addresses[i].address, state->r.out.addrs[j].addr) == 0) {
985 7 : found = true;
986 7 : break;
987 : }
988 : }
989 16 : if (found) continue;
990 :
991 9 : new_is_subset = false;
992 9 : break;
993 : }
994 :
995 16 : if (!new_is_subset) {
996 9 : r_not_replace(state->partner, state, state->rec, &state->owner, &state->replica);
997 9 : talloc_free(state);
998 9 : return;
999 : }
1000 :
1001 7 : num_rec_addrs = winsdb_addr_list_length(state->rec->addresses);
1002 16 : for (i=0; i < num_rec_addrs; i++) {
1003 11 : found = false;
1004 11 : old_is_subset = true;
1005 16 : for (j=0; j < state->r.out.num_addrs; j++) {
1006 14 : if (strcmp(state->rec->addresses[i]->address, state->r.out.addrs[j].addr) == 0) {
1007 9 : found = true;
1008 9 : break;
1009 : }
1010 : }
1011 11 : if (found) continue;
1012 :
1013 2 : old_is_subset = false;
1014 2 : break;
1015 : }
1016 :
1017 7 : if (!old_is_subset) {
1018 2 : status = r_do_late_release_demand(state);
1019 : /*
1020 : * only free state on error, because we pass it down,
1021 : * and r_do_late_release_demand() will free it
1022 : */
1023 2 : if (!NT_STATUS_IS_OK(status)) {
1024 0 : talloc_free(state);
1025 : }
1026 2 : return;
1027 : }
1028 :
1029 5 : r_do_mhomed_merge(state->partner, state, state->rec, &state->owner, &state->replica);
1030 5 : talloc_free(state);
1031 : }
1032 :
1033 21 : static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner,
1034 : TALLOC_CTX *mem_ctx,
1035 : struct winsdb_record *rec,
1036 : struct wrepl_wins_owner *owner,
1037 : struct wrepl_name *replica)
1038 : {
1039 0 : struct r_do_challenge_state *state;
1040 0 : struct tevent_req *subreq;
1041 0 : const char **addrs;
1042 0 : uint32_t i;
1043 :
1044 21 : DEBUG(4,("challenge record %s\n",
1045 : nbt_name_string(mem_ctx, &replica->name)));
1046 :
1047 21 : state = talloc_zero(mem_ctx, struct r_do_challenge_state);
1048 21 : NT_STATUS_HAVE_NO_MEMORY(state);
1049 21 : state->partner = partner;
1050 21 : state->rec = talloc_steal(state, rec);
1051 21 : state->owner = *owner;
1052 21 : state->replica = *replica;
1053 : /* some stuff to have valid memory pointers in the async complete function */
1054 21 : state->replica.name = *state->rec->name;
1055 21 : talloc_steal(state, replica->owner);
1056 21 : talloc_steal(state, replica->addresses);
1057 :
1058 42 : state->irpc_handle = irpc_binding_handle_by_name(state,
1059 21 : partner->service->task->msg_ctx,
1060 : "nbt_server",
1061 : &ndr_table_irpc);
1062 21 : if (state->irpc_handle == NULL) {
1063 0 : return NT_STATUS_INTERNAL_ERROR;
1064 : }
1065 :
1066 21 : state->r.in.name = *rec->name;
1067 21 : state->r.in.num_addrs = winsdb_addr_list_length(rec->addresses);
1068 21 : state->r.in.addrs = talloc_array(state, struct nbtd_proxy_wins_addr, state->r.in.num_addrs);
1069 21 : NT_STATUS_HAVE_NO_MEMORY(state->r.in.addrs);
1070 : /* TODO: fix pidl to handle inline ipv4address arrays */
1071 21 : addrs = winsdb_addr_string_list(state->r.in.addrs, rec->addresses);
1072 21 : NT_STATUS_HAVE_NO_MEMORY(addrs);
1073 48 : for (i=0; i < state->r.in.num_addrs; i++) {
1074 27 : state->r.in.addrs[i].addr = addrs[i];
1075 : }
1076 :
1077 21 : subreq = dcerpc_nbtd_proxy_wins_challenge_r_send(state,
1078 21 : state->partner->service->task->event_ctx,
1079 : state->irpc_handle,
1080 : &state->r);
1081 21 : NT_STATUS_HAVE_NO_MEMORY(subreq);
1082 :
1083 21 : tevent_req_set_callback(subreq, r_do_challenge_handler, state);
1084 :
1085 21 : talloc_steal(partner, state);
1086 21 : return NT_STATUS_OK;
1087 : }
1088 :
1089 : struct r_do_release_demand_state {
1090 : struct nbtd_proxy_wins_release_demand r;
1091 : };
1092 :
1093 8 : static void r_do_release_demand_handler(struct tevent_req *subreq)
1094 : {
1095 0 : NTSTATUS status;
1096 0 : struct r_do_release_demand_state *state =
1097 8 : tevent_req_callback_data(subreq,
1098 : struct r_do_release_demand_state);
1099 :
1100 8 : status = dcerpc_nbtd_proxy_wins_release_demand_r_recv(subreq, state);
1101 8 : TALLOC_FREE(subreq);
1102 :
1103 : /* don't care about the result */
1104 0 : (void)status;
1105 8 : talloc_free(state);
1106 8 : }
1107 :
1108 8 : static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner,
1109 : TALLOC_CTX *mem_ctx,
1110 : struct winsdb_record *rec,
1111 : struct wrepl_wins_owner *owner,
1112 : struct wrepl_name *replica)
1113 : {
1114 0 : NTSTATUS status;
1115 0 : struct dcerpc_binding_handle *irpc_handle;
1116 0 : const char **addrs;
1117 0 : struct winsdb_addr **addresses;
1118 0 : struct r_do_release_demand_state *state;
1119 0 : struct tevent_req *subreq;
1120 0 : uint32_t i;
1121 :
1122 : /*
1123 : * we need to get a reference to the old addresses,
1124 : * as we need to send a release demand to them after replacing the record
1125 : * and r_do_replace() will modify rec->addresses
1126 : */
1127 8 : addresses = rec->addresses;
1128 :
1129 8 : status = r_do_replace(partner, mem_ctx, rec, owner, replica);
1130 8 : NT_STATUS_NOT_OK_RETURN(status);
1131 :
1132 8 : DEBUG(4,("release demand record %s\n",
1133 : nbt_name_string(mem_ctx, &replica->name)));
1134 :
1135 8 : state = talloc_zero(mem_ctx, struct r_do_release_demand_state);
1136 8 : NT_STATUS_HAVE_NO_MEMORY(state);
1137 :
1138 8 : irpc_handle = irpc_binding_handle_by_name(state,
1139 8 : partner->service->task->msg_ctx,
1140 : "nbt_server",
1141 : &ndr_table_irpc);
1142 8 : if (irpc_handle == NULL) {
1143 0 : return NT_STATUS_INTERNAL_ERROR;
1144 : }
1145 :
1146 8 : state->r.in.name = *rec->name;
1147 8 : state->r.in.num_addrs = winsdb_addr_list_length(addresses);
1148 8 : state->r.in.addrs = talloc_array(state, struct nbtd_proxy_wins_addr,
1149 : state->r.in.num_addrs);
1150 8 : NT_STATUS_HAVE_NO_MEMORY(state->r.in.addrs);
1151 : /* TODO: fix pidl to handle inline ipv4address arrays */
1152 8 : addrs = winsdb_addr_string_list(state->r.in.addrs, addresses);
1153 8 : NT_STATUS_HAVE_NO_MEMORY(addrs);
1154 16 : for (i=0; i < state->r.in.num_addrs; i++) {
1155 8 : state->r.in.addrs[i].addr = addrs[i];
1156 : }
1157 :
1158 8 : subreq = dcerpc_nbtd_proxy_wins_release_demand_r_send(state,
1159 8 : partner->service->task->event_ctx,
1160 : irpc_handle,
1161 : &state->r);
1162 8 : NT_STATUS_HAVE_NO_MEMORY(subreq);
1163 :
1164 8 : tevent_req_set_callback(subreq, r_do_release_demand_handler, state);
1165 :
1166 8 : talloc_steal(partner, state);
1167 8 : return NT_STATUS_OK;
1168 : }
1169 :
1170 : /*
1171 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACE
1172 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACE
1173 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACE
1174 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACE
1175 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACE
1176 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACE
1177 :
1178 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGE
1179 : 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
1180 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGE
1181 : 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
1182 : 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
1183 : SGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGE
1184 :
1185 : Test Replica vs. owned active: SGROUP vs. SGROUP tests
1186 : _SA_SA_DI_U<1c> => SGROUP_MERGE
1187 : _SA_SA_SI_U<1c> => SGROUP_MERGE
1188 : _SA_SA_SP_U<1c> => SGROUP_MERGE
1189 : _SA_SA_SB_U<1c> => SGROUP_MERGE
1190 : */
1191 23 : static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner,
1192 : TALLOC_CTX *mem_ctx,
1193 : struct winsdb_record *rec,
1194 : struct wrepl_wins_owner *owner,
1195 : struct wrepl_name *replica)
1196 : {
1197 0 : struct winsdb_record *merge;
1198 23 : uint32_t modify_flags = 0;
1199 0 : uint32_t i,j;
1200 0 : uint8_t ret;
1201 0 : size_t len;
1202 23 : bool changed_old_addrs = false;
1203 23 : bool skip_replica_owned_by_us = false;
1204 23 : bool become_owner = true;
1205 23 : bool propagate = lpcfg_parm_bool(partner->service->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false);
1206 23 : const char *local_owner = partner->service->wins_db->local_owner;
1207 :
1208 23 : merge = talloc(mem_ctx, struct winsdb_record);
1209 23 : NT_STATUS_HAVE_NO_MEMORY(merge);
1210 :
1211 23 : merge->name = &replica->name;
1212 23 : merge->type = replica->type;
1213 23 : merge->state = replica->state;
1214 23 : merge->node = replica->node;
1215 23 : merge->is_static = replica->is_static;
1216 23 : merge->expire_time = time(NULL) + partner->service->config.verify_interval;
1217 23 : merge->version = replica->version_id;
1218 23 : merge->wins_owner = replica->owner;
1219 23 : merge->addresses = winsdb_addr_list_make(merge);
1220 23 : NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
1221 23 : merge->registered_by = NULL;
1222 :
1223 23 : len = winsdb_addr_list_length(rec->addresses);
1224 :
1225 91 : for (i=0; i < len; i++) {
1226 68 : bool found = false;
1227 :
1228 109 : for (j=0; j < replica->num_addresses; j++) {
1229 50 : if (strcmp(rec->addresses[i]->address, replica->addresses[j].address) != 0) {
1230 41 : continue;
1231 : }
1232 :
1233 9 : found = true;
1234 :
1235 9 : if (strcmp(rec->addresses[i]->wins_owner, replica->addresses[j].owner) != 0) {
1236 7 : changed_old_addrs = true;
1237 7 : break;
1238 : }
1239 2 : break;
1240 : }
1241 :
1242 : /*
1243 : * if the address isn't in the replica and is owned by replicas owner,
1244 : * it won't be added to the merged record
1245 : */
1246 68 : if (!found && strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) {
1247 34 : changed_old_addrs = true;
1248 34 : continue;
1249 : }
1250 :
1251 : /*
1252 : * add the address to the merge result, with the old owner and expire_time,
1253 : * the owner and expire_time will be overwritten later if the address is
1254 : * in the replica too
1255 : */
1256 68 : merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
1257 : merge, merge->addresses,
1258 34 : rec->addresses[i]->address,
1259 34 : rec->addresses[i]->wins_owner,
1260 34 : rec->addresses[i]->expire_time,
1261 : false);
1262 34 : NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
1263 : }
1264 :
1265 48 : for (i=0; i < replica->num_addresses; i++) {
1266 25 : if (propagate &&
1267 0 : strcmp(replica->addresses[i].owner, local_owner) == 0) {
1268 0 : const struct winsdb_addr *a;
1269 :
1270 : /*
1271 : * NOTE: this is different to the windows behavior
1272 : * and off by default, but it better propagated
1273 : * name releases
1274 : */
1275 0 : a = winsdb_addr_list_check(merge->addresses,
1276 0 : replica->addresses[i].address);
1277 0 : if (!a) {
1278 : /* don't add addresses owned by us */
1279 0 : skip_replica_owned_by_us = true;
1280 : }
1281 0 : continue;
1282 : }
1283 50 : merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
1284 : merge, merge->addresses,
1285 25 : replica->addresses[i].address,
1286 25 : replica->addresses[i].owner,
1287 : merge->expire_time,
1288 : false);
1289 25 : NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
1290 : }
1291 :
1292 : /* we the old addresses change changed we don't become the owner */
1293 23 : if (changed_old_addrs) {
1294 19 : become_owner = false;
1295 : }
1296 :
1297 : /*
1298 : * when we notice another server believes an address
1299 : * is owned by us and that's not the case
1300 : * we propagate the result
1301 : */
1302 23 : if (skip_replica_owned_by_us) {
1303 0 : become_owner = true;
1304 : }
1305 :
1306 : /* if we're the owner of the old record, we'll be the owner of the new one too */
1307 23 : if (strcmp(rec->wins_owner, local_owner)==0) {
1308 12 : become_owner = true;
1309 : }
1310 :
1311 : /*
1312 : * if the result has no addresses we take the ownership
1313 : */
1314 23 : len = winsdb_addr_list_length(merge->addresses);
1315 23 : if (len == 0) {
1316 8 : become_owner = true;
1317 : }
1318 :
1319 : /*
1320 : * if addresses of the old record will be changed the replica owner
1321 : * will be owner of the merge result, otherwise we take the ownership
1322 : */
1323 23 : if (become_owner) {
1324 18 : time_t lh = 0;
1325 :
1326 18 : modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
1327 :
1328 : /*
1329 : * if we're the owner, the expire time becomes the highest
1330 : * expire time of owned addresses
1331 : */
1332 18 : len = winsdb_addr_list_length(merge->addresses);
1333 :
1334 54 : for (i=0; i < len; i++) {
1335 36 : if (strcmp(merge->addresses[i]->wins_owner, local_owner)==0) {
1336 3 : lh = MAX(lh, merge->addresses[i]->expire_time);
1337 : }
1338 : }
1339 :
1340 18 : if (lh != 0) {
1341 2 : merge->expire_time = lh;
1342 : }
1343 : }
1344 :
1345 23 : ret = winsdb_modify(partner->service->wins_db, merge, modify_flags);
1346 23 : if (ret != NBT_RCODE_OK) {
1347 0 : DEBUG(0,("Failed to modify sgroup merge record %s: %u\n",
1348 : nbt_name_string(mem_ctx, &replica->name), ret));
1349 0 : return NT_STATUS_FOOBAR;
1350 : }
1351 :
1352 23 : DEBUG(4,("sgroup merge record %s\n",
1353 : nbt_name_string(mem_ctx, &replica->name)));
1354 :
1355 23 : return NT_STATUS_OK;
1356 : }
1357 :
1358 675 : static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
1359 : TALLOC_CTX *mem_ctx,
1360 : struct wrepl_wins_owner *owner,
1361 : struct wrepl_name *replica)
1362 : {
1363 0 : NTSTATUS status;
1364 675 : struct winsdb_record *rec = NULL;
1365 675 : enum _R_ACTION action = R_INVALID;
1366 675 : bool same_owner = false;
1367 675 : bool replica_vs_replica = false;
1368 675 : bool local_vs_replica = false;
1369 :
1370 675 : if (replica->name.scope) {
1371 0 : TALLOC_CTX *parent;
1372 0 : const char *scope;
1373 :
1374 : /*
1375 : * Windows 2008 truncates the scope to 237 bytes,
1376 : * so we do...
1377 : */
1378 132 : parent = talloc_parent(replica->name.scope);
1379 132 : scope = talloc_strndup(parent, replica->name.scope, 237);
1380 132 : NT_STATUS_HAVE_NO_MEMORY(scope);
1381 132 : replica->name.scope = scope;
1382 : }
1383 :
1384 675 : status = winsdb_lookup(partner->service->wins_db,
1385 675 : &replica->name, mem_ctx, &rec);
1386 675 : if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
1387 13 : return r_do_add(partner, mem_ctx, owner, replica);
1388 : }
1389 662 : NT_STATUS_NOT_OK_RETURN(status);
1390 :
1391 662 : if (strcmp(rec->wins_owner, partner->service->wins_db->local_owner)==0) {
1392 171 : local_vs_replica = true;
1393 491 : } else if (strcmp(rec->wins_owner, owner->address)==0) {
1394 350 : same_owner = true;
1395 : } else {
1396 141 : replica_vs_replica = true;
1397 : }
1398 :
1399 662 : if (rec->is_static && !same_owner) {
1400 0 : action = R_NOT_REPLACE;
1401 :
1402 : /*
1403 : * if we own the local record, then propagate it back to
1404 : * the other wins servers.
1405 : * to prevent ping-pong with other servers, we don't do this
1406 : * if the replica is static too.
1407 : *
1408 : * It seems that w2k3 doesn't do this, but I thing that's a bug
1409 : * and doing propagation helps to have consistent data on all servers
1410 : */
1411 0 : if (local_vs_replica && !replica->is_static) {
1412 0 : action = R_DO_PROPAGATE;
1413 : }
1414 662 : } else if (replica->is_static && !rec->is_static && !same_owner) {
1415 0 : action = R_DO_REPLACE;
1416 662 : } else if (same_owner) {
1417 350 : action = replace_same_owner(rec, replica);
1418 312 : } else if (replica_vs_replica) {
1419 141 : switch (rec->type) {
1420 28 : case WREPL_TYPE_UNIQUE:
1421 28 : action = replace_unique_replica_vs_X_replica(rec, replica);
1422 28 : break;
1423 25 : case WREPL_TYPE_GROUP:
1424 25 : action = replace_group_replica_vs_X_replica(rec, replica);
1425 25 : break;
1426 63 : case WREPL_TYPE_SGROUP:
1427 63 : action = replace_sgroup_replica_vs_X_replica(rec, replica);
1428 63 : break;
1429 25 : case WREPL_TYPE_MHOMED:
1430 25 : action = replace_mhomed_replica_vs_X_replica(rec, replica);
1431 25 : break;
1432 : }
1433 171 : } else if (local_vs_replica) {
1434 171 : switch (rec->type) {
1435 40 : case WREPL_TYPE_UNIQUE:
1436 40 : action = replace_unique_owned_vs_X_replica(rec, replica);
1437 40 : break;
1438 32 : case WREPL_TYPE_GROUP:
1439 32 : action = replace_group_owned_vs_X_replica(rec, replica);
1440 32 : break;
1441 54 : case WREPL_TYPE_SGROUP:
1442 54 : action = replace_sgroup_owned_vs_X_replica(rec, replica);
1443 54 : break;
1444 45 : case WREPL_TYPE_MHOMED:
1445 45 : action = replace_mhomed_owned_vs_X_replica(rec, replica);
1446 45 : break;
1447 : }
1448 : }
1449 :
1450 662 : DEBUG(4,("apply record %s: %s\n",
1451 : nbt_name_string(mem_ctx, &replica->name), _R_ACTION_enum_string(action)));
1452 :
1453 662 : switch (action) {
1454 0 : case R_INVALID: break;
1455 513 : case R_DO_REPLACE:
1456 513 : return r_do_replace(partner, mem_ctx, rec, owner, replica);
1457 39 : case R_NOT_REPLACE:
1458 39 : return r_not_replace(partner, mem_ctx, rec, owner, replica);
1459 58 : case R_DO_PROPAGATE:
1460 58 : return r_do_propagate(partner, mem_ctx, rec, owner, replica);
1461 21 : case R_DO_CHALLENGE:
1462 21 : return r_do_challenge(partner, mem_ctx, rec, owner, replica);
1463 8 : case R_DO_RELEASE_DEMAND:
1464 8 : return r_do_release_demand(partner, mem_ctx, rec, owner, replica);
1465 23 : case R_DO_SGROUP_MERGE:
1466 23 : return r_do_sgroup_merge(partner, mem_ctx, rec, owner, replica);
1467 : }
1468 :
1469 0 : return NT_STATUS_INTERNAL_ERROR;
1470 : }
1471 :
1472 675 : NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner,
1473 : struct wrepl_wins_owner *owner,
1474 : uint32_t num_names, struct wrepl_name *names)
1475 : {
1476 0 : NTSTATUS status;
1477 0 : uint32_t i;
1478 :
1479 675 : DEBUG(4,("apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
1480 : num_names, owner->address,
1481 : (long long)owner->min_version,
1482 : (long long)owner->max_version,
1483 : partner->address));
1484 :
1485 1350 : for (i=0; i < num_names; i++) {
1486 675 : TALLOC_CTX *tmp_mem = talloc_new(partner);
1487 675 : NT_STATUS_HAVE_NO_MEMORY(tmp_mem);
1488 :
1489 675 : status = wreplsrv_apply_one_record(partner, tmp_mem,
1490 675 : owner, &names[i]);
1491 675 : talloc_free(tmp_mem);
1492 675 : NT_STATUS_NOT_OK_RETURN(status);
1493 : }
1494 :
1495 675 : status = wreplsrv_add_table(partner->service,
1496 675 : partner->service,
1497 675 : &partner->service->table,
1498 : owner->address,
1499 : owner->max_version);
1500 675 : NT_STATUS_NOT_OK_RETURN(status);
1501 :
1502 675 : return NT_STATUS_OK;
1503 : }
|