r10967: move the function in the order they are used
[abartlet/samba.git/.git] / source4 / torture / nbt / winsreplication.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    WINS replication testing
5
6    Copyright (C) Andrew Tridgell 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "libcli/nbt/libnbt.h"
25 #include "libcli/wrepl/winsrepl.h"
26
27 #define CHECK_STATUS(status, correct) do { \
28         if (!NT_STATUS_EQUAL(status, correct)) { \
29                 printf("(%s) Incorrect status %s - should be %s\n", \
30                        __location__, nt_errstr(status), nt_errstr(correct)); \
31                 ret = False; \
32                 goto done; \
33         }} while (0)
34
35 #define CHECK_VALUE(v, correct) do { \
36         if ((v) != (correct)) { \
37                 printf("(%s) Incorrect value %s=%d - should be %d\n", \
38                        __location__, #v, v, correct); \
39                 ret = False; \
40                 goto done; \
41         }} while (0)
42
43 /*
44   test how assoc_ctx's are only usable on the connection
45   they are created on.
46 */
47 static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address)
48 {
49         BOOL ret = True;
50         struct wrepl_request *req;
51         struct wrepl_socket *wrepl_socket1;
52         struct wrepl_associate associate1;
53         struct wrepl_socket *wrepl_socket2;
54         struct wrepl_associate associate2;
55         struct wrepl_pull_table pull_table;
56         struct wrepl_packet *rep_packet;
57         struct wrepl_associate_stop assoc_stop;
58         NTSTATUS status;
59
60         if (!lp_parm_bool(-1, "torture", "dangerous", False)) {
61                 printf("winsrepl: cross connection assoc_ctx usage disabled - enable dangerous tests to use\n");
62                 return True;
63         }
64
65         printf("Test if assoc_ctx is only valid on the conection it was created on\n");
66
67         wrepl_socket1 = wrepl_socket_init(mem_ctx, NULL);
68         wrepl_socket2 = wrepl_socket_init(mem_ctx, NULL);
69
70         printf("Setup 2 wrepl connections\n");
71         status = wrepl_connect(wrepl_socket1, NULL, address);
72         CHECK_STATUS(status, NT_STATUS_OK);
73
74         status = wrepl_connect(wrepl_socket2, NULL, address);
75         CHECK_STATUS(status, NT_STATUS_OK);
76
77         printf("Send a start association request (conn1)\n");
78         status = wrepl_associate(wrepl_socket1, &associate1);
79         CHECK_STATUS(status, NT_STATUS_OK);
80
81         printf("association context (conn1): 0x%x\n", associate1.out.assoc_ctx);
82
83         printf("Send a start association request (conn2)\n");
84         status = wrepl_associate(wrepl_socket2, &associate2);
85         CHECK_STATUS(status, NT_STATUS_OK);
86
87         printf("association context (conn2): 0x%x\n", associate2.out.assoc_ctx);
88
89         printf("Send a replication table query, with assoc 1 (conn2), the anwser should be on conn1\n");
90         pull_table.in.assoc_ctx = associate1.out.assoc_ctx;
91         req = wrepl_pull_table_send(wrepl_socket2, &pull_table);
92         req->send_only = True;
93         status = wrepl_request_recv(req, mem_ctx, &rep_packet);
94         CHECK_STATUS(status, NT_STATUS_OK);
95
96         printf("Send a association request (conn2), to make sure the last request was ignored\n");
97         status = wrepl_associate(wrepl_socket2, &associate2);
98         CHECK_STATUS(status, NT_STATUS_OK);
99
100         printf("Send a replication table query, with invalid assoc (conn1), receive answer from conn2\n");
101         pull_table.in.assoc_ctx = 0;
102         req = wrepl_pull_table_send(wrepl_socket1, &pull_table);
103         status = wrepl_request_recv(req, mem_ctx, &rep_packet);
104         CHECK_STATUS(status, NT_STATUS_OK);
105
106         printf("Send a association request (conn1), to make sure the last request was handled correct\n");
107         status = wrepl_associate(wrepl_socket1, &associate2);
108         CHECK_STATUS(status, NT_STATUS_OK);
109
110         assoc_stop.in.assoc_ctx = associate1.out.assoc_ctx;
111         assoc_stop.in.reason    = 4;
112         printf("Send a association stop request (conn1), reson: %u\n", assoc_stop.in.reason);
113         status = wrepl_associate_stop(wrepl_socket1, &assoc_stop);
114         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
115
116         assoc_stop.in.assoc_ctx = associate2.out.assoc_ctx;
117         assoc_stop.in.reason    = 0;
118         printf("Send a association stop request (conn2), reson: %u\n", assoc_stop.in.reason);
119         status = wrepl_associate_stop(wrepl_socket2, &assoc_stop);
120         CHECK_STATUS(status, NT_STATUS_OK);
121
122 done:
123         printf("Close 2 wrepl connections\n");
124         talloc_free(wrepl_socket1);
125         talloc_free(wrepl_socket2);
126         return ret;
127 }
128
129 /*
130   test if we always get back the same assoc_ctx
131 */
132 static BOOL test_assoc_ctx2(TALLOC_CTX *mem_ctx, const char *address)
133 {
134         BOOL ret = True;
135         struct wrepl_socket *wrepl_socket;
136         struct wrepl_associate associate;
137         uint32_t assoc_ctx1;
138         NTSTATUS status;
139
140         printf("Test if we always get back the same assoc_ctx\n");
141
142         wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
143         
144         printf("Setup wrepl connections\n");
145         status = wrepl_connect(wrepl_socket, NULL, address);
146         CHECK_STATUS(status, NT_STATUS_OK);
147
148
149         printf("Send 1st start association request\n");
150         status = wrepl_associate(wrepl_socket, &associate);
151         CHECK_STATUS(status, NT_STATUS_OK);
152         assoc_ctx1 = associate.out.assoc_ctx;
153         printf("1st association context: 0x%x\n", associate.out.assoc_ctx);
154
155         printf("Send 2nd start association request\n");
156         status = wrepl_associate(wrepl_socket, &associate);
157         CHECK_VALUE(associate.out.assoc_ctx, assoc_ctx1);
158         CHECK_STATUS(status, NT_STATUS_OK);
159         printf("2nd association context: 0x%x\n", associate.out.assoc_ctx);
160
161         printf("Send 3rd 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("3rd association context: 0x%x\n", associate.out.assoc_ctx);
166
167 done:
168         printf("Close wrepl connections\n");
169         talloc_free(wrepl_socket);
170         return ret;
171 }
172
173
174 /*
175   display a replication entry
176 */
177 static void display_entry(TALLOC_CTX *mem_ctx, struct wrepl_name *name)
178 {
179         int i;
180
181         printf("%s\n", nbt_name_string(mem_ctx, &name->name));
182         printf("\tTYPE:%u STATE:%u NODE:%u STATIC:%u VERSION_ID: %llu\n",
183                 name->type, name->state, name->node, name->is_static, name->version_id);
184         printf("\tRAW_FLAGS: 0x%08X OWNER: %-15s\n",
185                 name->raw_flags, name->owner);
186         for (i=0;i<name->num_addresses;i++) {
187                 printf("\tADDR: %-15s OWNER: %-15s\n", 
188                         name->addresses[i].address, name->addresses[i].owner);
189         }
190 }
191
192 /*
193   test a full replication dump from a WINS server
194 */
195 static BOOL test_wins_replication(TALLOC_CTX *mem_ctx, const char *address)
196 {
197         BOOL ret = True;
198         struct wrepl_socket *wrepl_socket;
199         NTSTATUS status;
200         int i, j;
201         struct wrepl_associate associate;
202         struct wrepl_pull_table pull_table;
203         struct wrepl_pull_names pull_names;
204
205         printf("Test one pull replication cycle\n");
206
207         wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
208         
209         printf("Setup wrepl connections\n");
210         status = wrepl_connect(wrepl_socket, NULL, address);
211         CHECK_STATUS(status, NT_STATUS_OK);
212
213         printf("Send a start association request\n");
214
215         status = wrepl_associate(wrepl_socket, &associate);
216         CHECK_STATUS(status, NT_STATUS_OK);
217
218         printf("association context: 0x%x\n", associate.out.assoc_ctx);
219
220         printf("Send a replication table query\n");
221         pull_table.in.assoc_ctx = associate.out.assoc_ctx;
222
223         status = wrepl_pull_table(wrepl_socket, mem_ctx, &pull_table);
224         if (NT_STATUS_EQUAL(NT_STATUS_NETWORK_ACCESS_DENIED,status)) {
225                 struct wrepl_packet packet;
226                 struct wrepl_request *req;
227
228                 ZERO_STRUCT(packet);
229                 packet.opcode                      = WREPL_OPCODE_BITS;
230                 packet.assoc_ctx                   = associate.out.assoc_ctx;
231                 packet.mess_type                   = WREPL_STOP_ASSOCIATION;
232                 packet.message.stop.reason         = 0;
233
234                 req = wrepl_request_send(wrepl_socket, &packet);
235                 talloc_free(req);
236
237                 printf("failed - We are not a valid pull partner for the server\n");
238                 ret = False;
239                 goto done;
240         }
241         CHECK_STATUS(status, NT_STATUS_OK);
242
243         printf("Found %d replication partners\n", pull_table.out.num_partners);
244
245         for (i=0;i<pull_table.out.num_partners;i++) {
246                 struct wrepl_wins_owner *partner = &pull_table.out.partners[i];
247                 printf("%s   max_version=%6llu   min_version=%6llu type=%d\n",
248                        partner->address, 
249                        partner->max_version, 
250                        partner->min_version, 
251                        partner->type);
252
253                 pull_names.in.assoc_ctx = associate.out.assoc_ctx;
254                 pull_names.in.partner = *partner;
255                 
256                 status = wrepl_pull_names(wrepl_socket, mem_ctx, &pull_names);
257                 CHECK_STATUS(status, NT_STATUS_OK);
258
259                 printf("Received %d names\n", pull_names.out.num_names);
260
261                 for (j=0;j<pull_names.out.num_names;j++) {
262                         display_entry(mem_ctx, &pull_names.out.names[j]);
263                 }
264         }
265
266 done:
267         printf("Close wrepl connections\n");
268         talloc_free(wrepl_socket);
269         return ret;
270 }
271
272 struct test_wrepl_conflict_conn {
273         const char *address;
274         struct wrepl_socket *pull;
275         uint32_t pull_assoc;
276
277 #define TEST_OWNER_A_ADDRESS "127.65.65.1"
278 #define TEST_ADDRESS_A_PREFIX "127.0.65"
279 #define TEST_OWNER_B_ADDRESS "127.66.66.1"
280 #define TEST_ADDRESS_B_PREFIX "127.0.66"
281
282         struct wrepl_wins_owner a, b;
283 };
284
285 static const struct wrepl_ip addresses_A_1[] = {
286         {
287         .owner  = TEST_OWNER_A_ADDRESS,
288         .ip     = TEST_ADDRESS_A_PREFIX".1"
289         }
290 };
291 static const struct wrepl_ip addresses_A_2[] = {
292         {
293         .owner  = TEST_OWNER_A_ADDRESS,
294         .ip     = TEST_ADDRESS_A_PREFIX".2"
295         }
296 };
297
298 static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem_ctx,
299                                                                  const char *address)
300 {
301         struct test_wrepl_conflict_conn *ctx;
302         struct wrepl_associate associate;
303         struct wrepl_pull_table pull_table;
304         NTSTATUS status;
305         uint32_t i;
306
307         ctx = talloc_zero(mem_ctx, struct test_wrepl_conflict_conn);
308         if (!ctx) return NULL;
309
310         ctx->address    = address;
311         ctx->pull       = wrepl_socket_init(ctx, NULL);
312         if (!ctx->pull) return NULL;
313
314         printf("Setup wrepl conflict pull connection\n");
315         status = wrepl_connect(ctx->pull, NULL, ctx->address);
316         if (!NT_STATUS_IS_OK(status)) return NULL;
317
318         status = wrepl_associate(ctx->pull, &associate);
319         if (!NT_STATUS_IS_OK(status)) return NULL;
320
321         ctx->pull_assoc = associate.out.assoc_ctx;
322
323         ctx->a.address          = TEST_OWNER_A_ADDRESS;
324         ctx->a.max_version      = 0;
325         ctx->a.min_version      = 0;
326         ctx->a.type             = 1;
327
328         ctx->b.address          = TEST_OWNER_B_ADDRESS;
329         ctx->b.max_version      = 0;
330         ctx->b.min_version      = 0;
331         ctx->b.type             = 1;
332
333         pull_table.in.assoc_ctx = ctx->pull_assoc;
334         status = wrepl_pull_table(ctx->pull, ctx->pull, &pull_table);
335         if (!NT_STATUS_IS_OK(status)) return NULL;
336
337         for (i=0; i < pull_table.out.num_partners; i++) {
338                 if (strcmp(TEST_OWNER_A_ADDRESS,pull_table.out.partners[i].address)==0) {
339                         ctx->a.max_version      = pull_table.out.partners[i].max_version;
340                         ctx->a.min_version      = pull_table.out.partners[i].min_version;
341                 }
342                 if (strcmp(TEST_OWNER_B_ADDRESS,pull_table.out.partners[i].address)==0) {
343                         ctx->b.max_version      = pull_table.out.partners[i].max_version;
344                         ctx->b.min_version      = pull_table.out.partners[i].min_version;               
345                 }
346         }
347
348         talloc_free(pull_table.out.partners);
349
350         return ctx;
351 }
352
353 static BOOL test_wrepl_update_one_A(struct test_wrepl_conflict_conn *ctx,
354                                     const struct wrepl_wins_name *name)
355 {
356         BOOL ret = True;
357         struct wrepl_socket *wrepl_socket;
358         struct wrepl_associate associate;
359         struct wrepl_packet update_packet, repl_send;
360         struct wrepl_table *update;
361         struct wrepl_wins_owner wrepl_wins_owners[1];
362         struct wrepl_packet *repl_recv;
363         struct wrepl_wins_owner *send_request;
364         struct wrepl_send_reply *send_reply;
365         struct wrepl_wins_name wrepl_wins_names[1];
366         uint32_t assoc_ctx;
367         NTSTATUS status;
368
369         wrepl_socket = wrepl_socket_init(ctx, NULL);
370
371         status = wrepl_connect(wrepl_socket, NULL, ctx->address);
372         CHECK_STATUS(status, NT_STATUS_OK);
373
374         status = wrepl_associate(wrepl_socket, &associate);
375         CHECK_STATUS(status, NT_STATUS_OK);
376         assoc_ctx = associate.out.assoc_ctx;
377
378         /* now send a WREPL_REPL_UPDATE message */
379         ZERO_STRUCT(update_packet);
380         update_packet.opcode                    = WREPL_OPCODE_BITS;
381         update_packet.assoc_ctx                 = assoc_ctx;
382         update_packet.mess_type                 = WREPL_REPLICATION;
383         update_packet.message.replication.command       = WREPL_REPL_UPDATE;
384         update  = &update_packet.message.replication.info.table;
385
386         update->partner_count   = ARRAY_SIZE(wrepl_wins_owners);
387         update->partners        = wrepl_wins_owners;
388         update->initiator       = "0.0.0.0";
389
390         wrepl_wins_owners[0]    = ctx->a;
391
392         status = wrepl_request(wrepl_socket, wrepl_socket,
393                                &update_packet, &repl_recv);
394         CHECK_STATUS(status, NT_STATUS_OK);
395         CHECK_VALUE(repl_recv->mess_type, WREPL_REPLICATION);
396         CHECK_VALUE(repl_recv->message.replication.command, WREPL_REPL_SEND_REQUEST);
397         send_request = &repl_recv->message.replication.info.owner;
398
399         ZERO_STRUCT(repl_send);
400         repl_send.opcode                        = WREPL_OPCODE_BITS;
401         repl_send.assoc_ctx                     = assoc_ctx;
402         repl_send.mess_type                     = WREPL_REPLICATION;
403         repl_send.message.replication.command   = WREPL_REPL_SEND_REPLY;
404         send_reply = &repl_send.message.replication.info.reply;
405
406         send_reply->num_names   = ARRAY_SIZE(wrepl_wins_names);
407         send_reply->names       = wrepl_wins_names;
408
409         wrepl_wins_names[0]     = *name;
410
411         status = wrepl_request(wrepl_socket, wrepl_socket,
412                                &repl_send, &repl_recv);
413         CHECK_STATUS(status, NT_STATUS_OK);
414         CHECK_VALUE(repl_recv->mess_type, WREPL_STOP_ASSOCIATION);
415         CHECK_VALUE(repl_recv->message.stop.reason, 0);
416
417 done:
418         talloc_free(wrepl_socket);
419         return ret;
420 }
421
422 static BOOL test_wrepl_is_applied_A(struct test_wrepl_conflict_conn *ctx,
423                                     const struct wrepl_wins_name *name)
424 {
425         BOOL ret = True;
426         NTSTATUS status;
427         struct wrepl_pull_names pull_names;
428
429         ctx->a.min_version      = ctx->a.max_version;
430
431         pull_names.in.assoc_ctx = ctx->pull_assoc;
432         pull_names.in.partner   = ctx->a;
433                 
434         status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
435         CHECK_STATUS(status, NT_STATUS_OK);
436         CHECK_VALUE(pull_names.out.num_names, 1);
437
438 done:
439         talloc_free(pull_names.out.names);
440         return ret;
441 }
442
443 static BOOL test_conflict_same_owner(struct test_wrepl_conflict_conn *ctx)
444 {
445         BOOL ret = True;
446         struct nbt_name name;
447         struct wrepl_wins_name wins_name1;
448         struct wrepl_wins_name wins_name2;
449         struct wrepl_wins_name *wins_name_tmp;
450         struct wrepl_wins_name *wins_name_last;
451         struct wrepl_wins_name *wins_name_cur;
452         uint32_t i,j;
453         uint8_t types[] = { 0x00, 0x1C };
454         struct {
455                 enum wrepl_name_type type;
456                 enum wrepl_name_state state;
457                 enum wrepl_name_node node;
458                 BOOL is_static;
459                 uint32_t num_ips;
460                 const struct wrepl_ip *ips;
461         } records[] = {
462                 {
463                 .type           = WREPL_TYPE_GROUP,
464                 .state          = WREPL_STATE_ACTIVE,
465                 .node           = WREPL_NODE_B,
466                 .is_static      = False,
467                 .num_ips        = ARRAY_SIZE(addresses_A_1),
468                 .ips            = addresses_A_1,
469                 },{
470                 .type           = WREPL_TYPE_UNIQUE,
471                 .state          = WREPL_STATE_ACTIVE,
472                 .node           = WREPL_NODE_B,
473                 .is_static      = False,
474                 .num_ips        = ARRAY_SIZE(addresses_A_1),
475                 .ips            = addresses_A_1,
476                 },{
477                 .type           = WREPL_TYPE_UNIQUE,
478                 .state          = WREPL_STATE_ACTIVE,
479                 .node           = WREPL_NODE_B,
480                 .is_static      = False,
481                 .num_ips        = ARRAY_SIZE(addresses_A_2),
482                 .ips            = addresses_A_2,
483                 },{
484                 .type           = WREPL_TYPE_SGROUP,
485                 .state          = WREPL_STATE_TOMBSTONE,
486                 .node           = WREPL_NODE_B,
487                 .is_static      = False,
488                 .num_ips        = ARRAY_SIZE(addresses_A_2),
489                 .ips            = addresses_A_2,
490                 },{
491                 .type           = WREPL_TYPE_MHOMED,
492                 .state          = WREPL_STATE_TOMBSTONE,
493                 .node           = WREPL_NODE_B,
494                 .is_static      = False,
495                 .num_ips        = ARRAY_SIZE(addresses_A_1),
496                 .ips            = addresses_A_1,
497                 },{
498                 /* the last one should always be a tomstone record! */
499                 .type           = WREPL_TYPE_UNIQUE,
500                 .state          = WREPL_STATE_TOMBSTONE,
501                 .node           = WREPL_NODE_B,
502                 .is_static      = False,
503                 .num_ips        = ARRAY_SIZE(addresses_A_1),
504                 .ips            = addresses_A_1,
505                 }
506         };
507
508         if (!ctx) return False;
509
510         name.name       = "_SAME_OWNER_A";
511         name.type       = 0;
512         name.scope      = NULL;
513
514         wins_name_tmp   = NULL;
515         wins_name_last  = &wins_name2;
516         wins_name_cur   = &wins_name1;
517
518         for (j=0; ret && j < ARRAY_SIZE(types); j++) {
519                 name.type = types[j];
520                 printf("Test Replica Conflicts with same owner[%s] for %s\n",
521                         nbt_name_string(ctx, &name), ctx->a.address);
522
523                 for(i=0; ret && i < ARRAY_SIZE(records); i++) {
524                         wins_name_tmp   = wins_name_last;
525                         wins_name_last  = wins_name_cur;
526                         wins_name_cur   = wins_name_tmp;
527
528                         wins_name_cur->name     = &name;
529                         wins_name_cur->flags    = WREPL_NAME_FLAGS(records[i].type,
530                                                                    records[i].state,
531                                                                    records[i].node,
532                                                                    records[i].is_static);
533                         wins_name_cur->id       = ++ctx->a.max_version;
534                         if (wins_name_cur->flags & 2) {
535                                 wins_name_cur->addresses.addresses.num_ips = records[i].num_ips;
536                                 wins_name_cur->addresses.addresses.ips     = discard_const(records[i].ips);
537                         } else {
538                                 wins_name_cur->addresses.ip = records[i].ips[0].ip;
539                         }
540                         wins_name_cur->unknown  = "255.255.255.255";
541
542                         ret &= test_wrepl_update_one_A(ctx, wins_name_cur);
543                         ret &= test_wrepl_is_applied_A(ctx, wins_name_cur);
544                 }
545         }
546         return ret;
547 }
548
549 /*
550   test WINS replication operations
551 */
552 BOOL torture_nbt_winsreplication(void)
553 {
554         const char *address;
555         struct nbt_name name;
556         TALLOC_CTX *mem_ctx = talloc_new(NULL);
557         NTSTATUS status;
558         BOOL ret = True;
559         struct test_wrepl_conflict_conn *ctx;
560
561         make_nbt_name_server(&name, lp_parm_string(-1, "torture", "host"));
562
563         /* do an initial name resolution to find its IP */
564         status = resolve_name(&name, mem_ctx, &address, NULL);
565         if (!NT_STATUS_IS_OK(status)) {
566                 printf("Failed to resolve %s - %s\n",
567                        name.name, nt_errstr(status));
568                 talloc_free(mem_ctx);
569                 return False;
570         }
571
572         ret &= test_assoc_ctx1(mem_ctx, address);
573         ret &= test_assoc_ctx2(mem_ctx, address);
574
575         ret &= test_wins_replication(mem_ctx, address);
576
577         ctx = test_create_conflict_ctx(mem_ctx, address);
578
579         ret &= test_conflict_same_owner(ctx);
580
581         talloc_free(mem_ctx);
582
583         return ret;
584 }