Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into 4-0-local
[ira/wip.git] / source4 / torture / rpc / dfs.c
1 /*
2    Unix SMB/CIFS implementation.
3    test suite for rpc dfs operations
4
5    Copyright (C) Andrew Tridgell 2003
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "torture/torture.h"
24 #include "torture/rpc/rpc.h"
25 #include "librpc/gen_ndr/ndr_dfs_c.h"
26 #include "librpc/gen_ndr/ndr_srvsvc_c.h"
27 #include "libnet/libnet.h"
28 #include "libcli/raw/libcliraw.h"
29 #include "torture/util.h"
30 #include "libcli/libcli.h"
31 #include "lib/cmdline/popt_common.h"
32
33 #define SMBTORTURE_DFS_SHARENAME "smbtorture_dfs_share"
34 #define SMBTORTURE_DFS_DIRNAME "\\smbtorture_dfs_dir"
35 #define SMBTORTURE_DFS_PATHNAME "C:"SMBTORTURE_DFS_DIRNAME
36
37 #define IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(x,y)\
38         if (x == DFS_MANAGER_VERSION_W2K3) {\
39                 if (!W_ERROR_EQUAL(y,WERR_NOT_SUPPORTED)) {\
40                         printf("expected WERR_NOT_SUPPORTED\n");\
41                         return false;\
42                 }\
43                 return true;\
44         }\
45
46 static bool test_NetShareAdd(TALLOC_CTX *mem_ctx,
47                              struct torture_context *tctx,
48                              const char *host,
49                              const char *sharename,
50                              const char *dir)
51 {
52         NTSTATUS status;
53         struct srvsvc_NetShareInfo2 i;
54         struct libnet_context* libnetctx;
55         struct libnet_AddShare r;
56
57         printf("Creating share %s\n", sharename);
58
59         if (!(libnetctx = libnet_context_init(NULL, tctx->lp_ctx))) {
60                 return false;
61         }
62
63         libnetctx->cred = cmdline_credentials;
64
65         i.name                  = sharename;
66         i.type                  = STYPE_DISKTREE;
67         i.path                  = dir;
68         i.max_users             = (uint32_t) -1;
69         i.comment               = "created by smbtorture";
70         i.password              = NULL;
71         i.permissions           = 0x0;
72         i.current_users         = 0x0;
73
74         r.level                 = 2;
75         r.in.server_name        = host;
76         r.in.share              = i;
77
78         status = libnet_AddShare(libnetctx, mem_ctx, &r);
79         if (!NT_STATUS_IS_OK(status)) {
80                 d_printf("Failed to add new share: %s (%s)\n",
81                         nt_errstr(status), r.out.error_string);
82                 return false;
83         }
84
85         return true;
86 }
87
88 static bool test_NetShareDel(TALLOC_CTX *mem_ctx,
89                              struct torture_context *tctx,
90                              const char *host,
91                              const char *sharename)
92 {
93         NTSTATUS status;
94         struct libnet_context* libnetctx;
95         struct libnet_DelShare r;
96
97         printf("Deleting share %s\n", sharename);
98
99         if (!(libnetctx = libnet_context_init(NULL, tctx->lp_ctx))) {
100                 return false;
101         }
102
103         libnetctx->cred = cmdline_credentials;
104
105         r.in.share_name         = sharename;
106         r.in.server_name        = host;
107
108         status = libnet_DelShare(libnetctx, mem_ctx, &r);
109         if (!NT_STATUS_IS_OK(status)) {
110                 d_printf("Failed to delete share: %s (%s)\n",
111                         nt_errstr(status), r.out.error_string);
112                 return false;
113         }
114
115         return true;
116 }
117
118 static bool test_CreateDir(TALLOC_CTX *mem_ctx,
119                            struct smbcli_state **cli,
120                            struct torture_context *tctx,
121                            const char *host,
122                            const char *share,
123                            const char *dir)
124 {
125         printf("Creating directory %s\n", dir);
126
127         if (!torture_open_connection_share(mem_ctx, cli, tctx, host, share, NULL)) {
128                 return false;
129         }
130
131         if (!torture_setup_dir(*cli, dir)) {
132                 return false;
133         }
134
135         return true;
136 }
137
138 static bool test_DeleteDir(struct smbcli_state *cli,
139                            const char *dir)
140 {
141         printf("Deleting directory %s\n", dir);
142
143         if (smbcli_deltree(cli->tree, dir) == -1) {
144                 printf("Unable to delete dir %s - %s\n", dir,
145                         smbcli_errstr(cli->tree));
146                 return false;
147         }
148
149         return true;
150 }
151
152 static bool test_GetManagerVersion(struct dcerpc_pipe *p,
153                                    TALLOC_CTX *mem_ctx,
154                                    enum dfs_ManagerVersion *version)
155 {
156         NTSTATUS status;
157         struct dfs_GetManagerVersion r;
158
159         r.out.version = version;
160
161         status = dcerpc_dfs_GetManagerVersion(p, mem_ctx, &r);
162         if (!NT_STATUS_IS_OK(status)) {
163                 printf("GetManagerVersion failed - %s\n", nt_errstr(status));
164                 return false;
165         }
166
167         return true;
168 }
169
170 static bool test_ManagerInitialize(struct dcerpc_pipe *p,
171                                    TALLOC_CTX *mem_ctx,
172                                    const char *host)
173 {
174         NTSTATUS status;
175         enum dfs_ManagerVersion version;
176         struct dfs_ManagerInitialize r;
177
178         printf("Testing ManagerInitialize\n");
179
180         if (!test_GetManagerVersion(p, mem_ctx, &version)) {
181                 return false;
182         }
183
184         r.in.servername = host;
185         r.in.flags = 0;
186
187         status = dcerpc_dfs_ManagerInitialize(p, mem_ctx, &r);
188         if (!NT_STATUS_IS_OK(status)) {
189                 printf("ManagerInitialize failed - %s\n", nt_errstr(status));
190                 return false;
191         } else if (!W_ERROR_IS_OK(r.out.result)) {
192                 printf("dfs_ManagerInitialize failed - %s\n",
193                         win_errstr(r.out.result));
194                 IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(version, r.out.result);
195                 return false;
196         }
197
198         return true;
199 }
200
201 static bool test_GetInfoLevel(struct dcerpc_pipe *p,
202                               TALLOC_CTX *mem_ctx,
203                               uint16_t level,
204                               const char *root)
205 {
206         NTSTATUS status;
207         struct dfs_GetInfo r;
208
209         printf("Testing GetInfo level %u on '%s'\n", level, root);
210
211         r.in.dfs_entry_path = talloc_strdup(mem_ctx, root);
212         r.in.servername = NULL;
213         r.in.sharename = NULL;
214         r.in.level = level;
215
216         status = dcerpc_dfs_GetInfo(p, mem_ctx, &r);
217         if (!NT_STATUS_IS_OK(status)) {
218                 printf("GetInfo failed - %s\n", nt_errstr(status));
219                 return false;
220         } else if (!W_ERROR_IS_OK(r.out.result) &&
221                    !W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, r.out.result)) {
222                 printf("dfs_GetInfo failed - %s\n", win_errstr(r.out.result));
223                 return false;
224         }
225
226         return true;
227 }
228
229 static bool test_GetInfo(struct dcerpc_pipe *p,
230                          TALLOC_CTX *mem_ctx,
231                          const char *root)
232 {
233         bool ret = true;
234         /* 103, 104, 105, 106 is only available on Set */
235         uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 100, 101, 102, 103, 104, 105, 106};
236         int i;
237
238         for (i=0;i<ARRAY_SIZE(levels);i++) {
239                 if (!test_GetInfoLevel(p, mem_ctx, levels[i], root)) {
240                         ret = false;
241                 }
242         }
243         return ret;
244 }
245
246 static bool test_EnumLevelEx(struct dcerpc_pipe *p,
247                              TALLOC_CTX *mem_ctx,
248                              uint16_t level,
249                              const char *dfs_name)
250 {
251         NTSTATUS status;
252         struct dfs_EnumEx rex;
253         uint32_t total=0;
254         struct dfs_EnumStruct e;
255         struct dfs_Info1 s;
256         struct dfs_EnumArray1 e1;
257         bool ret = true;
258
259         rex.in.level = level;
260         rex.in.bufsize = (uint32_t)-1;
261         rex.in.total = &total;
262         rex.in.info = &e;
263         rex.in.dfs_name = dfs_name;
264
265         e.level = rex.in.level;
266         e.e.info1 = &e1;
267         e.e.info1->count = 0;
268         e.e.info1->s = &s;
269         s.path = NULL;
270
271         printf("Testing EnumEx level %u on '%s'\n", level, dfs_name);
272
273         status = dcerpc_dfs_EnumEx(p, mem_ctx, &rex);
274         if (!NT_STATUS_IS_OK(status)) {
275                 printf("EnumEx failed - %s\n", nt_errstr(status));
276                 return false;
277         }
278
279         if (level == 1 && rex.out.total) {
280                 int i;
281                 for (i=0;i<*rex.out.total;i++) {
282                         const char *root = talloc_strdup(mem_ctx,
283                                 rex.out.info->e.info1->s[i].path);
284                         if (!test_GetInfo(p, mem_ctx, root)) {
285                                 ret = false;
286                         }
287                 }
288         }
289
290         if (level == 300 && rex.out.total) {
291                 int i,k;
292                 for (i=0;i<*rex.out.total;i++) {
293                         uint16_t levels[] = {1, 2, 3, 4, 200}; /* 300 */
294                         const char *root = talloc_strdup(mem_ctx,
295                                 rex.out.info->e.info300->s[i].dom_root);
296                         for (k=0;k<ARRAY_SIZE(levels);k++) {
297                                 if (!test_EnumLevelEx(p, mem_ctx,
298                                                       levels[k], root))
299                                 {
300                                         ret = false;
301                                 }
302                         }
303                         if (!test_GetInfo(p, mem_ctx, root)) {
304                                 ret = false;
305                         }
306                 }
307         }
308
309         return ret;
310 }
311
312
313 static bool test_EnumLevel(struct dcerpc_pipe *p,
314                            TALLOC_CTX *mem_ctx,
315                            uint16_t level)
316 {
317         NTSTATUS status;
318         struct dfs_Enum r;
319         uint32_t total=0;
320         struct dfs_EnumStruct e;
321         struct dfs_Info1 s;
322         struct dfs_EnumArray1 e1;
323         bool ret = true;
324
325         r.in.level = level;
326         r.in.bufsize = (uint32_t)-1;
327         r.in.total = &total;
328         r.in.info = &e;
329
330         e.level = r.in.level;
331         e.e.info1 = &e1;
332         e.e.info1->count = 0;
333         e.e.info1->s = &s;
334         s.path = NULL;
335
336         printf("Testing Enum level %u\n", level);
337
338         status = dcerpc_dfs_Enum(p, mem_ctx, &r);
339         if (!NT_STATUS_IS_OK(status)) {
340                 printf("Enum failed - %s\n", nt_errstr(status));
341                 return false;
342         } else if (!W_ERROR_IS_OK(r.out.result) &&
343                    !W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, r.out.result)) {
344                 printf("dfs_Enum failed - %s\n", win_errstr(r.out.result));
345                 return false;
346         }
347
348         if (level == 1 && r.out.total) {
349                 int i;
350                 for (i=0;i<*r.out.total;i++) {
351                         const char *root = r.out.info->e.info1->s[i].path;
352                         if (!test_GetInfo(p, mem_ctx, root)) {
353                                 ret = false;
354                         }
355                 }
356
357         }
358
359         return ret;
360 }
361
362
363 static bool test_Enum(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
364 {
365         bool ret = true;
366         uint16_t levels[] = {1, 2, 3, 4, 5, 6, 200, 300};
367         int i;
368
369         for (i=0;i<ARRAY_SIZE(levels);i++) {
370                 if (!test_EnumLevel(p, mem_ctx, levels[i])) {
371                         ret = false;
372                 }
373         }
374
375         return ret;
376 }
377
378 static bool test_EnumEx(struct dcerpc_pipe *p,
379                         TALLOC_CTX *mem_ctx,
380                         const char *host)
381 {
382         bool ret = true;
383         uint16_t levels[] = {1, 2, 3, 4, 5, 6, 200, 300};
384         int i;
385
386         for (i=0;i<ARRAY_SIZE(levels);i++) {
387                 if (!test_EnumLevelEx(p, mem_ctx, levels[i], host)) {
388                         ret = false;
389                 }
390         }
391
392         return ret;
393 }
394
395 static bool test_RemoveStdRoot(struct dcerpc_pipe *p,
396                                TALLOC_CTX *mem_ctx,
397                                const char *host,
398                                const char *sharename)
399 {
400         struct dfs_RemoveStdRoot r;
401         NTSTATUS status;
402
403         printf("Testing RemoveStdRoot\n");
404
405         r.in.servername = host;
406         r.in.rootshare  = sharename;
407         r.in.flags      = 0;
408
409         status = dcerpc_dfs_RemoveStdRoot(p, mem_ctx, &r);
410         if (!NT_STATUS_IS_OK(status)) {
411                 printf("RemoveStdRoot failed - %s\n", nt_errstr(status));
412                 return false;
413         } else if (!W_ERROR_IS_OK(r.out.result)) {
414                 printf("dfs_RemoveStdRoot failed - %s\n",
415                         win_errstr(r.out.result));
416                 return false;
417         }
418
419         return true;
420 }
421
422 static bool test_AddStdRoot(struct dcerpc_pipe *p,
423                             TALLOC_CTX *mem_ctx,
424                             const char *host,
425                             const char *sharename)
426 {
427         NTSTATUS status;
428         struct dfs_AddStdRoot r;
429
430         printf("Testing AddStdRoot\n");
431
432         r.in.servername = host;
433         r.in.rootshare  = sharename;
434         r.in.comment    = "standard dfs standalone DFS root created by smbtorture (dfs_AddStdRoot)";
435         r.in.flags      = 0;
436
437         status = dcerpc_dfs_AddStdRoot(p, mem_ctx, &r);
438         if (!NT_STATUS_IS_OK(status)) {
439                 printf("AddStdRoot failed - %s\n", nt_errstr(status));
440                 return false;
441         } else if (!W_ERROR_IS_OK(r.out.result)) {
442                 printf("dfs_AddStdRoot failed - %s\n",
443                         win_errstr(r.out.result));
444                 return false;
445         }
446
447         return true;
448 }
449
450 static bool test_AddStdRootForced(struct dcerpc_pipe *p,
451                                   TALLOC_CTX *mem_ctx,
452                                   const char *host,
453                                   const char *sharename)
454 {
455         NTSTATUS status;
456         struct dfs_AddStdRootForced r;
457         enum dfs_ManagerVersion version;
458
459         printf("Testing AddStdRootForced\n");
460
461         if (!test_GetManagerVersion(p, mem_ctx, &version)) {
462                 return false;
463         }
464
465         r.in.servername = host;
466         r.in.rootshare  = sharename;
467         r.in.comment    = "standard dfs forced standalone DFS root created by smbtorture (dfs_AddStdRootForced)";
468         r.in.store      = SMBTORTURE_DFS_PATHNAME;
469
470         status = dcerpc_dfs_AddStdRootForced(p, mem_ctx, &r);
471         if (!NT_STATUS_IS_OK(status)) {
472                 printf("AddStdRootForced failed - %s\n", nt_errstr(status));
473                 return false;
474         } else if (!W_ERROR_IS_OK(r.out.result)) {
475                 printf("dfs_AddStdRootForced failed - %s\n",
476                         win_errstr(r.out.result));
477                 IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(version, r.out.result);
478                 return false;
479         }
480
481         return test_RemoveStdRoot(p, mem_ctx, host, sharename);
482 }
483
484 static void test_cleanup_stdroot(struct dcerpc_pipe *p,
485                                  TALLOC_CTX *mem_ctx,
486                                  struct torture_context *tctx,
487                                  const char *host,
488                                  const char *sharename,
489                                  const char *dir)
490 {
491         struct smbcli_state *cli;
492
493         printf("Cleaning up StdRoot\n");
494
495         test_RemoveStdRoot(p, mem_ctx, host, sharename);
496         test_NetShareDel(mem_ctx, tctx, host, sharename);
497         torture_open_connection_share(mem_ctx, &cli, tctx, host, "C$", NULL);
498         test_DeleteDir(cli, dir);
499         torture_close_connection(cli);
500 }
501
502 static bool test_StdRoot(struct dcerpc_pipe *p,
503                          TALLOC_CTX *mem_ctx,
504                          struct torture_context *tctx,
505                          const char *host)
506 {
507         const char *sharename = SMBTORTURE_DFS_SHARENAME;
508         const char *dir = SMBTORTURE_DFS_DIRNAME;
509         const char *path = SMBTORTURE_DFS_PATHNAME;
510         struct smbcli_state *cli;
511         bool ret = true;
512
513         printf("Testing StdRoot\n");
514
515         test_cleanup_stdroot(p, mem_ctx, tctx, host, sharename, dir);
516
517         ret &= test_CreateDir(mem_ctx, &cli, tctx, host, "C$", dir);
518         ret &= test_NetShareAdd(mem_ctx, tctx, host, sharename, path);
519         ret &= test_AddStdRoot(p, mem_ctx, host, sharename);
520         ret &= test_RemoveStdRoot(p, mem_ctx, host, sharename);
521         ret &= test_AddStdRootForced(p, mem_ctx, host, sharename);
522         ret &= test_NetShareDel(mem_ctx, tctx, host, sharename);
523         ret &= test_DeleteDir(cli, dir);
524
525         torture_close_connection(cli);
526
527         return ret;
528 }
529
530 static bool test_GetDcAddress(struct dcerpc_pipe *p,
531                               TALLOC_CTX *mem_ctx,
532                               const char *host)
533 {
534         NTSTATUS status;
535         struct dfs_GetDcAddress r;
536         uint8_t is_root = 0;
537         uint32_t ttl = 0;
538         const char *ptr;
539
540         printf("Testing GetDcAddress\n");
541
542         ptr = host;
543
544         r.in.servername = host;
545         r.in.server_fullname = r.out.server_fullname = &ptr;
546         r.in.is_root = r.out.is_root = &is_root;
547         r.in.ttl = r.out.ttl = &ttl;
548
549         status = dcerpc_dfs_GetDcAddress(p, mem_ctx, &r);
550         if (!NT_STATUS_IS_OK(status)) {
551                 printf("GetDcAddress failed - %s\n", nt_errstr(status));
552                 return false;
553         } else if (!W_ERROR_IS_OK(r.out.result)) {
554                 printf("dfs_GetDcAddress failed - %s\n",
555                         win_errstr(r.out.result));
556                 return false;
557         }
558
559         return true;
560 }
561
562 static bool test_SetDcAddress(struct dcerpc_pipe *p,
563                               TALLOC_CTX *mem_ctx,
564                               const char *host)
565 {
566         NTSTATUS status;
567         struct dfs_SetDcAddress r;
568
569         printf("Testing SetDcAddress\n");
570
571         r.in.servername = host;
572         r.in.server_fullname = host;
573         r.in.flags = 0;
574         r.in.ttl = 1000;
575
576         status = dcerpc_dfs_SetDcAddress(p, mem_ctx, &r);
577         if (!NT_STATUS_IS_OK(status)) {
578                 printf("SetDcAddress failed - %s\n", nt_errstr(status));
579                 return false;
580         } else if (!W_ERROR_IS_OK(r.out.result)) {
581                 printf("dfs_SetDcAddress failed - %s\n",
582                         win_errstr(r.out.result));
583                 return false;
584         }
585
586         return true;
587 }
588
589 static bool test_DcAddress(struct dcerpc_pipe *p,
590                            TALLOC_CTX *mem_ctx,
591                            const char *host)
592 {
593         if (!test_GetDcAddress(p, mem_ctx, host)) {
594                 return false;
595         }
596
597         if (!test_SetDcAddress(p, mem_ctx, host)) {
598                 return false;
599         }
600
601         return true;
602 }
603
604 static bool test_FlushFtTable(struct dcerpc_pipe *p,
605                               TALLOC_CTX *mem_ctx,
606                               const char *host,
607                               const char *sharename)
608 {
609         NTSTATUS status;
610         struct dfs_FlushFtTable r;
611         enum dfs_ManagerVersion version;
612
613         printf("Testing FlushFtTable\n");
614
615         if (!test_GetManagerVersion(p, mem_ctx, &version)) {
616                 return false;
617         }
618
619         r.in.servername = host;
620         r.in.rootshare = sharename;
621
622         status = dcerpc_dfs_FlushFtTable(p, mem_ctx, &r);
623         if (!NT_STATUS_IS_OK(status)) {
624                 printf("FlushFtTable failed - %s\n", nt_errstr(status));
625                 return false;
626         } else if (!W_ERROR_IS_OK(r.out.result)) {
627                 printf("dfs_FlushFtTable failed - %s\n",
628                         win_errstr(r.out.result));
629                 IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(version, r.out.result);
630                 return false;
631         }
632
633         return true;
634 }
635
636 static bool test_FtRoot(struct dcerpc_pipe *p,
637                         TALLOC_CTX *mem_ctx,
638                         const char *host)
639 {
640         const char *sharename = SMBTORTURE_DFS_SHARENAME;
641
642         return test_FlushFtTable(p, mem_ctx, host, sharename);
643 }
644
645 bool torture_rpc_dfs(struct torture_context *torture)
646 {
647         NTSTATUS status;
648         struct dcerpc_pipe *p;
649         bool ret = true;
650         enum dfs_ManagerVersion version;
651         const char *host = torture_setting_string(torture, "host", NULL);
652
653         status = torture_rpc_connection(torture, &p, &ndr_table_netdfs);
654         torture_assert_ntstatus_ok(torture, status, "Unable to connect");
655
656         ret &= test_GetManagerVersion(p, torture, &version);
657         ret &= test_ManagerInitialize(p, torture, host);
658         ret &= test_Enum(p, torture);
659         ret &= test_EnumEx(p, torture, host);
660         ret &= test_StdRoot(p, torture, torture, host);
661         ret &= test_FtRoot(p, torture, host);
662         ret &= test_DcAddress(p, torture, host);
663
664         return ret;
665 }