r10993: - make us able to check released records, we can only do that by finding...
[abartlet/samba.git/.git] / source4 / torture / nbt / winsreplication.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    WINS replication testing
5
6    Copyright (C) Andrew Tridgell 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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "libcli/nbt/libnbt.h"
25 #include "libcli/wrepl/winsrepl.h"
26
27 #define CHECK_STATUS(status, correct) do { \
28         if (!NT_STATUS_EQUAL(status, correct)) { \
29                 printf("(%s) Incorrect status %s - should be %s\n", \
30                        __location__, nt_errstr(status), nt_errstr(correct)); \
31                 ret = False; \
32                 goto done; \
33         }} while (0)
34
35 #define CHECK_VALUE(v, correct) do { \
36         if ((v) != (correct)) { \
37                 printf("(%s) Incorrect value %s=%d - should be %d\n", \
38                        __location__, #v, v, correct); \
39                 ret = False; \
40                 goto done; \
41         }} while (0)
42
43 #define _NBT_NAME(n,t,s) {\
44         .name   = n,\
45         .type   = t,\
46         .scope  = s\
47 }
48
49 static const char *wrepl_name_type_string(enum wrepl_name_type type)
50 {
51         switch (type) {
52         case WREPL_TYPE_UNIQUE: return "UNIQUE";
53         case WREPL_TYPE_GROUP: return "GROUP";
54         case WREPL_TYPE_SGROUP: return "SGROUP";
55         case WREPL_TYPE_MHOMED: return "MHOMED";
56         }
57         return "UNKNOWN_TYPE";
58 }
59
60 static const char *wrepl_name_state_string(enum wrepl_name_state state)
61 {
62         switch (state) {
63         case WREPL_STATE_ACTIVE: return "ACTIVE";
64         case WREPL_STATE_RELEASED: return "RELEASED";
65         case WREPL_STATE_TOMBSTONE: return "TOMBSTONE";
66         case WREPL_STATE_RESERVED: return "RESERVED";
67         }
68         return "UNKNOWN_STATE";
69 }
70
71 /*
72   test how assoc_ctx's are only usable on the connection
73   they are created on.
74 */
75 static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address)
76 {
77         BOOL ret = True;
78         struct wrepl_request *req;
79         struct wrepl_socket *wrepl_socket1;
80         struct wrepl_associate associate1;
81         struct wrepl_socket *wrepl_socket2;
82         struct wrepl_associate associate2;
83         struct wrepl_pull_table pull_table;
84         struct wrepl_packet *rep_packet;
85         struct wrepl_associate_stop assoc_stop;
86         NTSTATUS status;
87
88         if (!lp_parm_bool(-1, "torture", "dangerous", False)) {
89                 printf("winsrepl: cross connection assoc_ctx usage disabled - enable dangerous tests to use\n");
90                 return True;
91         }
92
93         printf("Test if assoc_ctx is only valid on the conection it was created on\n");
94
95         wrepl_socket1 = wrepl_socket_init(mem_ctx, NULL);
96         wrepl_socket2 = wrepl_socket_init(mem_ctx, NULL);
97
98         printf("Setup 2 wrepl connections\n");
99         status = wrepl_connect(wrepl_socket1, NULL, address);
100         CHECK_STATUS(status, NT_STATUS_OK);
101
102         status = wrepl_connect(wrepl_socket2, NULL, address);
103         CHECK_STATUS(status, NT_STATUS_OK);
104
105         printf("Send a start association request (conn1)\n");
106         status = wrepl_associate(wrepl_socket1, &associate1);
107         CHECK_STATUS(status, NT_STATUS_OK);
108
109         printf("association context (conn1): 0x%x\n", associate1.out.assoc_ctx);
110
111         printf("Send a start association request (conn2)\n");
112         status = wrepl_associate(wrepl_socket2, &associate2);
113         CHECK_STATUS(status, NT_STATUS_OK);
114
115         printf("association context (conn2): 0x%x\n", associate2.out.assoc_ctx);
116
117         printf("Send a replication table query, with assoc 1 (conn2), the anwser should be on conn1\n");
118         pull_table.in.assoc_ctx = associate1.out.assoc_ctx;
119         req = wrepl_pull_table_send(wrepl_socket2, &pull_table);
120         req->send_only = True;
121         status = wrepl_request_recv(req, mem_ctx, &rep_packet);
122         CHECK_STATUS(status, NT_STATUS_OK);
123
124         printf("Send a association request (conn2), to make sure the last request was ignored\n");
125         status = wrepl_associate(wrepl_socket2, &associate2);
126         CHECK_STATUS(status, NT_STATUS_OK);
127
128         printf("Send a replication table query, with invalid assoc (conn1), receive answer from conn2\n");
129         pull_table.in.assoc_ctx = 0;
130         req = wrepl_pull_table_send(wrepl_socket1, &pull_table);
131         status = wrepl_request_recv(req, mem_ctx, &rep_packet);
132         CHECK_STATUS(status, NT_STATUS_OK);
133
134         printf("Send a association request (conn1), to make sure the last request was handled correct\n");
135         status = wrepl_associate(wrepl_socket1, &associate2);
136         CHECK_STATUS(status, NT_STATUS_OK);
137
138         assoc_stop.in.assoc_ctx = associate1.out.assoc_ctx;
139         assoc_stop.in.reason    = 4;
140         printf("Send a association stop request (conn1), reson: %u\n", assoc_stop.in.reason);
141         status = wrepl_associate_stop(wrepl_socket1, &assoc_stop);
142         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
143
144         assoc_stop.in.assoc_ctx = associate2.out.assoc_ctx;
145         assoc_stop.in.reason    = 0;
146         printf("Send a association stop request (conn2), reson: %u\n", assoc_stop.in.reason);
147         status = wrepl_associate_stop(wrepl_socket2, &assoc_stop);
148         CHECK_STATUS(status, NT_STATUS_OK);
149
150 done:
151         printf("Close 2 wrepl connections\n");
152         talloc_free(wrepl_socket1);
153         talloc_free(wrepl_socket2);
154         return ret;
155 }
156
157 /*
158   test if we always get back the same assoc_ctx
159 */
160 static BOOL test_assoc_ctx2(TALLOC_CTX *mem_ctx, const char *address)
161 {
162         BOOL ret = True;
163         struct wrepl_socket *wrepl_socket;
164         struct wrepl_associate associate;
165         uint32_t assoc_ctx1;
166         NTSTATUS status;
167
168         printf("Test if we always get back the same assoc_ctx\n");
169
170         wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
171         
172         printf("Setup wrepl connections\n");
173         status = wrepl_connect(wrepl_socket, NULL, address);
174         CHECK_STATUS(status, NT_STATUS_OK);
175
176
177         printf("Send 1st start association request\n");
178         status = wrepl_associate(wrepl_socket, &associate);
179         CHECK_STATUS(status, NT_STATUS_OK);
180         assoc_ctx1 = associate.out.assoc_ctx;
181         printf("1st association context: 0x%x\n", associate.out.assoc_ctx);
182
183         printf("Send 2nd start association request\n");
184         status = wrepl_associate(wrepl_socket, &associate);
185         CHECK_VALUE(associate.out.assoc_ctx, assoc_ctx1);
186         CHECK_STATUS(status, NT_STATUS_OK);
187         printf("2nd association context: 0x%x\n", associate.out.assoc_ctx);
188
189         printf("Send 3rd start association request\n");
190         status = wrepl_associate(wrepl_socket, &associate);
191         CHECK_VALUE(associate.out.assoc_ctx, assoc_ctx1);
192         CHECK_STATUS(status, NT_STATUS_OK);
193         printf("3rd association context: 0x%x\n", associate.out.assoc_ctx);
194
195 done:
196         printf("Close wrepl connections\n");
197         talloc_free(wrepl_socket);
198         return ret;
199 }
200
201
202 /*
203   display a replication entry
204 */
205 static void display_entry(TALLOC_CTX *mem_ctx, struct wrepl_name *name)
206 {
207         int i;
208
209         printf("%s\n", nbt_name_string(mem_ctx, &name->name));
210         printf("\tTYPE:%u STATE:%u NODE:%u STATIC:%u VERSION_ID: %llu\n",
211                 name->type, name->state, name->node, name->is_static, name->version_id);
212         printf("\tRAW_FLAGS: 0x%08X OWNER: %-15s\n",
213                 name->raw_flags, name->owner);
214         for (i=0;i<name->num_addresses;i++) {
215                 printf("\tADDR: %-15s OWNER: %-15s\n", 
216                         name->addresses[i].address, name->addresses[i].owner);
217         }
218 }
219
220 /*
221   test a full replication dump from a WINS server
222 */
223 static BOOL test_wins_replication(TALLOC_CTX *mem_ctx, const char *address)
224 {
225         BOOL ret = True;
226         struct wrepl_socket *wrepl_socket;
227         NTSTATUS status;
228         int i, j;
229         struct wrepl_associate associate;
230         struct wrepl_pull_table pull_table;
231         struct wrepl_pull_names pull_names;
232
233         printf("Test one pull replication cycle\n");
234
235         wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
236         
237         printf("Setup wrepl connections\n");
238         status = wrepl_connect(wrepl_socket, NULL, address);
239         CHECK_STATUS(status, NT_STATUS_OK);
240
241         printf("Send a start association request\n");
242
243         status = wrepl_associate(wrepl_socket, &associate);
244         CHECK_STATUS(status, NT_STATUS_OK);
245
246         printf("association context: 0x%x\n", associate.out.assoc_ctx);
247
248         printf("Send a replication table query\n");
249         pull_table.in.assoc_ctx = associate.out.assoc_ctx;
250
251         status = wrepl_pull_table(wrepl_socket, mem_ctx, &pull_table);
252         if (NT_STATUS_EQUAL(NT_STATUS_NETWORK_ACCESS_DENIED,status)) {
253                 struct wrepl_packet packet;
254                 struct wrepl_request *req;
255
256                 ZERO_STRUCT(packet);
257                 packet.opcode                      = WREPL_OPCODE_BITS;
258                 packet.assoc_ctx                   = associate.out.assoc_ctx;
259                 packet.mess_type                   = WREPL_STOP_ASSOCIATION;
260                 packet.message.stop.reason         = 0;
261
262                 req = wrepl_request_send(wrepl_socket, &packet);
263                 talloc_free(req);
264
265                 printf("failed - We are not a valid pull partner for the server\n");
266                 ret = False;
267                 goto done;
268         }
269         CHECK_STATUS(status, NT_STATUS_OK);
270
271         printf("Found %d replication partners\n", pull_table.out.num_partners);
272
273         for (i=0;i<pull_table.out.num_partners;i++) {
274                 struct wrepl_wins_owner *partner = &pull_table.out.partners[i];
275                 printf("%s   max_version=%6llu   min_version=%6llu type=%d\n",
276                        partner->address, 
277                        partner->max_version, 
278                        partner->min_version, 
279                        partner->type);
280
281                 pull_names.in.assoc_ctx = associate.out.assoc_ctx;
282                 pull_names.in.partner = *partner;
283                 
284                 status = wrepl_pull_names(wrepl_socket, mem_ctx, &pull_names);
285                 CHECK_STATUS(status, NT_STATUS_OK);
286
287                 printf("Received %d names\n", pull_names.out.num_names);
288
289                 for (j=0;j<pull_names.out.num_names;j++) {
290                         display_entry(mem_ctx, &pull_names.out.names[j]);
291                 }
292         }
293
294 done:
295         printf("Close wrepl connections\n");
296         talloc_free(wrepl_socket);
297         return ret;
298 }
299
300 struct test_wrepl_conflict_conn {
301         const char *address;
302         struct wrepl_socket *pull;
303         uint32_t pull_assoc;
304
305 #define TEST_OWNER_A_ADDRESS "127.65.65.1"
306 #define TEST_ADDRESS_A_PREFIX "127.0.65"
307 #define TEST_OWNER_B_ADDRESS "127.66.66.1"
308 #define TEST_ADDRESS_B_PREFIX "127.0.66"
309
310         struct wrepl_wins_owner a, b;
311 };
312
313 static const struct wrepl_ip addresses_A_1[] = {
314         {
315         .owner  = TEST_OWNER_A_ADDRESS,
316         .ip     = TEST_ADDRESS_A_PREFIX".1"
317         }
318 };
319 static const struct wrepl_ip addresses_A_2[] = {
320         {
321         .owner  = TEST_OWNER_A_ADDRESS,
322         .ip     = TEST_ADDRESS_A_PREFIX".2"
323         }
324 };
325
326 static const struct wrepl_ip addresses_B_1[] = {
327         {
328         .owner  = TEST_OWNER_B_ADDRESS,
329         .ip     = TEST_ADDRESS_B_PREFIX".1"
330         }
331 };
332 static const struct wrepl_ip addresses_B_2[] = {
333         {
334         .owner  = TEST_OWNER_B_ADDRESS,
335         .ip     = TEST_ADDRESS_B_PREFIX".2"
336         }
337 };
338
339 static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem_ctx,
340                                                                  const char *address)
341 {
342         struct test_wrepl_conflict_conn *ctx;
343         struct wrepl_associate associate;
344         struct wrepl_pull_table pull_table;
345         NTSTATUS status;
346         uint32_t i;
347
348         ctx = talloc_zero(mem_ctx, struct test_wrepl_conflict_conn);
349         if (!ctx) return NULL;
350
351         ctx->address    = address;
352         ctx->pull       = wrepl_socket_init(ctx, NULL);
353         if (!ctx->pull) return NULL;
354
355         printf("Setup wrepl conflict pull connection\n");
356         status = wrepl_connect(ctx->pull, NULL, ctx->address);
357         if (!NT_STATUS_IS_OK(status)) return NULL;
358
359         status = wrepl_associate(ctx->pull, &associate);
360         if (!NT_STATUS_IS_OK(status)) return NULL;
361
362         ctx->pull_assoc = associate.out.assoc_ctx;
363
364         ctx->a.address          = TEST_OWNER_A_ADDRESS;
365         ctx->a.max_version      = 0;
366         ctx->a.min_version      = 0;
367         ctx->a.type             = 1;
368
369         ctx->b.address          = TEST_OWNER_B_ADDRESS;
370         ctx->b.max_version      = 0;
371         ctx->b.min_version      = 0;
372         ctx->b.type             = 1;
373
374         pull_table.in.assoc_ctx = ctx->pull_assoc;
375         status = wrepl_pull_table(ctx->pull, ctx->pull, &pull_table);
376         if (!NT_STATUS_IS_OK(status)) return NULL;
377
378         for (i=0; i < pull_table.out.num_partners; i++) {
379                 if (strcmp(TEST_OWNER_A_ADDRESS,pull_table.out.partners[i].address)==0) {
380                         ctx->a.max_version      = pull_table.out.partners[i].max_version;
381                         ctx->a.min_version      = pull_table.out.partners[i].min_version;
382                 }
383                 if (strcmp(TEST_OWNER_B_ADDRESS,pull_table.out.partners[i].address)==0) {
384                         ctx->b.max_version      = pull_table.out.partners[i].max_version;
385                         ctx->b.min_version      = pull_table.out.partners[i].min_version;               
386                 }
387         }
388
389         talloc_free(pull_table.out.partners);
390
391         return ctx;
392 }
393
394 static BOOL test_wrepl_update_one(struct test_wrepl_conflict_conn *ctx,
395                                   const struct wrepl_wins_owner *owner,
396                                   const struct wrepl_wins_name *name)
397 {
398         BOOL ret = True;
399         struct wrepl_socket *wrepl_socket;
400         struct wrepl_associate associate;
401         struct wrepl_packet update_packet, repl_send;
402         struct wrepl_table *update;
403         struct wrepl_wins_owner wrepl_wins_owners[1];
404         struct wrepl_packet *repl_recv;
405         struct wrepl_wins_owner *send_request;
406         struct wrepl_send_reply *send_reply;
407         struct wrepl_wins_name wrepl_wins_names[1];
408         uint32_t assoc_ctx;
409         NTSTATUS status;
410
411         wrepl_socket = wrepl_socket_init(ctx, NULL);
412
413         status = wrepl_connect(wrepl_socket, NULL, ctx->address);
414         CHECK_STATUS(status, NT_STATUS_OK);
415
416         status = wrepl_associate(wrepl_socket, &associate);
417         CHECK_STATUS(status, NT_STATUS_OK);
418         assoc_ctx = associate.out.assoc_ctx;
419
420         /* now send a WREPL_REPL_UPDATE message */
421         ZERO_STRUCT(update_packet);
422         update_packet.opcode                    = WREPL_OPCODE_BITS;
423         update_packet.assoc_ctx                 = assoc_ctx;
424         update_packet.mess_type                 = WREPL_REPLICATION;
425         update_packet.message.replication.command       = WREPL_REPL_UPDATE;
426         update  = &update_packet.message.replication.info.table;
427
428         update->partner_count   = ARRAY_SIZE(wrepl_wins_owners);
429         update->partners        = wrepl_wins_owners;
430         update->initiator       = "0.0.0.0";
431
432         wrepl_wins_owners[0]    = *owner;
433
434         status = wrepl_request(wrepl_socket, wrepl_socket,
435                                &update_packet, &repl_recv);
436         CHECK_STATUS(status, NT_STATUS_OK);
437         CHECK_VALUE(repl_recv->mess_type, WREPL_REPLICATION);
438         CHECK_VALUE(repl_recv->message.replication.command, WREPL_REPL_SEND_REQUEST);
439         send_request = &repl_recv->message.replication.info.owner;
440
441         ZERO_STRUCT(repl_send);
442         repl_send.opcode                        = WREPL_OPCODE_BITS;
443         repl_send.assoc_ctx                     = assoc_ctx;
444         repl_send.mess_type                     = WREPL_REPLICATION;
445         repl_send.message.replication.command   = WREPL_REPL_SEND_REPLY;
446         send_reply = &repl_send.message.replication.info.reply;
447
448         send_reply->num_names   = ARRAY_SIZE(wrepl_wins_names);
449         send_reply->names       = wrepl_wins_names;
450
451         wrepl_wins_names[0]     = *name;
452
453         status = wrepl_request(wrepl_socket, wrepl_socket,
454                                &repl_send, &repl_recv);
455         CHECK_STATUS(status, NT_STATUS_OK);
456         CHECK_VALUE(repl_recv->mess_type, WREPL_STOP_ASSOCIATION);
457         CHECK_VALUE(repl_recv->message.stop.reason, 0);
458
459 done:
460         talloc_free(wrepl_socket);
461         return ret;
462 }
463
464 static BOOL test_wrepl_is_applied(struct test_wrepl_conflict_conn *ctx,
465                                   const struct wrepl_wins_owner *owner,
466                                   const struct wrepl_wins_name *name,
467                                   BOOL expected)
468 {
469         BOOL ret = True;
470         NTSTATUS status;
471         struct wrepl_pull_names pull_names;
472
473         pull_names.in.assoc_ctx = ctx->pull_assoc;
474         pull_names.in.partner   = *owner;
475         pull_names.in.partner.min_version = pull_names.in.partner.max_version;
476                 
477         status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
478         CHECK_STATUS(status, NT_STATUS_OK);
479         CHECK_VALUE(pull_names.out.num_names, (expected?1:0));
480
481 done:
482         talloc_free(pull_names.out.names);
483         return ret;
484 }
485
486 static BOOL test_conflict_same_owner(struct test_wrepl_conflict_conn *ctx)
487 {
488         BOOL ret = True;
489         struct nbt_name name;
490         struct wrepl_wins_name wins_name1;
491         struct wrepl_wins_name wins_name2;
492         struct wrepl_wins_name *wins_name_tmp;
493         struct wrepl_wins_name *wins_name_last;
494         struct wrepl_wins_name *wins_name_cur;
495         uint32_t i,j;
496         uint8_t types[] = { 0x00, 0x1C };
497         struct {
498                 enum wrepl_name_type type;
499                 enum wrepl_name_state state;
500                 enum wrepl_name_node node;
501                 BOOL is_static;
502                 uint32_t num_ips;
503                 const struct wrepl_ip *ips;
504         } records[] = {
505                 {
506                 .type           = WREPL_TYPE_GROUP,
507                 .state          = WREPL_STATE_ACTIVE,
508                 .node           = WREPL_NODE_B,
509                 .is_static      = False,
510                 .num_ips        = ARRAY_SIZE(addresses_A_1),
511                 .ips            = addresses_A_1,
512                 },{
513                 .type           = WREPL_TYPE_UNIQUE,
514                 .state          = WREPL_STATE_ACTIVE,
515                 .node           = WREPL_NODE_B,
516                 .is_static      = False,
517                 .num_ips        = ARRAY_SIZE(addresses_A_1),
518                 .ips            = addresses_A_1,
519                 },{
520                 .type           = WREPL_TYPE_UNIQUE,
521                 .state          = WREPL_STATE_ACTIVE,
522                 .node           = WREPL_NODE_B,
523                 .is_static      = False,
524                 .num_ips        = ARRAY_SIZE(addresses_A_2),
525                 .ips            = addresses_A_2,
526                 },{
527                 .type           = WREPL_TYPE_UNIQUE,
528                 .state          = WREPL_STATE_ACTIVE,
529                 .node           = WREPL_NODE_B,
530                 .is_static      = True,
531                 .num_ips        = ARRAY_SIZE(addresses_A_1),
532                 .ips            = addresses_A_1,
533                 },{
534                 .type           = WREPL_TYPE_UNIQUE,
535                 .state          = WREPL_STATE_ACTIVE,
536                 .node           = WREPL_NODE_B,
537                 .is_static      = False,
538                 .num_ips        = ARRAY_SIZE(addresses_A_2),
539                 .ips            = addresses_A_2,
540                 },{
541                 .type           = WREPL_TYPE_SGROUP,
542                 .state          = WREPL_STATE_TOMBSTONE,
543                 .node           = WREPL_NODE_B,
544                 .is_static      = False,
545                 .num_ips        = ARRAY_SIZE(addresses_A_2),
546                 .ips            = addresses_A_2,
547                 },{
548                 .type           = WREPL_TYPE_MHOMED,
549                 .state          = WREPL_STATE_TOMBSTONE,
550                 .node           = WREPL_NODE_B,
551                 .is_static      = False,
552                 .num_ips        = ARRAY_SIZE(addresses_A_1),
553                 .ips            = addresses_A_1,
554                 },{
555                 .type           = WREPL_TYPE_MHOMED,
556                 .state          = WREPL_STATE_RELEASED,
557                 .node           = WREPL_NODE_B,
558                 .is_static      = False,
559                 .num_ips        = ARRAY_SIZE(addresses_A_2),
560                 .ips            = addresses_A_2,
561                 },{
562                 .type           = WREPL_TYPE_SGROUP,
563                 .state          = WREPL_STATE_ACTIVE,
564                 .node           = WREPL_NODE_B,
565                 .is_static      = False,
566                 .num_ips        = ARRAY_SIZE(addresses_A_1),
567                 .ips            = addresses_A_1,
568                 },{
569                 /* the last one should always be a unique,tomstone record! */
570                 .type           = WREPL_TYPE_UNIQUE,
571                 .state          = WREPL_STATE_TOMBSTONE,
572                 .node           = WREPL_NODE_B,
573                 .is_static      = False,
574                 .num_ips        = ARRAY_SIZE(addresses_A_1),
575                 .ips            = addresses_A_1,
576                 }
577         };
578
579         if (!ctx) return False;
580
581         name.name       = "_SAME_OWNER_A";
582         name.type       = 0;
583         name.scope      = NULL;
584
585         wins_name_tmp   = NULL;
586         wins_name_last  = &wins_name2;
587         wins_name_cur   = &wins_name1;
588
589         for (j=0; ret && j < ARRAY_SIZE(types); j++) {
590                 name.type = types[j];
591                 printf("Test Replica Conflicts with same owner[%s] for %s\n",
592                         nbt_name_string(ctx, &name), ctx->a.address);
593
594                 for(i=0; ret && i < ARRAY_SIZE(records); i++) {
595                         wins_name_tmp   = wins_name_last;
596                         wins_name_last  = wins_name_cur;
597                         wins_name_cur   = wins_name_tmp;
598
599                         if (i > 0) {
600                                 printf("%s,%s%s vs, %s,%s%s with %s ip(s) => %s\n",
601                                         wrepl_name_type_string(records[i-1].type),
602                                         wrepl_name_state_string(records[i-1].state),
603                                         (records[i-1].is_static?",static":""),
604                                         wrepl_name_type_string(records[i].type),
605                                         wrepl_name_state_string(records[i].state),
606                                         (records[i].is_static?",static":""),
607                                         (records[i-1].ips==records[i].ips?"same":"different"),
608                                         "REPLACE");
609                         }
610
611                         wins_name_cur->name     = &name;
612                         wins_name_cur->flags    = WREPL_NAME_FLAGS(records[i].type,
613                                                                    records[i].state,
614                                                                    records[i].node,
615                                                                    records[i].is_static);
616                         wins_name_cur->id       = ++ctx->a.max_version;
617                         if (wins_name_cur->flags & 2) {
618                                 wins_name_cur->addresses.addresses.num_ips = records[i].num_ips;
619                                 wins_name_cur->addresses.addresses.ips     = discard_const(records[i].ips);
620                         } else {
621                                 wins_name_cur->addresses.ip = records[i].ips[0].ip;
622                         }
623                         wins_name_cur->unknown  = "255.255.255.255";
624
625                         ret &= test_wrepl_update_one(ctx, &ctx->a,wins_name_cur);
626                         if (records[i].state == WREPL_STATE_RELEASED) {
627                                 ret &= test_wrepl_is_applied(ctx, &ctx->a, wins_name_last, False);
628                                 ret &= test_wrepl_is_applied(ctx, &ctx->a, wins_name_cur, False);
629                         } else {
630                                 ret &= test_wrepl_is_applied(ctx, &ctx->a, wins_name_cur, True);
631                         }
632
633                         /* the first one is a cleanup run */
634                         if (!ret && i == 0) ret = True;
635
636                         if (!ret) {
637                                 printf("conflict handled wrong or record[%u]: %s\n", i, __location__);
638                                 return ret;
639                         }
640                 }
641         }
642         return ret;
643 }
644
645 static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
646 {
647         BOOL ret = True;
648         struct wrepl_wins_name wins_name1;
649         struct wrepl_wins_name wins_name2;
650         struct wrepl_wins_name *wins_name_r1;
651         struct wrepl_wins_name *wins_name_r2;
652         uint32_t i;
653         struct {
654                 const char *line; /* just better debugging */
655                 struct nbt_name name;
656                 struct {
657                         struct wrepl_wins_owner *owner;
658                         enum wrepl_name_type type;
659                         enum wrepl_name_state state;
660                         enum wrepl_name_node node;
661                         BOOL is_static;
662                         uint32_t num_ips;
663                         const struct wrepl_ip *ips;
664                         BOOL apply_expected;
665                 } r1, r2;
666         } records[] = {
667         /* 
668          * NOTE: the first record and the last applied one
669          *       needs to be from the same owner,
670          *       to not conflict in the next smbtorture run!!!
671          */
672         {
673                 .line   = __location__,
674                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
675                 .r1     = {
676                         .owner          = &ctx->b,
677                         .type           = WREPL_TYPE_UNIQUE,
678                         .state          = WREPL_STATE_TOMBSTONE,
679                         .node           = WREPL_NODE_B,
680                         .is_static      = False,
681                         .num_ips        = ARRAY_SIZE(addresses_B_1),
682                         .ips            = addresses_B_1,
683                         .apply_expected = True /* ignored */
684                 },
685                 .r2     = {
686                         .owner          = &ctx->a,
687                         .type           = WREPL_TYPE_UNIQUE,
688                         .state          = WREPL_STATE_TOMBSTONE,
689                         .node           = WREPL_NODE_B,
690                         .is_static      = False,
691                         .num_ips        = ARRAY_SIZE(addresses_A_1),
692                         .ips            = addresses_A_1,
693                         .apply_expected = True /* ignored */
694                 }
695         },
696
697 /*
698  * unique vs unique section
699  */
700         /* 
701          * unique,active vs. unique,active the same ip
702          * => should be replaced
703          */
704         {
705                 .line   = __location__,
706                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
707                 .r1     = {
708                         .owner          = &ctx->a,
709                         .type           = WREPL_TYPE_UNIQUE,
710                         .state          = WREPL_STATE_ACTIVE,
711                         .node           = WREPL_NODE_B,
712                         .is_static      = False,
713                         .num_ips        = ARRAY_SIZE(addresses_A_1),
714                         .ips            = addresses_A_1,
715                         .apply_expected = True
716                 },
717                 .r2     = {
718                         .owner          = &ctx->b,
719                         .type           = WREPL_TYPE_UNIQUE,
720                         .state          = WREPL_STATE_ACTIVE,
721                         .node           = WREPL_NODE_B,
722                         .is_static      = False,
723                         .num_ips        = ARRAY_SIZE(addresses_A_1),
724                         .ips            = addresses_A_1,
725                         .apply_expected = True
726                 }
727         },
728
729         /* 
730          * unique,active vs. unique,tombstone the same ips
731          * => should NOT be replaced
732          */
733         {
734                 .line   = __location__,
735                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
736                 .r1     = {
737                         .owner          = &ctx->b,
738                         .type           = WREPL_TYPE_UNIQUE,
739                         .state          = WREPL_STATE_ACTIVE,
740                         .node           = WREPL_NODE_B,
741                         .is_static      = False,
742                         .num_ips        = ARRAY_SIZE(addresses_B_1),
743                         .ips            = addresses_B_1,
744                         .apply_expected = True
745                 },
746                 .r2     = {
747                         .owner          = &ctx->a,
748                         .type           = WREPL_TYPE_UNIQUE,
749                         .state          = WREPL_STATE_TOMBSTONE,
750                         .node           = WREPL_NODE_B,
751                         .is_static      = False,
752                         .num_ips        = ARRAY_SIZE(addresses_B_1),
753                         .ips            = addresses_B_1,
754                         .apply_expected = False
755                 }
756         },
757
758         /* 
759          * unique,tombstone vs. unique,active the same ips
760          * => should NOT be replaced
761          */
762         {
763                 .line   = __location__,
764                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
765                 .r1     = {
766                         .owner          = &ctx->b,
767                         .type           = WREPL_TYPE_UNIQUE,
768                         .state          = WREPL_STATE_TOMBSTONE,
769                         .node           = WREPL_NODE_B,
770                         .is_static      = False,
771                         .num_ips        = ARRAY_SIZE(addresses_B_1),
772                         .ips            = addresses_B_1,
773                         .apply_expected = True
774                 },
775                 .r2     = {
776                         .owner          = &ctx->a,
777                         .type           = WREPL_TYPE_UNIQUE,
778                         .state          = WREPL_STATE_ACTIVE,
779                         .node           = WREPL_NODE_B,
780                         .is_static      = False,
781                         .num_ips        = ARRAY_SIZE(addresses_B_1),
782                         .ips            = addresses_B_1,
783                         .apply_expected = True
784                 }
785         },
786
787         /* 
788          * unique,tombstone vs. unique,tombstone the same ips
789          * => should be replaced
790          */
791         {
792                 .line   = __location__,
793                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
794                 .r1     = {
795                         .owner          = &ctx->a,
796                         .type           = WREPL_TYPE_UNIQUE,
797                         .state          = WREPL_STATE_TOMBSTONE,
798                         .node           = WREPL_NODE_B,
799                         .is_static      = False,
800                         .num_ips        = ARRAY_SIZE(addresses_A_1),
801                         .ips            = addresses_A_1,
802                         .apply_expected = True
803                 },
804                 .r2     = {
805                         .owner          = &ctx->b,
806                         .type           = WREPL_TYPE_UNIQUE,
807                         .state          = WREPL_STATE_TOMBSTONE,
808                         .node           = WREPL_NODE_B,
809                         .is_static      = False,
810                         .num_ips        = ARRAY_SIZE(addresses_A_1),
811                         .ips            = addresses_A_1,
812                         .apply_expected = True
813                 }
814         },
815
816         /* 
817          * unique,active vs. unique,active the different ips
818          * => should be replaced
819          */
820         {
821                 .line   = __location__,
822                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
823                 .r1     = {
824                         .owner          = &ctx->a,
825                         .type           = WREPL_TYPE_UNIQUE,
826                         .state          = WREPL_STATE_ACTIVE,
827                         .node           = WREPL_NODE_B,
828                         .is_static      = False,
829                         .num_ips        = ARRAY_SIZE(addresses_A_1),
830                         .ips            = addresses_A_1,
831                         .apply_expected = True
832                 },
833                 .r2     = {
834                         .owner          = &ctx->b,
835                         .type           = WREPL_TYPE_UNIQUE,
836                         .state          = WREPL_STATE_ACTIVE,
837                         .node           = WREPL_NODE_B,
838                         .is_static      = False,
839                         .num_ips        = ARRAY_SIZE(addresses_B_1),
840                         .ips            = addresses_B_1,
841                         .apply_expected = True
842                 }
843         },
844
845         /* 
846          * unique,active vs. unique,tombstone the different ips
847          * => should NOT be replaced
848          */
849         {
850                 .line   = __location__,
851                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
852                 .r1     = {
853                         .owner          = &ctx->b,
854                         .type           = WREPL_TYPE_UNIQUE,
855                         .state          = WREPL_STATE_ACTIVE,
856                         .node           = WREPL_NODE_B,
857                         .is_static      = False,
858                         .num_ips        = ARRAY_SIZE(addresses_B_1),
859                         .ips            = addresses_B_1,
860                         .apply_expected = True
861                 },
862                 .r2     = {
863                         .owner          = &ctx->a,
864                         .type           = WREPL_TYPE_UNIQUE,
865                         .state          = WREPL_STATE_TOMBSTONE,
866                         .node           = WREPL_NODE_B,
867                         .is_static      = False,
868                         .num_ips        = ARRAY_SIZE(addresses_A_1),
869                         .ips            = addresses_A_1,
870                         .apply_expected = False
871                 }
872         },
873
874         /* 
875          * unique,tombstone vs. unique,active the different ips
876          * => should be replaced
877          */
878         {
879                 .line   = __location__,
880                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
881                 .r1     = {
882                         .owner          = &ctx->b,
883                         .type           = WREPL_TYPE_UNIQUE,
884                         .state          = WREPL_STATE_TOMBSTONE,
885                         .node           = WREPL_NODE_B,
886                         .is_static      = False,
887                         .num_ips        = ARRAY_SIZE(addresses_B_1),
888                         .ips            = addresses_B_1,
889                         .apply_expected = True
890                 },
891                 .r2     = {
892                         .owner          = &ctx->a,
893                         .type           = WREPL_TYPE_UNIQUE,
894                         .state          = WREPL_STATE_ACTIVE,
895                         .node           = WREPL_NODE_B,
896                         .is_static      = False,
897                         .num_ips        = ARRAY_SIZE(addresses_A_1),
898                         .ips            = addresses_A_1,
899                         .apply_expected = True
900                 }
901         },
902
903         /* 
904          * unique,tombstone vs. unique,tombstone the different ips
905          * => should be replaced
906          */
907         {
908                 .line   = __location__,
909                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
910                 .r1     = {
911                         .owner          = &ctx->a,
912                         .type           = WREPL_TYPE_UNIQUE,
913                         .state          = WREPL_STATE_TOMBSTONE,
914                         .node           = WREPL_NODE_B,
915                         .is_static      = False,
916                         .num_ips        = ARRAY_SIZE(addresses_A_1),
917                         .ips            = addresses_A_1,
918                         .apply_expected = True
919                 },
920                 .r2     = {
921                         .owner          = &ctx->b,
922                         .type           = WREPL_TYPE_UNIQUE,
923                         .state          = WREPL_STATE_TOMBSTONE,
924                         .node           = WREPL_NODE_B,
925                         .is_static      = False,
926                         .num_ips        = ARRAY_SIZE(addresses_B_1),
927                         .ips            = addresses_B_1,
928                         .apply_expected = True
929                 }
930         },
931
932 /*
933  * unique vs normal groups section,
934  * TODO: group,released!
935  */
936         /* 
937          * unique,active vs. group,active
938          * => should be replaced
939          */
940         {
941                 .line   = __location__,
942                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
943                 .r1     = {
944                         .owner          = &ctx->b,
945                         .type           = WREPL_TYPE_UNIQUE,
946                         .state          = WREPL_STATE_ACTIVE,
947                         .node           = WREPL_NODE_B,
948                         .is_static      = False,
949                         .num_ips        = ARRAY_SIZE(addresses_B_1),
950                         .ips            = addresses_B_1,
951                         .apply_expected = True
952                 },
953                 .r2     = {
954                         .owner          = &ctx->a,
955                         .type           = WREPL_TYPE_GROUP,
956                         .state          = WREPL_STATE_ACTIVE,
957                         .node           = WREPL_NODE_B,
958                         .is_static      = False,
959                         .num_ips        = ARRAY_SIZE(addresses_A_1),
960                         .ips            = addresses_A_1,
961                         .apply_expected = True
962                 }
963         },
964
965         /* 
966          * unique,active vs. group,tombstone same ip
967          * => should NOT be replaced
968          */
969         {
970                 .line   = __location__,
971                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
972                 .r1     = {
973                         .owner          = &ctx->a,
974                         .type           = WREPL_TYPE_UNIQUE,
975                         .state          = WREPL_STATE_ACTIVE,
976                         .node           = WREPL_NODE_B,
977                         .is_static      = False,
978                         .num_ips        = ARRAY_SIZE(addresses_A_1),
979                         .ips            = addresses_A_1,
980                         .apply_expected = True
981                 },
982                 .r2     = {
983                         .owner          = &ctx->b,
984                         .type           = WREPL_TYPE_GROUP,
985                         .state          = WREPL_STATE_TOMBSTONE,
986                         .node           = WREPL_NODE_B,
987                         .is_static      = False,
988                         .num_ips        = ARRAY_SIZE(addresses_A_1),
989                         .ips            = addresses_A_1,
990                         .apply_expected = False
991                 }
992         },
993
994         /* 
995          * unique,active vs. group,tombstone different ip
996          * => should NOT be replaced
997          */
998         {
999                 .line   = __location__,
1000                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1001                 .r1     = {
1002                         .owner          = &ctx->a,
1003                         .type           = WREPL_TYPE_UNIQUE,
1004                         .state          = WREPL_STATE_ACTIVE,
1005                         .node           = WREPL_NODE_B,
1006                         .is_static      = False,
1007                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1008                         .ips            = addresses_A_1,
1009                         .apply_expected = True
1010                 },
1011                 .r2     = {
1012                         .owner          = &ctx->b,
1013                         .type           = WREPL_TYPE_GROUP,
1014                         .state          = WREPL_STATE_TOMBSTONE,
1015                         .node           = WREPL_NODE_B,
1016                         .is_static      = False,
1017                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1018                         .ips            = addresses_B_1,
1019                         .apply_expected = False
1020                 }
1021         },
1022
1023         /* 
1024          * unique,active vs. group,released
1025          * => should NOT be replaced
1026          */
1027         {
1028                 .line   = __location__,
1029                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1030                 .r1     = {
1031                         .owner          = &ctx->a,
1032                         .type           = WREPL_TYPE_UNIQUE,
1033                         .state          = WREPL_STATE_ACTIVE,
1034                         .node           = WREPL_NODE_B,
1035                         .is_static      = False,
1036                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1037                         .ips            = addresses_A_1,
1038                         .apply_expected = True
1039                 },
1040                 .r2     = {
1041                         .owner          = &ctx->b,
1042                         .type           = WREPL_TYPE_GROUP,
1043                         .state          = WREPL_STATE_RELEASED,
1044                         .node           = WREPL_NODE_B,
1045                         .is_static      = False,
1046                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1047                         .ips            = addresses_B_1,
1048                         .apply_expected = False
1049                 }
1050         },
1051
1052         /* 
1053          * unique,tombstone vs. group,active
1054          * => should be replaced
1055          */
1056         {
1057                 .line   = __location__,
1058                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1059                 .r1     = {
1060                         .owner          = &ctx->a,
1061                         .type           = WREPL_TYPE_UNIQUE,
1062                         .state          = WREPL_STATE_TOMBSTONE,
1063                         .node           = WREPL_NODE_B,
1064                         .is_static      = False,
1065                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1066                         .ips            = addresses_A_1,
1067                         .apply_expected = True
1068                 },
1069                 .r2     = {
1070                         .owner          = &ctx->b,
1071                         .type           = WREPL_TYPE_GROUP,
1072                         .state          = WREPL_STATE_ACTIVE,
1073                         .node           = WREPL_NODE_B,
1074                         .is_static      = False,
1075                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1076                         .ips            = addresses_B_1,
1077                         .apply_expected = True
1078                 }
1079         },
1080
1081         /* 
1082          * unique,tombstone vs. group,tombstone
1083          * => should be replaced
1084          */
1085         {
1086                 .line   = __location__,
1087                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1088                 .r1     = {
1089                         .owner          = &ctx->b,
1090                         .type           = WREPL_TYPE_UNIQUE,
1091                         .state          = WREPL_STATE_TOMBSTONE,
1092                         .node           = WREPL_NODE_B,
1093                         .is_static      = False,
1094                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1095                         .ips            = addresses_B_1,
1096                         .apply_expected = True
1097                 },
1098                 .r2     = {
1099                         .owner          = &ctx->a,
1100                         .type           = WREPL_TYPE_GROUP,
1101                         .state          = WREPL_STATE_TOMBSTONE,
1102                         .node           = WREPL_NODE_B,
1103                         .is_static      = False,
1104                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1105                         .ips            = addresses_A_1,
1106                         .apply_expected = True
1107                 }
1108         },
1109
1110         /* 
1111          * unique,tombstone vs. group,released
1112          * => should be replaced
1113          */
1114         {
1115                 .line   = __location__,
1116                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1117                 .r1     = {
1118                         .owner          = &ctx->a,
1119                         .type           = WREPL_TYPE_UNIQUE,
1120                         .state          = WREPL_STATE_TOMBSTONE,
1121                         .node           = WREPL_NODE_B,
1122                         .is_static      = False,
1123                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1124                         .ips            = addresses_A_1,
1125                         .apply_expected = True
1126                 },
1127                 .r2     = {
1128                         .owner          = &ctx->b,
1129                         .type           = WREPL_TYPE_GROUP,
1130                         .state          = WREPL_STATE_RELEASED,
1131                         .node           = WREPL_NODE_B,
1132                         .is_static      = False,
1133                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1134                         .ips            = addresses_B_1,
1135                         .apply_expected = True
1136                 }
1137         },
1138
1139         /* 
1140          * unique,released vs. group,released
1141          * => should be replaced
1142          */
1143         {
1144                 .line   = __location__,
1145                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1146                 .r1     = {
1147                         .owner          = &ctx->b,
1148                         .type           = WREPL_TYPE_UNIQUE,
1149                         .state          = WREPL_STATE_RELEASED,
1150                         .node           = WREPL_NODE_B,
1151                         .is_static      = False,
1152                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1153                         .ips            = addresses_B_1,
1154                         .apply_expected = False
1155                 },
1156                 .r2     = {
1157                         .owner          = &ctx->a,
1158                         .type           = WREPL_TYPE_GROUP,
1159                         .state          = WREPL_STATE_RELEASED,
1160                         .node           = WREPL_NODE_B,
1161                         .is_static      = False,
1162                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1163                         .ips            = addresses_A_1,
1164                         .apply_expected = True
1165                 }
1166         },
1167
1168         /* 
1169          * unique,released vs. group,released
1170          * => should be replaced
1171          */
1172         {
1173                 .line   = __location__,
1174                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1175                 .r1     = {
1176                         .owner          = &ctx->a,
1177                         .type           = WREPL_TYPE_UNIQUE,
1178                         .state          = WREPL_STATE_RELEASED,
1179                         .node           = WREPL_NODE_B,
1180                         .is_static      = False,
1181                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1182                         .ips            = addresses_A_1,
1183                         .apply_expected = False
1184                 },
1185                 .r2     = {
1186                         .owner          = &ctx->b,
1187                         .type           = WREPL_TYPE_GROUP,
1188                         .state          = WREPL_STATE_TOMBSTONE,
1189                         .node           = WREPL_NODE_B,
1190                         .is_static      = False,
1191                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1192                         .ips            = addresses_B_1,
1193                         .apply_expected = True
1194                 }
1195         },
1196
1197         /* 
1198          * group,active vs. unique,active
1199          * => should NOT be replaced
1200          */
1201         {
1202                 .line   = __location__,
1203                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1204                 .r1     = {
1205                         .owner          = &ctx->a,
1206                         .type           = WREPL_TYPE_GROUP,
1207                         .state          = WREPL_STATE_ACTIVE,
1208                         .node           = WREPL_NODE_B,
1209                         .is_static      = False,
1210                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1211                         .ips            = addresses_A_1,
1212                         .apply_expected = True
1213                 },
1214                 .r2     = {
1215                         .owner          = &ctx->b,
1216                         .type           = WREPL_TYPE_UNIQUE,
1217                         .state          = WREPL_STATE_TOMBSTONE,
1218                         .node           = WREPL_NODE_B,
1219                         .is_static      = False,
1220                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1221                         .ips            = addresses_B_1,
1222                         .apply_expected = False
1223                 }
1224         },
1225
1226         /* 
1227          * group,active vs. unique,tombstone
1228          * => should NOT be replaced
1229          */
1230         {
1231                 .line   = __location__,
1232                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1233                 .r1     = {
1234                         .owner          = &ctx->a,
1235                         .type           = WREPL_TYPE_GROUP,
1236                         .state          = WREPL_STATE_ACTIVE,
1237                         .node           = WREPL_NODE_B,
1238                         .is_static      = False,
1239                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1240                         .ips            = addresses_A_1,
1241                         .apply_expected = True
1242                 },
1243                 .r2     = {
1244                         .owner          = &ctx->b,
1245                         .type           = WREPL_TYPE_UNIQUE,
1246                         .state          = WREPL_STATE_TOMBSTONE,
1247                         .node           = WREPL_NODE_B,
1248                         .is_static      = False,
1249                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1250                         .ips            = addresses_B_1,
1251                         .apply_expected = False
1252                 }
1253         },
1254
1255         /* 
1256          * group,released vs. unique,active
1257          * => should NOT be replaced
1258          */
1259         {
1260                 .line   = __location__,
1261                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1262                 .r1     = {
1263                         .owner          = &ctx->a,
1264                         .type           = WREPL_TYPE_GROUP,
1265                         .state          = WREPL_STATE_RELEASED,
1266                         .node           = WREPL_NODE_B,
1267                         .is_static      = False,
1268                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1269                         .ips            = addresses_A_1,
1270                         .apply_expected = False
1271                 },
1272                 .r2     = {
1273                         .owner          = &ctx->b,
1274                         .type           = WREPL_TYPE_UNIQUE,
1275                         .state          = WREPL_STATE_ACTIVE,
1276                         .node           = WREPL_NODE_B,
1277                         .is_static      = False,
1278                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1279                         .ips            = addresses_B_1,
1280                         .apply_expected = False
1281                 }
1282         },
1283
1284         /* 
1285          * group,released vs. unique,tombstone
1286          * => should NOT be replaced
1287          */
1288         {
1289                 .line   = __location__,
1290                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1291                 .r1     = {
1292                         .owner          = &ctx->a,
1293                         .type           = WREPL_TYPE_GROUP,
1294                         .state          = WREPL_STATE_RELEASED,
1295                         .node           = WREPL_NODE_B,
1296                         .is_static      = False,
1297                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1298                         .ips            = addresses_A_1,
1299                         .apply_expected = False
1300                 },
1301                 .r2     = {
1302                         .owner          = &ctx->b,
1303                         .type           = WREPL_TYPE_UNIQUE,
1304                         .state          = WREPL_STATE_TOMBSTONE,
1305                         .node           = WREPL_NODE_B,
1306                         .is_static      = False,
1307                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1308                         .ips            = addresses_B_1,
1309                         .apply_expected = False
1310                 }
1311         },
1312
1313         /* 
1314          * group,tombstone vs. unique,active
1315          * => should NOT be replaced
1316          */
1317         {
1318                 .line   = __location__,
1319                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1320                 .r1     = {
1321                         .owner          = &ctx->a,
1322                         .type           = WREPL_TYPE_GROUP,
1323                         .state          = WREPL_STATE_TOMBSTONE,
1324                         .node           = WREPL_NODE_B,
1325                         .is_static      = False,
1326                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1327                         .ips            = addresses_A_1,
1328                         .apply_expected = True
1329                 },
1330                 .r2     = {
1331                         .owner          = &ctx->b,
1332                         .type           = WREPL_TYPE_UNIQUE,
1333                         .state          = WREPL_STATE_ACTIVE,
1334                         .node           = WREPL_NODE_B,
1335                         .is_static      = False,
1336                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1337                         .ips            = addresses_B_1,
1338                         .apply_expected = False
1339                 }
1340         },
1341
1342         /* 
1343          * group,tombstone vs. unique,tombstone
1344          * => should NOT be replaced
1345          */
1346         {
1347                 .line   = __location__,
1348                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1349                 .r1     = {
1350                         .owner          = &ctx->a,
1351                         .type           = WREPL_TYPE_GROUP,
1352                         .state          = WREPL_STATE_TOMBSTONE,
1353                         .node           = WREPL_NODE_B,
1354                         .is_static      = False,
1355                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1356                         .ips            = addresses_A_1,
1357                         .apply_expected = True
1358                 },
1359                 .r2     = {
1360                         .owner          = &ctx->b,
1361                         .type           = WREPL_TYPE_UNIQUE,
1362                         .state          = WREPL_STATE_TOMBSTONE,
1363                         .node           = WREPL_NODE_B,
1364                         .is_static      = False,
1365                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1366                         .ips            = addresses_B_1,
1367                         .apply_expected = False
1368                 }
1369         },
1370
1371         /* 
1372          * This should be the last record in this array,
1373          * we need to make sure the we leave a tombstoned unique entry
1374          * owned by OWNER_A
1375          */
1376         {
1377                 .line   = __location__,
1378                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1379                 .r1     = {
1380                         .owner          = &ctx->a,
1381                         .type           = WREPL_TYPE_UNIQUE,
1382                         .state          = WREPL_STATE_TOMBSTONE,
1383                         .node           = WREPL_NODE_B,
1384                         .is_static      = False,
1385                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1386                         .ips            = addresses_A_1,
1387                         .apply_expected = True
1388                 },
1389                 .r2     = {
1390                         .owner          = &ctx->a,
1391                         .type           = WREPL_TYPE_UNIQUE,
1392                         .state          = WREPL_STATE_TOMBSTONE,
1393                         .node           = WREPL_NODE_B,
1394                         .is_static      = False,
1395                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1396                         .ips            = addresses_A_1,
1397                         .apply_expected = True
1398                 }
1399         }}; /* do not add entries here, this should be the last record! */
1400
1401         if (!ctx) return False;
1402
1403         wins_name_r1    = &wins_name1;
1404         wins_name_r2    = &wins_name2;
1405
1406         printf("Test Replica Conflicts with different owners\n");
1407
1408         for(i=0; ret && i < ARRAY_SIZE(records); i++) {
1409
1410                 if (i > 0) {
1411                         printf("%s,%s%s vs, %s,%s%s with %s ip(s) => %s\n",
1412                                 wrepl_name_type_string(records[i].r1.type),
1413                                 wrepl_name_state_string(records[i].r1.state),
1414                                 (records[i].r1.is_static?",static":""),
1415                                 wrepl_name_type_string(records[i].r2.type),
1416                                 wrepl_name_state_string(records[i].r2.state),
1417                                 (records[i].r2.is_static?",static":""),
1418                                 (records[i].r1.ips==records[i].r2.ips?"same":"different"),
1419                                 (records[i].r2.apply_expected?"REPLACE":"NOT REPLACE"));
1420                 }
1421
1422                 /*
1423                  * Setup R1
1424                  */
1425                 wins_name_r1->name      = &records[i].name;
1426                 wins_name_r1->flags     = WREPL_NAME_FLAGS(records[i].r1.type,
1427                                                            records[i].r1.state,
1428                                                            records[i].r1.node,
1429                                                            records[i].r1.is_static);
1430                 wins_name_r1->id        = ++records[i].r1.owner->max_version;
1431                 if (wins_name_r1->flags & 2) {
1432                         wins_name_r1->addresses.addresses.num_ips = records[i].r1.num_ips;
1433                         wins_name_r1->addresses.addresses.ips     = discard_const(records[i].r1.ips);
1434                 } else {
1435                         wins_name_r1->addresses.ip = records[i].r1.ips[0].ip;
1436                 }
1437                 wins_name_r1->unknown   = "255.255.255.255";
1438
1439                 /* now apply R1 */
1440                 ret &= test_wrepl_update_one(ctx, records[i].r1.owner, wins_name_r1);
1441                 ret &= test_wrepl_is_applied(ctx, records[i].r1.owner,
1442                                              wins_name_r1, records[i].r1.apply_expected);
1443
1444                 /*
1445                  * Setup R2
1446                  */
1447                 wins_name_r2->name      = &records[i].name;
1448                 wins_name_r2->flags     = WREPL_NAME_FLAGS(records[i].r2.type,
1449                                                            records[i].r2.state,
1450                                                            records[i].r2.node,
1451                                                            records[i].r2.is_static);
1452                 wins_name_r2->id        = ++records[i].r2.owner->max_version;
1453                 if (wins_name_r2->flags & 2) {
1454                         wins_name_r2->addresses.addresses.num_ips = records[i].r2.num_ips;
1455                         wins_name_r2->addresses.addresses.ips     = discard_const(records[i].r2.ips);
1456                 } else {
1457                         wins_name_r2->addresses.ip = records[i].r2.ips[0].ip;
1458                 }
1459                 wins_name_r2->unknown   = "255.255.255.255";
1460
1461                 /* now apply R2 */
1462                 ret &= test_wrepl_update_one(ctx, records[i].r2.owner, wins_name_r2);
1463                 if (records[i].r2.apply_expected &&
1464                     (records[i].r1.state == WREPL_STATE_RELEASED ||
1465                      records[i].r2.state == WREPL_STATE_RELEASED)) {
1466                         ret &= test_wrepl_is_applied(ctx, records[i].r1.owner,
1467                                                      wins_name_r1, False);
1468                 }
1469                 if (records[i].r2.state == WREPL_STATE_RELEASED) {
1470                         ret &= test_wrepl_is_applied(ctx, records[i].r2.owner,
1471                                                      wins_name_r2, False);
1472                 } else {
1473                         ret &= test_wrepl_is_applied(ctx, records[i].r2.owner,
1474                                                      wins_name_r2, records[i].r2.apply_expected);
1475                 }
1476
1477                 /* the first one is a cleanup run */
1478                 if (!ret && i == 0) ret = True;
1479
1480                 if (!ret) {
1481                         printf("conflict handled wrong or record[%u]: %s\n", i, records[i].line);
1482                         return ret;
1483                 }
1484         }
1485
1486         return ret;
1487 }
1488
1489 /*
1490   test WINS replication operations
1491 */
1492 BOOL torture_nbt_winsreplication(void)
1493 {
1494         const char *address;
1495         struct nbt_name name;
1496         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1497         NTSTATUS status;
1498         BOOL ret = True;
1499         struct test_wrepl_conflict_conn *ctx;
1500
1501         make_nbt_name_server(&name, lp_parm_string(-1, "torture", "host"));
1502
1503         /* do an initial name resolution to find its IP */
1504         status = resolve_name(&name, mem_ctx, &address, NULL);
1505         if (!NT_STATUS_IS_OK(status)) {
1506                 printf("Failed to resolve %s - %s\n",
1507                        name.name, nt_errstr(status));
1508                 talloc_free(mem_ctx);
1509                 return False;
1510         }
1511
1512         ret &= test_assoc_ctx1(mem_ctx, address);
1513         ret &= test_assoc_ctx2(mem_ctx, address);
1514
1515         ret &= test_wins_replication(mem_ctx, address);
1516
1517         ctx = test_create_conflict_ctx(mem_ctx, address);
1518
1519         ret &= test_conflict_same_owner(ctx);
1520         ret &= test_conflict_different_owner(ctx);
1521
1522         talloc_free(mem_ctx);
1523
1524         return ret;
1525 }