r10971: - test static records with the same owner too
[tprouty/samba.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 /*
50   test how assoc_ctx's are only usable on the connection
51   they are created on.
52 */
53 static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address)
54 {
55         BOOL ret = True;
56         struct wrepl_request *req;
57         struct wrepl_socket *wrepl_socket1;
58         struct wrepl_associate associate1;
59         struct wrepl_socket *wrepl_socket2;
60         struct wrepl_associate associate2;
61         struct wrepl_pull_table pull_table;
62         struct wrepl_packet *rep_packet;
63         struct wrepl_associate_stop assoc_stop;
64         NTSTATUS status;
65
66         if (!lp_parm_bool(-1, "torture", "dangerous", False)) {
67                 printf("winsrepl: cross connection assoc_ctx usage disabled - enable dangerous tests to use\n");
68                 return True;
69         }
70
71         printf("Test if assoc_ctx is only valid on the conection it was created on\n");
72
73         wrepl_socket1 = wrepl_socket_init(mem_ctx, NULL);
74         wrepl_socket2 = wrepl_socket_init(mem_ctx, NULL);
75
76         printf("Setup 2 wrepl connections\n");
77         status = wrepl_connect(wrepl_socket1, NULL, address);
78         CHECK_STATUS(status, NT_STATUS_OK);
79
80         status = wrepl_connect(wrepl_socket2, NULL, address);
81         CHECK_STATUS(status, NT_STATUS_OK);
82
83         printf("Send a start association request (conn1)\n");
84         status = wrepl_associate(wrepl_socket1, &associate1);
85         CHECK_STATUS(status, NT_STATUS_OK);
86
87         printf("association context (conn1): 0x%x\n", associate1.out.assoc_ctx);
88
89         printf("Send a start association request (conn2)\n");
90         status = wrepl_associate(wrepl_socket2, &associate2);
91         CHECK_STATUS(status, NT_STATUS_OK);
92
93         printf("association context (conn2): 0x%x\n", associate2.out.assoc_ctx);
94
95         printf("Send a replication table query, with assoc 1 (conn2), the anwser should be on conn1\n");
96         pull_table.in.assoc_ctx = associate1.out.assoc_ctx;
97         req = wrepl_pull_table_send(wrepl_socket2, &pull_table);
98         req->send_only = True;
99         status = wrepl_request_recv(req, mem_ctx, &rep_packet);
100         CHECK_STATUS(status, NT_STATUS_OK);
101
102         printf("Send a association request (conn2), to make sure the last request was ignored\n");
103         status = wrepl_associate(wrepl_socket2, &associate2);
104         CHECK_STATUS(status, NT_STATUS_OK);
105
106         printf("Send a replication table query, with invalid assoc (conn1), receive answer from conn2\n");
107         pull_table.in.assoc_ctx = 0;
108         req = wrepl_pull_table_send(wrepl_socket1, &pull_table);
109         status = wrepl_request_recv(req, mem_ctx, &rep_packet);
110         CHECK_STATUS(status, NT_STATUS_OK);
111
112         printf("Send a association request (conn1), to make sure the last request was handled correct\n");
113         status = wrepl_associate(wrepl_socket1, &associate2);
114         CHECK_STATUS(status, NT_STATUS_OK);
115
116         assoc_stop.in.assoc_ctx = associate1.out.assoc_ctx;
117         assoc_stop.in.reason    = 4;
118         printf("Send a association stop request (conn1), reson: %u\n", assoc_stop.in.reason);
119         status = wrepl_associate_stop(wrepl_socket1, &assoc_stop);
120         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
121
122         assoc_stop.in.assoc_ctx = associate2.out.assoc_ctx;
123         assoc_stop.in.reason    = 0;
124         printf("Send a association stop request (conn2), reson: %u\n", assoc_stop.in.reason);
125         status = wrepl_associate_stop(wrepl_socket2, &assoc_stop);
126         CHECK_STATUS(status, NT_STATUS_OK);
127
128 done:
129         printf("Close 2 wrepl connections\n");
130         talloc_free(wrepl_socket1);
131         talloc_free(wrepl_socket2);
132         return ret;
133 }
134
135 /*
136   test if we always get back the same assoc_ctx
137 */
138 static BOOL test_assoc_ctx2(TALLOC_CTX *mem_ctx, const char *address)
139 {
140         BOOL ret = True;
141         struct wrepl_socket *wrepl_socket;
142         struct wrepl_associate associate;
143         uint32_t assoc_ctx1;
144         NTSTATUS status;
145
146         printf("Test if we always get back the same assoc_ctx\n");
147
148         wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
149         
150         printf("Setup wrepl connections\n");
151         status = wrepl_connect(wrepl_socket, NULL, address);
152         CHECK_STATUS(status, NT_STATUS_OK);
153
154
155         printf("Send 1st start association request\n");
156         status = wrepl_associate(wrepl_socket, &associate);
157         CHECK_STATUS(status, NT_STATUS_OK);
158         assoc_ctx1 = associate.out.assoc_ctx;
159         printf("1st association context: 0x%x\n", associate.out.assoc_ctx);
160
161         printf("Send 2nd start association request\n");
162         status = wrepl_associate(wrepl_socket, &associate);
163         CHECK_VALUE(associate.out.assoc_ctx, assoc_ctx1);
164         CHECK_STATUS(status, NT_STATUS_OK);
165         printf("2nd association context: 0x%x\n", associate.out.assoc_ctx);
166
167         printf("Send 3rd start association request\n");
168         status = wrepl_associate(wrepl_socket, &associate);
169         CHECK_VALUE(associate.out.assoc_ctx, assoc_ctx1);
170         CHECK_STATUS(status, NT_STATUS_OK);
171         printf("3rd association context: 0x%x\n", associate.out.assoc_ctx);
172
173 done:
174         printf("Close wrepl connections\n");
175         talloc_free(wrepl_socket);
176         return ret;
177 }
178
179
180 /*
181   display a replication entry
182 */
183 static void display_entry(TALLOC_CTX *mem_ctx, struct wrepl_name *name)
184 {
185         int i;
186
187         printf("%s\n", nbt_name_string(mem_ctx, &name->name));
188         printf("\tTYPE:%u STATE:%u NODE:%u STATIC:%u VERSION_ID: %llu\n",
189                 name->type, name->state, name->node, name->is_static, name->version_id);
190         printf("\tRAW_FLAGS: 0x%08X OWNER: %-15s\n",
191                 name->raw_flags, name->owner);
192         for (i=0;i<name->num_addresses;i++) {
193                 printf("\tADDR: %-15s OWNER: %-15s\n", 
194                         name->addresses[i].address, name->addresses[i].owner);
195         }
196 }
197
198 /*
199   test a full replication dump from a WINS server
200 */
201 static BOOL test_wins_replication(TALLOC_CTX *mem_ctx, const char *address)
202 {
203         BOOL ret = True;
204         struct wrepl_socket *wrepl_socket;
205         NTSTATUS status;
206         int i, j;
207         struct wrepl_associate associate;
208         struct wrepl_pull_table pull_table;
209         struct wrepl_pull_names pull_names;
210
211         printf("Test one pull replication cycle\n");
212
213         wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
214         
215         printf("Setup wrepl connections\n");
216         status = wrepl_connect(wrepl_socket, NULL, address);
217         CHECK_STATUS(status, NT_STATUS_OK);
218
219         printf("Send a start association request\n");
220
221         status = wrepl_associate(wrepl_socket, &associate);
222         CHECK_STATUS(status, NT_STATUS_OK);
223
224         printf("association context: 0x%x\n", associate.out.assoc_ctx);
225
226         printf("Send a replication table query\n");
227         pull_table.in.assoc_ctx = associate.out.assoc_ctx;
228
229         status = wrepl_pull_table(wrepl_socket, mem_ctx, &pull_table);
230         if (NT_STATUS_EQUAL(NT_STATUS_NETWORK_ACCESS_DENIED,status)) {
231                 struct wrepl_packet packet;
232                 struct wrepl_request *req;
233
234                 ZERO_STRUCT(packet);
235                 packet.opcode                      = WREPL_OPCODE_BITS;
236                 packet.assoc_ctx                   = associate.out.assoc_ctx;
237                 packet.mess_type                   = WREPL_STOP_ASSOCIATION;
238                 packet.message.stop.reason         = 0;
239
240                 req = wrepl_request_send(wrepl_socket, &packet);
241                 talloc_free(req);
242
243                 printf("failed - We are not a valid pull partner for the server\n");
244                 ret = False;
245                 goto done;
246         }
247         CHECK_STATUS(status, NT_STATUS_OK);
248
249         printf("Found %d replication partners\n", pull_table.out.num_partners);
250
251         for (i=0;i<pull_table.out.num_partners;i++) {
252                 struct wrepl_wins_owner *partner = &pull_table.out.partners[i];
253                 printf("%s   max_version=%6llu   min_version=%6llu type=%d\n",
254                        partner->address, 
255                        partner->max_version, 
256                        partner->min_version, 
257                        partner->type);
258
259                 pull_names.in.assoc_ctx = associate.out.assoc_ctx;
260                 pull_names.in.partner = *partner;
261                 
262                 status = wrepl_pull_names(wrepl_socket, mem_ctx, &pull_names);
263                 CHECK_STATUS(status, NT_STATUS_OK);
264
265                 printf("Received %d names\n", pull_names.out.num_names);
266
267                 for (j=0;j<pull_names.out.num_names;j++) {
268                         display_entry(mem_ctx, &pull_names.out.names[j]);
269                 }
270         }
271
272 done:
273         printf("Close wrepl connections\n");
274         talloc_free(wrepl_socket);
275         return ret;
276 }
277
278 struct test_wrepl_conflict_conn {
279         const char *address;
280         struct wrepl_socket *pull;
281         uint32_t pull_assoc;
282
283 #define TEST_OWNER_A_ADDRESS "127.65.65.1"
284 #define TEST_ADDRESS_A_PREFIX "127.0.65"
285 #define TEST_OWNER_B_ADDRESS "127.66.66.1"
286 #define TEST_ADDRESS_B_PREFIX "127.0.66"
287
288         struct wrepl_wins_owner a, b;
289 };
290
291 static const struct wrepl_ip addresses_A_1[] = {
292         {
293         .owner  = TEST_OWNER_A_ADDRESS,
294         .ip     = TEST_ADDRESS_A_PREFIX".1"
295         }
296 };
297 static const struct wrepl_ip addresses_A_2[] = {
298         {
299         .owner  = TEST_OWNER_A_ADDRESS,
300         .ip     = TEST_ADDRESS_A_PREFIX".2"
301         }
302 };
303
304 static const struct wrepl_ip addresses_B_1[] = {
305         {
306         .owner  = TEST_OWNER_B_ADDRESS,
307         .ip     = TEST_ADDRESS_B_PREFIX".1"
308         }
309 };
310 static const struct wrepl_ip addresses_B_2[] = {
311         {
312         .owner  = TEST_OWNER_B_ADDRESS,
313         .ip     = TEST_ADDRESS_B_PREFIX".2"
314         }
315 };
316
317 static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem_ctx,
318                                                                  const char *address)
319 {
320         struct test_wrepl_conflict_conn *ctx;
321         struct wrepl_associate associate;
322         struct wrepl_pull_table pull_table;
323         NTSTATUS status;
324         uint32_t i;
325
326         ctx = talloc_zero(mem_ctx, struct test_wrepl_conflict_conn);
327         if (!ctx) return NULL;
328
329         ctx->address    = address;
330         ctx->pull       = wrepl_socket_init(ctx, NULL);
331         if (!ctx->pull) return NULL;
332
333         printf("Setup wrepl conflict pull connection\n");
334         status = wrepl_connect(ctx->pull, NULL, ctx->address);
335         if (!NT_STATUS_IS_OK(status)) return NULL;
336
337         status = wrepl_associate(ctx->pull, &associate);
338         if (!NT_STATUS_IS_OK(status)) return NULL;
339
340         ctx->pull_assoc = associate.out.assoc_ctx;
341
342         ctx->a.address          = TEST_OWNER_A_ADDRESS;
343         ctx->a.max_version      = 0;
344         ctx->a.min_version      = 0;
345         ctx->a.type             = 1;
346
347         ctx->b.address          = TEST_OWNER_B_ADDRESS;
348         ctx->b.max_version      = 0;
349         ctx->b.min_version      = 0;
350         ctx->b.type             = 1;
351
352         pull_table.in.assoc_ctx = ctx->pull_assoc;
353         status = wrepl_pull_table(ctx->pull, ctx->pull, &pull_table);
354         if (!NT_STATUS_IS_OK(status)) return NULL;
355
356         for (i=0; i < pull_table.out.num_partners; i++) {
357                 if (strcmp(TEST_OWNER_A_ADDRESS,pull_table.out.partners[i].address)==0) {
358                         ctx->a.max_version      = pull_table.out.partners[i].max_version;
359                         ctx->a.min_version      = pull_table.out.partners[i].min_version;
360                 }
361                 if (strcmp(TEST_OWNER_B_ADDRESS,pull_table.out.partners[i].address)==0) {
362                         ctx->b.max_version      = pull_table.out.partners[i].max_version;
363                         ctx->b.min_version      = pull_table.out.partners[i].min_version;               
364                 }
365         }
366
367         talloc_free(pull_table.out.partners);
368
369         return ctx;
370 }
371
372 static BOOL test_wrepl_update_one(struct test_wrepl_conflict_conn *ctx,
373                                   const struct wrepl_wins_owner *owner,
374                                   const struct wrepl_wins_name *name)
375 {
376         BOOL ret = True;
377         struct wrepl_socket *wrepl_socket;
378         struct wrepl_associate associate;
379         struct wrepl_packet update_packet, repl_send;
380         struct wrepl_table *update;
381         struct wrepl_wins_owner wrepl_wins_owners[1];
382         struct wrepl_packet *repl_recv;
383         struct wrepl_wins_owner *send_request;
384         struct wrepl_send_reply *send_reply;
385         struct wrepl_wins_name wrepl_wins_names[1];
386         uint32_t assoc_ctx;
387         NTSTATUS status;
388
389         wrepl_socket = wrepl_socket_init(ctx, NULL);
390
391         status = wrepl_connect(wrepl_socket, NULL, ctx->address);
392         CHECK_STATUS(status, NT_STATUS_OK);
393
394         status = wrepl_associate(wrepl_socket, &associate);
395         CHECK_STATUS(status, NT_STATUS_OK);
396         assoc_ctx = associate.out.assoc_ctx;
397
398         /* now send a WREPL_REPL_UPDATE message */
399         ZERO_STRUCT(update_packet);
400         update_packet.opcode                    = WREPL_OPCODE_BITS;
401         update_packet.assoc_ctx                 = assoc_ctx;
402         update_packet.mess_type                 = WREPL_REPLICATION;
403         update_packet.message.replication.command       = WREPL_REPL_UPDATE;
404         update  = &update_packet.message.replication.info.table;
405
406         update->partner_count   = ARRAY_SIZE(wrepl_wins_owners);
407         update->partners        = wrepl_wins_owners;
408         update->initiator       = "0.0.0.0";
409
410         wrepl_wins_owners[0]    = *owner;
411
412         status = wrepl_request(wrepl_socket, wrepl_socket,
413                                &update_packet, &repl_recv);
414         CHECK_STATUS(status, NT_STATUS_OK);
415         CHECK_VALUE(repl_recv->mess_type, WREPL_REPLICATION);
416         CHECK_VALUE(repl_recv->message.replication.command, WREPL_REPL_SEND_REQUEST);
417         send_request = &repl_recv->message.replication.info.owner;
418
419         ZERO_STRUCT(repl_send);
420         repl_send.opcode                        = WREPL_OPCODE_BITS;
421         repl_send.assoc_ctx                     = assoc_ctx;
422         repl_send.mess_type                     = WREPL_REPLICATION;
423         repl_send.message.replication.command   = WREPL_REPL_SEND_REPLY;
424         send_reply = &repl_send.message.replication.info.reply;
425
426         send_reply->num_names   = ARRAY_SIZE(wrepl_wins_names);
427         send_reply->names       = wrepl_wins_names;
428
429         wrepl_wins_names[0]     = *name;
430
431         status = wrepl_request(wrepl_socket, wrepl_socket,
432                                &repl_send, &repl_recv);
433         CHECK_STATUS(status, NT_STATUS_OK);
434         CHECK_VALUE(repl_recv->mess_type, WREPL_STOP_ASSOCIATION);
435         CHECK_VALUE(repl_recv->message.stop.reason, 0);
436
437 done:
438         talloc_free(wrepl_socket);
439         return ret;
440 }
441
442 static BOOL test_wrepl_is_applied(struct test_wrepl_conflict_conn *ctx,
443                                   const struct wrepl_wins_owner *owner,
444                                   const struct wrepl_wins_name *name,
445                                   BOOL expected)
446 {
447         BOOL ret = True;
448         NTSTATUS status;
449         struct wrepl_pull_names pull_names;
450
451         pull_names.in.assoc_ctx = ctx->pull_assoc;
452         pull_names.in.partner   = *owner;
453         pull_names.in.partner.min_version = pull_names.in.partner.max_version;
454                 
455         status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
456         CHECK_STATUS(status, NT_STATUS_OK);
457         CHECK_VALUE(pull_names.out.num_names, (expected?1:0));
458
459 done:
460         talloc_free(pull_names.out.names);
461         return ret;
462 }
463
464 static BOOL test_conflict_same_owner(struct test_wrepl_conflict_conn *ctx)
465 {
466         BOOL ret = True;
467         struct nbt_name name;
468         struct wrepl_wins_name wins_name1;
469         struct wrepl_wins_name wins_name2;
470         struct wrepl_wins_name *wins_name_tmp;
471         struct wrepl_wins_name *wins_name_last;
472         struct wrepl_wins_name *wins_name_cur;
473         uint32_t i,j;
474         uint8_t types[] = { 0x00, 0x1C };
475         struct {
476                 enum wrepl_name_type type;
477                 enum wrepl_name_state state;
478                 enum wrepl_name_node node;
479                 BOOL is_static;
480                 uint32_t num_ips;
481                 const struct wrepl_ip *ips;
482         } records[] = {
483                 {
484                 .type           = WREPL_TYPE_GROUP,
485                 .state          = WREPL_STATE_ACTIVE,
486                 .node           = WREPL_NODE_B,
487                 .is_static      = False,
488                 .num_ips        = ARRAY_SIZE(addresses_A_1),
489                 .ips            = addresses_A_1,
490                 },{
491                 .type           = WREPL_TYPE_UNIQUE,
492                 .state          = WREPL_STATE_ACTIVE,
493                 .node           = WREPL_NODE_B,
494                 .is_static      = False,
495                 .num_ips        = ARRAY_SIZE(addresses_A_1),
496                 .ips            = addresses_A_1,
497                 },{
498                 .type           = WREPL_TYPE_UNIQUE,
499                 .state          = WREPL_STATE_ACTIVE,
500                 .node           = WREPL_NODE_B,
501                 .is_static      = False,
502                 .num_ips        = ARRAY_SIZE(addresses_A_2),
503                 .ips            = addresses_A_2,
504                 },{
505                 .type           = WREPL_TYPE_UNIQUE,
506                 .state          = WREPL_STATE_ACTIVE,
507                 .node           = WREPL_NODE_B,
508                 .is_static      = True,
509                 .num_ips        = ARRAY_SIZE(addresses_A_1),
510                 .ips            = addresses_A_1,
511                 },{
512                 .type           = WREPL_TYPE_UNIQUE,
513                 .state          = WREPL_STATE_ACTIVE,
514                 .node           = WREPL_NODE_B,
515                 .is_static      = False,
516                 .num_ips        = ARRAY_SIZE(addresses_A_2),
517                 .ips            = addresses_A_2,
518                 },{
519                 .type           = WREPL_TYPE_SGROUP,
520                 .state          = WREPL_STATE_TOMBSTONE,
521                 .node           = WREPL_NODE_B,
522                 .is_static      = False,
523                 .num_ips        = ARRAY_SIZE(addresses_A_2),
524                 .ips            = addresses_A_2,
525                 },{
526                 .type           = WREPL_TYPE_MHOMED,
527                 .state          = WREPL_STATE_TOMBSTONE,
528                 .node           = WREPL_NODE_B,
529                 .is_static      = False,
530                 .num_ips        = ARRAY_SIZE(addresses_A_1),
531                 .ips            = addresses_A_1,
532                 },{
533                 /* the last one should always be a unique,tomstone record! */
534                 .type           = WREPL_TYPE_UNIQUE,
535                 .state          = WREPL_STATE_TOMBSTONE,
536                 .node           = WREPL_NODE_B,
537                 .is_static      = False,
538                 .num_ips        = ARRAY_SIZE(addresses_A_1),
539                 .ips            = addresses_A_1,
540                 }
541         };
542
543         if (!ctx) return False;
544
545         name.name       = "_SAME_OWNER_A";
546         name.type       = 0;
547         name.scope      = NULL;
548
549         wins_name_tmp   = NULL;
550         wins_name_last  = &wins_name2;
551         wins_name_cur   = &wins_name1;
552
553         for (j=0; ret && j < ARRAY_SIZE(types); j++) {
554                 name.type = types[j];
555                 printf("Test Replica Conflicts with same owner[%s] for %s\n",
556                         nbt_name_string(ctx, &name), ctx->a.address);
557
558                 for(i=0; ret && i < ARRAY_SIZE(records); i++) {
559                         wins_name_tmp   = wins_name_last;
560                         wins_name_last  = wins_name_cur;
561                         wins_name_cur   = wins_name_tmp;
562
563                         wins_name_cur->name     = &name;
564                         wins_name_cur->flags    = WREPL_NAME_FLAGS(records[i].type,
565                                                                    records[i].state,
566                                                                    records[i].node,
567                                                                    records[i].is_static);
568                         wins_name_cur->id       = ++ctx->a.max_version;
569                         if (wins_name_cur->flags & 2) {
570                                 wins_name_cur->addresses.addresses.num_ips = records[i].num_ips;
571                                 wins_name_cur->addresses.addresses.ips     = discard_const(records[i].ips);
572                         } else {
573                                 wins_name_cur->addresses.ip = records[i].ips[0].ip;
574                         }
575                         wins_name_cur->unknown  = "255.255.255.255";
576
577                         ret &= test_wrepl_update_one(ctx, &ctx->a,wins_name_cur);
578                         ret &= test_wrepl_is_applied(ctx, &ctx->a, wins_name_cur, True);
579                 }
580         }
581         return ret;
582 }
583
584 static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
585 {
586         BOOL ret = True;
587         struct wrepl_wins_name wins_name1;
588         struct wrepl_wins_name wins_name2;
589         struct wrepl_wins_name *wins_name_r1;
590         struct wrepl_wins_name *wins_name_r2;
591         uint32_t i;
592         struct {
593                 struct nbt_name name;
594                 struct {
595                         struct wrepl_wins_owner *owner;
596                         enum wrepl_name_type type;
597                         enum wrepl_name_state state;
598                         enum wrepl_name_node node;
599                         BOOL is_static;
600                         uint32_t num_ips;
601                         const struct wrepl_ip *ips;
602                         BOOL apply_expected;
603                 } r1, r2;
604         } records[] = {
605         /* 
606          * NOTE: the first record and the last applied one
607          *       needs to be from the same owner,
608          *       to not conflict in the next smbtorture run!!!
609          */
610
611         /* 
612          * unique,active vs. unique,active the same ip
613          * => should be replaced
614          */
615         {
616                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
617                 .r1     = {
618                         .owner          = &ctx->a,
619                         .type           = WREPL_TYPE_UNIQUE,
620                         .state          = WREPL_STATE_ACTIVE,
621                         .node           = WREPL_NODE_B,
622                         .is_static      = False,
623                         .num_ips        = ARRAY_SIZE(addresses_A_1),
624                         .ips            = addresses_A_1,
625                         .apply_expected = True
626                 },
627                 .r2     = {
628                         .owner          = &ctx->b,
629                         .type           = WREPL_TYPE_UNIQUE,
630                         .state          = WREPL_STATE_ACTIVE,
631                         .node           = WREPL_NODE_B,
632                         .is_static      = False,
633                         .num_ips        = ARRAY_SIZE(addresses_A_1),
634                         .ips            = addresses_A_1,
635                         .apply_expected = True
636                 }
637         },
638
639         /* 
640          * unique,active vs. unique,tombstone the same ips
641          * => should NOT be replaced
642          */
643         {
644                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
645                 .r1     = {
646                         .owner          = &ctx->b,
647                         .type           = WREPL_TYPE_UNIQUE,
648                         .state          = WREPL_STATE_ACTIVE,
649                         .node           = WREPL_NODE_B,
650                         .is_static      = False,
651                         .num_ips        = ARRAY_SIZE(addresses_B_1),
652                         .ips            = addresses_B_1,
653                         .apply_expected = True
654                 },
655                 .r2     = {
656                         .owner          = &ctx->a,
657                         .type           = WREPL_TYPE_UNIQUE,
658                         .state          = WREPL_STATE_TOMBSTONE,
659                         .node           = WREPL_NODE_B,
660                         .is_static      = False,
661                         .num_ips        = ARRAY_SIZE(addresses_B_1),
662                         .ips            = addresses_B_1,
663                         .apply_expected = False
664                 }
665         },
666
667         /* 
668          * unique,tombstone vs. unique,active the same ips
669          * => should NOT be replaced
670          */
671         {
672                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
673                 .r1     = {
674                         .owner          = &ctx->b,
675                         .type           = WREPL_TYPE_UNIQUE,
676                         .state          = WREPL_STATE_TOMBSTONE,
677                         .node           = WREPL_NODE_B,
678                         .is_static      = False,
679                         .num_ips        = ARRAY_SIZE(addresses_B_1),
680                         .ips            = addresses_B_1,
681                         .apply_expected = True
682                 },
683                 .r2     = {
684                         .owner          = &ctx->a,
685                         .type           = WREPL_TYPE_UNIQUE,
686                         .state          = WREPL_STATE_ACTIVE,
687                         .node           = WREPL_NODE_B,
688                         .is_static      = False,
689                         .num_ips        = ARRAY_SIZE(addresses_B_1),
690                         .ips            = addresses_B_1,
691                         .apply_expected = True
692                 }
693         },
694
695         /* 
696          * unique,tombstone vs. unique,tombstone the same ips
697          * => should be replaced
698          */
699         {
700                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
701                 .r1     = {
702                         .owner          = &ctx->a,
703                         .type           = WREPL_TYPE_UNIQUE,
704                         .state          = WREPL_STATE_TOMBSTONE,
705                         .node           = WREPL_NODE_B,
706                         .is_static      = False,
707                         .num_ips        = ARRAY_SIZE(addresses_A_1),
708                         .ips            = addresses_A_1,
709                         .apply_expected = True
710                 },
711                 .r2     = {
712                         .owner          = &ctx->b,
713                         .type           = WREPL_TYPE_UNIQUE,
714                         .state          = WREPL_STATE_TOMBSTONE,
715                         .node           = WREPL_NODE_B,
716                         .is_static      = False,
717                         .num_ips        = ARRAY_SIZE(addresses_A_1),
718                         .ips            = addresses_A_1,
719                         .apply_expected = True
720                 }
721         },
722
723         /* 
724          * unique,active vs. unique,active the different ips
725          * => should be replaced
726          */
727         {
728                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
729                 .r1     = {
730                         .owner          = &ctx->a,
731                         .type           = WREPL_TYPE_UNIQUE,
732                         .state          = WREPL_STATE_ACTIVE,
733                         .node           = WREPL_NODE_B,
734                         .is_static      = False,
735                         .num_ips        = ARRAY_SIZE(addresses_A_1),
736                         .ips            = addresses_A_1,
737                         .apply_expected = True
738                 },
739                 .r2     = {
740                         .owner          = &ctx->b,
741                         .type           = WREPL_TYPE_UNIQUE,
742                         .state          = WREPL_STATE_ACTIVE,
743                         .node           = WREPL_NODE_B,
744                         .is_static      = False,
745                         .num_ips        = ARRAY_SIZE(addresses_B_1),
746                         .ips            = addresses_B_1,
747                         .apply_expected = True
748                 }
749         },
750
751         /* 
752          * unique,active vs. unique,tombstone the different ips
753          * => should NOT be replaced
754          */
755         {
756                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
757                 .r1     = {
758                         .owner          = &ctx->b,
759                         .type           = WREPL_TYPE_UNIQUE,
760                         .state          = WREPL_STATE_ACTIVE,
761                         .node           = WREPL_NODE_B,
762                         .is_static      = False,
763                         .num_ips        = ARRAY_SIZE(addresses_B_1),
764                         .ips            = addresses_B_1,
765                         .apply_expected = True
766                 },
767                 .r2     = {
768                         .owner          = &ctx->a,
769                         .type           = WREPL_TYPE_UNIQUE,
770                         .state          = WREPL_STATE_TOMBSTONE,
771                         .node           = WREPL_NODE_B,
772                         .is_static      = False,
773                         .num_ips        = ARRAY_SIZE(addresses_A_1),
774                         .ips            = addresses_A_1,
775                         .apply_expected = False
776                 }
777         },
778
779         /* 
780          * unique,tombstone vs. unique,active the different ips
781          * => should be replaced
782          */
783         {
784                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
785                 .r1     = {
786                         .owner          = &ctx->b,
787                         .type           = WREPL_TYPE_UNIQUE,
788                         .state          = WREPL_STATE_TOMBSTONE,
789                         .node           = WREPL_NODE_B,
790                         .is_static      = False,
791                         .num_ips        = ARRAY_SIZE(addresses_B_1),
792                         .ips            = addresses_B_1,
793                         .apply_expected = True
794                 },
795                 .r2     = {
796                         .owner          = &ctx->a,
797                         .type           = WREPL_TYPE_UNIQUE,
798                         .state          = WREPL_STATE_ACTIVE,
799                         .node           = WREPL_NODE_B,
800                         .is_static      = False,
801                         .num_ips        = ARRAY_SIZE(addresses_A_1),
802                         .ips            = addresses_A_1,
803                         .apply_expected = True
804                 }
805         },
806
807         /* 
808          * unique,tombstone vs. unique,tombstone the different ips
809          * => should be replaced
810          */
811         {
812                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
813                 .r1     = {
814                         .owner          = &ctx->a,
815                         .type           = WREPL_TYPE_UNIQUE,
816                         .state          = WREPL_STATE_TOMBSTONE,
817                         .node           = WREPL_NODE_B,
818                         .is_static      = False,
819                         .num_ips        = ARRAY_SIZE(addresses_A_1),
820                         .ips            = addresses_A_1,
821                         .apply_expected = True
822                 },
823                 .r2     = {
824                         .owner          = &ctx->b,
825                         .type           = WREPL_TYPE_UNIQUE,
826                         .state          = WREPL_STATE_TOMBSTONE,
827                         .node           = WREPL_NODE_B,
828                         .is_static      = False,
829                         .num_ips        = ARRAY_SIZE(addresses_B_1),
830                         .ips            = addresses_B_1,
831                         .apply_expected = True
832                 }
833         },
834
835         /* 
836          * This should be the last record in this array,
837          * we need to make sure the we leave a tombstoned unique entry
838          * owned by OWNER_A
839          */
840         {
841                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
842                 .r1     = {
843                         .owner          = &ctx->a,
844                         .type           = WREPL_TYPE_UNIQUE,
845                         .state          = WREPL_STATE_TOMBSTONE,
846                         .node           = WREPL_NODE_B,
847                         .is_static      = False,
848                         .num_ips        = ARRAY_SIZE(addresses_A_1),
849                         .ips            = addresses_A_1,
850                         .apply_expected = True
851                 },
852                 .r2     = {
853                         .owner          = &ctx->a,
854                         .type           = WREPL_TYPE_UNIQUE,
855                         .state          = WREPL_STATE_TOMBSTONE,
856                         .node           = WREPL_NODE_B,
857                         .is_static      = False,
858                         .num_ips        = ARRAY_SIZE(addresses_A_1),
859                         .ips            = addresses_A_1,
860                         .apply_expected = True
861                 }
862         }}; /* do not add entries here, this should be the last record! */
863
864         if (!ctx) return False;
865
866         wins_name_r1    = &wins_name1;
867         wins_name_r2    = &wins_name2;
868
869         for(i=0; ret && i < ARRAY_SIZE(records); i++) {
870
871                 /*
872                  * Setup R1
873                  */
874                 wins_name_r1->name      = &records[i].name;
875                 wins_name_r1->flags     = WREPL_NAME_FLAGS(records[i].r1.type,
876                                                            records[i].r1.state,
877                                                            records[i].r1.node,
878                                                            records[i].r1.is_static);
879                 wins_name_r1->id        = ++records[i].r1.owner->max_version;
880                 if (wins_name_r1->flags & 2) {
881                         wins_name_r1->addresses.addresses.num_ips = records[i].r1.num_ips;
882                         wins_name_r1->addresses.addresses.ips     = discard_const(records[i].r1.ips);
883                 } else {
884                         wins_name_r1->addresses.ip = records[i].r1.ips[0].ip;
885                 }
886                 wins_name_r1->unknown   = "255.255.255.255";
887
888                 /* now apply R1 */
889                 ret &= test_wrepl_update_one(ctx, records[i].r1.owner, wins_name_r1);
890                 ret &= test_wrepl_is_applied(ctx, records[i].r1.owner,
891                                              wins_name_r1, records[i].r1.apply_expected);
892
893                 /*
894                  * Setup R2
895                  */
896                 wins_name_r2->name      = &records[i].name;
897                 wins_name_r2->flags     = WREPL_NAME_FLAGS(records[i].r2.type,
898                                                            records[i].r2.state,
899                                                            records[i].r2.node,
900                                                            records[i].r2.is_static);
901                 wins_name_r2->id        = ++records[i].r2.owner->max_version;
902                 if (wins_name_r2->flags & 2) {
903                         wins_name_r2->addresses.addresses.num_ips = records[i].r2.num_ips;
904                         wins_name_r2->addresses.addresses.ips     = discard_const(records[i].r2.ips);
905                 } else {
906                         wins_name_r2->addresses.ip = records[i].r2.ips[0].ip;
907                 }
908                 wins_name_r2->unknown   = "255.255.255.255";
909
910                 /* now apply R2 */
911                 ret &= test_wrepl_update_one(ctx, records[i].r2.owner, wins_name_r2);
912                 ret &= test_wrepl_is_applied(ctx, records[i].r2.owner,
913                                              wins_name_r2, records[i].r2.apply_expected);
914
915                 if (!ret) {
916                         printf("%s: failed with index: %u\n", __location__, i);
917                         return ret;
918                 }
919         }
920
921         return ret;
922 }
923
924 /*
925   test WINS replication operations
926 */
927 BOOL torture_nbt_winsreplication(void)
928 {
929         const char *address;
930         struct nbt_name name;
931         TALLOC_CTX *mem_ctx = talloc_new(NULL);
932         NTSTATUS status;
933         BOOL ret = True;
934         struct test_wrepl_conflict_conn *ctx;
935
936         make_nbt_name_server(&name, lp_parm_string(-1, "torture", "host"));
937
938         /* do an initial name resolution to find its IP */
939         status = resolve_name(&name, mem_ctx, &address, NULL);
940         if (!NT_STATUS_IS_OK(status)) {
941                 printf("Failed to resolve %s - %s\n",
942                        name.name, nt_errstr(status));
943                 talloc_free(mem_ctx);
944                 return False;
945         }
946
947         ret &= test_assoc_ctx1(mem_ctx, address);
948         ret &= test_assoc_ctx2(mem_ctx, address);
949
950         ret &= test_wins_replication(mem_ctx, address);
951
952         ctx = test_create_conflict_ctx(mem_ctx, address);
953
954         ret &= test_conflict_same_owner(ctx);
955         ret &= test_conflict_different_owner(ctx);
956
957         talloc_free(mem_ctx);
958
959         return ret;
960 }