s4-smbtorture: fix test_GetInfoLevel crash bug in RPC-DFS.
[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(tctx->ev, 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(tctx->ev, 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, tctx->ev)) {
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         union dfs_Info info;
209
210         printf("Testing GetInfo level %u on '%s'\n", level, root);
211
212         r.in.dfs_entry_path = talloc_strdup(mem_ctx, root);
213         r.in.servername = NULL;
214         r.in.sharename = NULL;
215         r.in.level = level;
216         r.out.info = &info;
217
218         status = dcerpc_dfs_GetInfo(p, mem_ctx, &r);
219         if (!NT_STATUS_IS_OK(status)) {
220                 printf("GetInfo failed - %s\n", nt_errstr(status));
221                 return false;
222         } else if (!W_ERROR_IS_OK(r.out.result) &&
223                    !W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, r.out.result)) {
224                 printf("dfs_GetInfo failed - %s\n", win_errstr(r.out.result));
225                 return false;
226         }
227
228         return true;
229 }
230
231 static bool test_GetInfo(struct dcerpc_pipe *p,
232                          TALLOC_CTX *mem_ctx,
233                          const char *root)
234 {
235         bool ret = true;
236         /* 103, 104, 105, 106 is only available on Set */
237         uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 100, 101, 102, 103, 104, 105, 106};
238         int i;
239
240         for (i=0;i<ARRAY_SIZE(levels);i++) {
241                 if (!test_GetInfoLevel(p, mem_ctx, levels[i], root)) {
242                         ret = false;
243                 }
244         }
245         return ret;
246 }
247
248 static bool test_EnumLevelEx(struct dcerpc_pipe *p,
249                              TALLOC_CTX *mem_ctx,
250                              uint16_t level,
251                              const char *dfs_name)
252 {
253         NTSTATUS status;
254         struct dfs_EnumEx rex;
255         uint32_t total=0;
256         struct dfs_EnumStruct e;
257         struct dfs_Info1 s;
258         struct dfs_EnumArray1 e1;
259         bool ret = true;
260
261         rex.in.level = level;
262         rex.in.bufsize = (uint32_t)-1;
263         rex.in.total = &total;
264         rex.in.info = &e;
265         rex.in.dfs_name = dfs_name;
266
267         e.level = rex.in.level;
268         e.e.info1 = &e1;
269         e.e.info1->count = 0;
270         e.e.info1->s = &s;
271         s.path = NULL;
272
273         printf("Testing EnumEx level %u on '%s'\n", level, dfs_name);
274
275         status = dcerpc_dfs_EnumEx(p, mem_ctx, &rex);
276         if (!NT_STATUS_IS_OK(status)) {
277                 printf("EnumEx failed - %s\n", nt_errstr(status));
278                 return false;
279         }
280
281         if (level == 1 && rex.out.total) {
282                 int i;
283                 for (i=0;i<*rex.out.total;i++) {
284                         const char *root = talloc_strdup(mem_ctx,
285                                 rex.out.info->e.info1->s[i].path);
286                         if (!test_GetInfo(p, mem_ctx, root)) {
287                                 ret = false;
288                         }
289                 }
290         }
291
292         if (level == 300 && rex.out.total) {
293                 int i,k;
294                 for (i=0;i<*rex.out.total;i++) {
295                         uint16_t levels[] = {1, 2, 3, 4, 200}; /* 300 */
296                         const char *root = talloc_strdup(mem_ctx,
297                                 rex.out.info->e.info300->s[i].dom_root);
298                         for (k=0;k<ARRAY_SIZE(levels);k++) {
299                                 if (!test_EnumLevelEx(p, mem_ctx,
300                                                       levels[k], root))
301                                 {
302                                         ret = false;
303                                 }
304                         }
305                         if (!test_GetInfo(p, mem_ctx, root)) {
306                                 ret = false;
307                         }
308                 }
309         }
310
311         return ret;
312 }
313
314
315 static bool test_EnumLevel(struct dcerpc_pipe *p,
316                            TALLOC_CTX *mem_ctx,
317                            uint16_t level)
318 {
319         NTSTATUS status;
320         struct dfs_Enum r;
321         uint32_t total=0;
322         struct dfs_EnumStruct e;
323         struct dfs_Info1 s;
324         struct dfs_EnumArray1 e1;
325         bool ret = true;
326
327         r.in.level = level;
328         r.in.bufsize = (uint32_t)-1;
329         r.in.total = &total;
330         r.in.info = &e;
331
332         e.level = r.in.level;
333         e.e.info1 = &e1;
334         e.e.info1->count = 0;
335         e.e.info1->s = &s;
336         s.path = NULL;
337
338         printf("Testing Enum level %u\n", level);
339
340         status = dcerpc_dfs_Enum(p, mem_ctx, &r);
341         if (!NT_STATUS_IS_OK(status)) {
342                 printf("Enum failed - %s\n", nt_errstr(status));
343                 return false;
344         } else if (!W_ERROR_IS_OK(r.out.result) &&
345                    !W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, r.out.result)) {
346                 printf("dfs_Enum failed - %s\n", win_errstr(r.out.result));
347                 return false;
348         }
349
350         if (level == 1 && r.out.total) {
351                 int i;
352                 for (i=0;i<*r.out.total;i++) {
353                         const char *root = r.out.info->e.info1->s[i].path;
354                         if (!test_GetInfo(p, mem_ctx, root)) {
355                                 ret = false;
356                         }
357                 }
358
359         }
360
361         return ret;
362 }
363
364
365 static bool test_Enum(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
366 {
367         bool ret = true;
368         uint16_t levels[] = {1, 2, 3, 4, 5, 6, 200, 300};
369         int i;
370
371         for (i=0;i<ARRAY_SIZE(levels);i++) {
372                 if (!test_EnumLevel(p, mem_ctx, levels[i])) {
373                         ret = false;
374                 }
375         }
376
377         return ret;
378 }
379
380 static bool test_EnumEx(struct dcerpc_pipe *p,
381                         TALLOC_CTX *mem_ctx,
382                         const char *host)
383 {
384         bool ret = true;
385         uint16_t levels[] = {1, 2, 3, 4, 5, 6, 200, 300};
386         int i;
387
388         for (i=0;i<ARRAY_SIZE(levels);i++) {
389                 if (!test_EnumLevelEx(p, mem_ctx, levels[i], host)) {
390                         ret = false;
391                 }
392         }
393
394         return ret;
395 }
396
397 static bool test_RemoveStdRoot(struct dcerpc_pipe *p,
398                                TALLOC_CTX *mem_ctx,
399                                const char *host,
400                                const char *sharename)
401 {
402         struct dfs_RemoveStdRoot r;
403         NTSTATUS status;
404
405         printf("Testing RemoveStdRoot\n");
406
407         r.in.servername = host;
408         r.in.rootshare  = sharename;
409         r.in.flags      = 0;
410
411         status = dcerpc_dfs_RemoveStdRoot(p, mem_ctx, &r);
412         if (!NT_STATUS_IS_OK(status)) {
413                 printf("RemoveStdRoot failed - %s\n", nt_errstr(status));
414                 return false;
415         } else if (!W_ERROR_IS_OK(r.out.result)) {
416                 printf("dfs_RemoveStdRoot failed - %s\n",
417                         win_errstr(r.out.result));
418                 return false;
419         }
420
421         return true;
422 }
423
424 static bool test_AddStdRoot(struct dcerpc_pipe *p,
425                             TALLOC_CTX *mem_ctx,
426                             const char *host,
427                             const char *sharename)
428 {
429         NTSTATUS status;
430         struct dfs_AddStdRoot r;
431
432         printf("Testing AddStdRoot\n");
433
434         r.in.servername = host;
435         r.in.rootshare  = sharename;
436         r.in.comment    = "standard dfs standalone DFS root created by smbtorture (dfs_AddStdRoot)";
437         r.in.flags      = 0;
438
439         status = dcerpc_dfs_AddStdRoot(p, mem_ctx, &r);
440         if (!NT_STATUS_IS_OK(status)) {
441                 printf("AddStdRoot failed - %s\n", nt_errstr(status));
442                 return false;
443         } else if (!W_ERROR_IS_OK(r.out.result)) {
444                 printf("dfs_AddStdRoot failed - %s\n",
445                         win_errstr(r.out.result));
446                 return false;
447         }
448
449         return true;
450 }
451
452 static bool test_AddStdRootForced(struct dcerpc_pipe *p,
453                                   TALLOC_CTX *mem_ctx,
454                                   const char *host,
455                                   const char *sharename)
456 {
457         NTSTATUS status;
458         struct dfs_AddStdRootForced r;
459         enum dfs_ManagerVersion version;
460
461         printf("Testing AddStdRootForced\n");
462
463         if (!test_GetManagerVersion(p, mem_ctx, &version)) {
464                 return false;
465         }
466
467         r.in.servername = host;
468         r.in.rootshare  = sharename;
469         r.in.comment    = "standard dfs forced standalone DFS root created by smbtorture (dfs_AddStdRootForced)";
470         r.in.store      = SMBTORTURE_DFS_PATHNAME;
471
472         status = dcerpc_dfs_AddStdRootForced(p, mem_ctx, &r);
473         if (!NT_STATUS_IS_OK(status)) {
474                 printf("AddStdRootForced failed - %s\n", nt_errstr(status));
475                 return false;
476         } else if (!W_ERROR_IS_OK(r.out.result)) {
477                 printf("dfs_AddStdRootForced failed - %s\n",
478                         win_errstr(r.out.result));
479                 IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(version, r.out.result);
480                 return false;
481         }
482
483         return test_RemoveStdRoot(p, mem_ctx, host, sharename);
484 }
485
486 static void test_cleanup_stdroot(struct dcerpc_pipe *p,
487                                  TALLOC_CTX *mem_ctx,
488                                  struct torture_context *tctx,
489                                  const char *host,
490                                  const char *sharename,
491                                  const char *dir)
492 {
493         struct smbcli_state *cli;
494
495         printf("Cleaning up StdRoot\n");
496
497         test_RemoveStdRoot(p, mem_ctx, host, sharename);
498         test_NetShareDel(mem_ctx, tctx, host, sharename);
499         torture_open_connection_share(mem_ctx, &cli, tctx, host, "C$", tctx->ev);
500         test_DeleteDir(cli, dir);
501         torture_close_connection(cli);
502 }
503
504 static bool test_StdRoot(struct dcerpc_pipe *p,
505                          TALLOC_CTX *mem_ctx,
506                          struct torture_context *tctx,
507                          const char *host)
508 {
509         const char *sharename = SMBTORTURE_DFS_SHARENAME;
510         const char *dir = SMBTORTURE_DFS_DIRNAME;
511         const char *path = SMBTORTURE_DFS_PATHNAME;
512         struct smbcli_state *cli;
513         bool ret = true;
514
515         printf("Testing StdRoot\n");
516
517         test_cleanup_stdroot(p, mem_ctx, tctx, host, sharename, dir);
518
519         ret &= test_CreateDir(mem_ctx, &cli, tctx, host, "C$", dir);
520         ret &= test_NetShareAdd(mem_ctx, tctx, host, sharename, path);
521         ret &= test_AddStdRoot(p, mem_ctx, host, sharename);
522         ret &= test_RemoveStdRoot(p, mem_ctx, host, sharename);
523         ret &= test_AddStdRootForced(p, mem_ctx, host, sharename);
524         ret &= test_NetShareDel(mem_ctx, tctx, host, sharename);
525         ret &= test_DeleteDir(cli, dir);
526
527         torture_close_connection(cli);
528
529         return ret;
530 }
531
532 static bool test_GetDcAddress(struct dcerpc_pipe *p,
533                               TALLOC_CTX *mem_ctx,
534                               const char *host)
535 {
536         NTSTATUS status;
537         struct dfs_GetDcAddress r;
538         uint8_t is_root = 0;
539         uint32_t ttl = 0;
540         const char *ptr;
541
542         printf("Testing GetDcAddress\n");
543
544         ptr = host;
545
546         r.in.servername = host;
547         r.in.server_fullname = r.out.server_fullname = &ptr;
548         r.in.is_root = r.out.is_root = &is_root;
549         r.in.ttl = r.out.ttl = &ttl;
550
551         status = dcerpc_dfs_GetDcAddress(p, mem_ctx, &r);
552         if (!NT_STATUS_IS_OK(status)) {
553                 printf("GetDcAddress failed - %s\n", nt_errstr(status));
554                 return false;
555         } else if (!W_ERROR_IS_OK(r.out.result)) {
556                 printf("dfs_GetDcAddress failed - %s\n",
557                         win_errstr(r.out.result));
558                 return false;
559         }
560
561         return true;
562 }
563
564 static bool test_SetDcAddress(struct dcerpc_pipe *p,
565                               TALLOC_CTX *mem_ctx,
566                               const char *host)
567 {
568         NTSTATUS status;
569         struct dfs_SetDcAddress r;
570
571         printf("Testing SetDcAddress\n");
572
573         r.in.servername = host;
574         r.in.server_fullname = host;
575         r.in.flags = 0;
576         r.in.ttl = 1000;
577
578         status = dcerpc_dfs_SetDcAddress(p, mem_ctx, &r);
579         if (!NT_STATUS_IS_OK(status)) {
580                 printf("SetDcAddress failed - %s\n", nt_errstr(status));
581                 return false;
582         } else if (!W_ERROR_IS_OK(r.out.result)) {
583                 printf("dfs_SetDcAddress failed - %s\n",
584                         win_errstr(r.out.result));
585                 return false;
586         }
587
588         return true;
589 }
590
591 static bool test_DcAddress(struct dcerpc_pipe *p,
592                            TALLOC_CTX *mem_ctx,
593                            const char *host)
594 {
595         if (!test_GetDcAddress(p, mem_ctx, host)) {
596                 return false;
597         }
598
599         if (!test_SetDcAddress(p, mem_ctx, host)) {
600                 return false;
601         }
602
603         return true;
604 }
605
606 static bool test_FlushFtTable(struct dcerpc_pipe *p,
607                               TALLOC_CTX *mem_ctx,
608                               const char *host,
609                               const char *sharename)
610 {
611         NTSTATUS status;
612         struct dfs_FlushFtTable r;
613         enum dfs_ManagerVersion version;
614
615         printf("Testing FlushFtTable\n");
616
617         if (!test_GetManagerVersion(p, mem_ctx, &version)) {
618                 return false;
619         }
620
621         r.in.servername = host;
622         r.in.rootshare = sharename;
623
624         status = dcerpc_dfs_FlushFtTable(p, mem_ctx, &r);
625         if (!NT_STATUS_IS_OK(status)) {
626                 printf("FlushFtTable failed - %s\n", nt_errstr(status));
627                 return false;
628         } else if (!W_ERROR_IS_OK(r.out.result)) {
629                 printf("dfs_FlushFtTable failed - %s\n",
630                         win_errstr(r.out.result));
631                 IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(version, r.out.result);
632                 return false;
633         }
634
635         return true;
636 }
637
638 static bool test_FtRoot(struct dcerpc_pipe *p,
639                         TALLOC_CTX *mem_ctx,
640                         const char *host)
641 {
642         const char *sharename = SMBTORTURE_DFS_SHARENAME;
643
644         return test_FlushFtTable(p, mem_ctx, host, sharename);
645 }
646
647 bool torture_rpc_dfs(struct torture_context *torture)
648 {
649         NTSTATUS status;
650         struct dcerpc_pipe *p;
651         bool ret = true;
652         enum dfs_ManagerVersion version;
653         const char *host = torture_setting_string(torture, "host", NULL);
654
655         status = torture_rpc_connection(torture, &p, &ndr_table_netdfs);
656         torture_assert_ntstatus_ok(torture, status, "Unable to connect");
657
658         ret &= test_GetManagerVersion(p, torture, &version);
659         ret &= test_ManagerInitialize(p, torture, host);
660         ret &= test_Enum(p, torture);
661         ret &= test_EnumEx(p, torture, host);
662         ret &= test_StdRoot(p, torture, torture, host);
663         ret &= test_FtRoot(p, torture, host);
664         ret &= test_DcAddress(p, torture, host);
665
666         return ret;
667 }