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