libcli: move ioctl function field defs to smb_constants
[rusty/samba.git] / source4 / torture / util_smb.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester utility functions
4    Copyright (C) Andrew Tridgell 2003
5    Copyright (C) Jelmer Vernooij 2006
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, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "lib/cmdline/popt_common.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "../libcli/smb/smb_constants.h"
26 #include "libcli/libcli.h"
27 #include "system/filesys.h"
28 #include "system/shmem.h"
29 #include "system/wait.h"
30 #include "system/time.h"
31 #include "torture/torture.h"
32 #include "../lib/util/dlinklist.h"
33 #include "libcli/resolve/resolve.h"
34 #include "param/param.h"
35 #include "libcli/security/security.h"
36 #include "libcli/util/clilsa.h"
37 #include "torture/util.h"
38
39
40 /**
41   setup a directory ready for a test
42 */
43 _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
44 {
45         smb_raw_exit(cli->session);
46         if (smbcli_deltree(cli->tree, dname) == -1 ||
47             NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
48                 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
49                 return false;
50         }
51         return true;
52 }
53
54 /*
55   create a directory, returning a handle to it
56 */
57 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
58 {
59         NTSTATUS status;
60         union smb_open io;
61         TALLOC_CTX *mem_ctx;
62
63         mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
64
65         io.generic.level = RAW_OPEN_NTCREATEX;
66         io.ntcreatex.in.root_fid.fnum = 0;
67         io.ntcreatex.in.flags = 0;
68         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
69         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
70         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
71         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
72         io.ntcreatex.in.alloc_size = 0;
73         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
74         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
75         io.ntcreatex.in.security_flags = 0;
76         io.ntcreatex.in.fname = dname;
77
78         status = smb_raw_open(tree, mem_ctx, &io);
79         talloc_free(mem_ctx);
80
81         if (NT_STATUS_IS_OK(status)) {
82                 *fnum = io.ntcreatex.out.file.fnum;
83         }
84
85         return status;
86 }
87
88
89 /**
90   sometimes we need a fairly complex file to work with, so we can test
91   all possible attributes. 
92 */
93 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
94 {
95         int fnum;
96         char buf[7] = "abc";
97         union smb_setfileinfo setfile;
98         union smb_fileinfo fileinfo;
99         time_t t = (time(NULL) & ~1);
100         NTSTATUS status;
101
102         smbcli_unlink(cli->tree, fname);
103         fnum = smbcli_nt_create_full(cli->tree, fname, 0, 
104                                      SEC_RIGHTS_FILE_ALL,
105                                      FILE_ATTRIBUTE_NORMAL,
106                                      NTCREATEX_SHARE_ACCESS_DELETE|
107                                      NTCREATEX_SHARE_ACCESS_READ|
108                                      NTCREATEX_SHARE_ACCESS_WRITE, 
109                                      NTCREATEX_DISP_OVERWRITE_IF,
110                                      0, 0);
111         if (fnum == -1) return -1;
112
113         smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
114
115         if (strchr(fname, ':') == NULL) {
116                 /* setup some EAs */
117                 setfile.generic.level = RAW_SFILEINFO_EA_SET;
118                 setfile.generic.in.file.fnum = fnum;
119                 setfile.ea_set.in.num_eas = 2;  
120                 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
121                 setfile.ea_set.in.eas[0].flags = 0;
122                 setfile.ea_set.in.eas[0].name.s = "EAONE";
123                 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
124                 setfile.ea_set.in.eas[1].flags = 0;
125                 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
126                 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
127                 status = smb_raw_setfileinfo(cli->tree, &setfile);
128                 if (!NT_STATUS_IS_OK(status)) {
129                         printf("Failed to setup EAs\n");
130                 }
131         }
132
133         /* make sure all the timestamps aren't the same */
134         ZERO_STRUCT(setfile);
135         setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
136         setfile.generic.in.file.fnum = fnum;
137
138         unix_to_nt_time(&setfile.basic_info.in.create_time,
139             t + 9*30*24*60*60);
140         unix_to_nt_time(&setfile.basic_info.in.access_time,
141             t + 6*30*24*60*60);
142         unix_to_nt_time(&setfile.basic_info.in.write_time,
143             t + 3*30*24*60*60);
144
145         status = smb_raw_setfileinfo(cli->tree, &setfile);
146         if (!NT_STATUS_IS_OK(status)) {
147                 printf("Failed to setup file times - %s\n", nt_errstr(status));
148         }
149
150         /* make sure all the timestamps aren't the same */
151         fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
152         fileinfo.generic.in.file.fnum = fnum;
153
154         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
155         if (!NT_STATUS_IS_OK(status)) {
156                 printf("Failed to query file times - %s\n", nt_errstr(status));
157         }
158
159         if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
160                 printf("create_time not setup correctly\n");
161         }
162         if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
163                 printf("access_time not setup correctly\n");
164         }
165         if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
166                 printf("write_time not setup correctly\n");
167         }
168
169         return fnum;
170 }
171
172
173 /*
174   sometimes we need a fairly complex directory to work with, so we can test
175   all possible attributes. 
176 */
177 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
178 {
179         int fnum;
180         union smb_setfileinfo setfile;
181         union smb_fileinfo fileinfo;
182         time_t t = (time(NULL) & ~1);
183         NTSTATUS status;
184
185         smbcli_deltree(cli->tree, dname);
186         fnum = smbcli_nt_create_full(cli->tree, dname, 0, 
187                                      SEC_RIGHTS_DIR_ALL,
188                                      FILE_ATTRIBUTE_DIRECTORY,
189                                      NTCREATEX_SHARE_ACCESS_READ|
190                                      NTCREATEX_SHARE_ACCESS_WRITE, 
191                                      NTCREATEX_DISP_OPEN_IF,
192                                      NTCREATEX_OPTIONS_DIRECTORY, 0);
193         if (fnum == -1) return -1;
194
195         if (strchr(dname, ':') == NULL) {
196                 /* setup some EAs */
197                 setfile.generic.level = RAW_SFILEINFO_EA_SET;
198                 setfile.generic.in.file.fnum = fnum;
199                 setfile.ea_set.in.num_eas = 2;  
200                 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
201                 setfile.ea_set.in.eas[0].flags = 0;
202                 setfile.ea_set.in.eas[0].name.s = "EAONE";
203                 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
204                 setfile.ea_set.in.eas[1].flags = 0;
205                 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
206                 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
207                 status = smb_raw_setfileinfo(cli->tree, &setfile);
208                 if (!NT_STATUS_IS_OK(status)) {
209                         printf("Failed to setup EAs\n");
210                 }
211         }
212
213         /* make sure all the timestamps aren't the same */
214         ZERO_STRUCT(setfile);
215         setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
216         setfile.generic.in.file.fnum = fnum;
217
218         unix_to_nt_time(&setfile.basic_info.in.create_time,
219             t + 9*30*24*60*60);
220         unix_to_nt_time(&setfile.basic_info.in.access_time,
221             t + 6*30*24*60*60);
222         unix_to_nt_time(&setfile.basic_info.in.write_time,
223             t + 3*30*24*60*60);
224
225         status = smb_raw_setfileinfo(cli->tree, &setfile);
226         if (!NT_STATUS_IS_OK(status)) {
227                 printf("Failed to setup file times - %s\n", nt_errstr(status));
228         }
229
230         /* make sure all the timestamps aren't the same */
231         fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
232         fileinfo.generic.in.file.fnum = fnum;
233
234         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
235         if (!NT_STATUS_IS_OK(status)) {
236                 printf("Failed to query file times - %s\n", nt_errstr(status));
237         }
238
239         if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
240                 printf("create_time not setup correctly\n");
241         }
242         if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
243                 printf("access_time not setup correctly\n");
244         }
245         if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
246                 printf("write_time not setup correctly\n");
247         }
248
249         return fnum;
250 }
251
252
253
254 /* return a pointer to a anonymous shared memory segment of size "size"
255    which will persist across fork() but will disappear when all processes
256    exit 
257
258    The memory is not zeroed 
259
260    This function uses system5 shared memory. It takes advantage of a property
261    that the memory is not destroyed if it is attached when the id is removed
262    */
263 void *shm_setup(int size)
264 {
265         int shmid;
266         void *ret;
267
268 #ifdef __QNXNTO__
269         shmid = shm_open("private", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
270         if (shmid == -1) {
271                 printf("can't get shared memory\n");
272                 exit(1);
273         }
274         shm_unlink("private");
275         if (ftruncate(shmid, size) == -1) {
276                 printf("can't set shared memory size\n");
277                 exit(1);
278         }
279         ret = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0);
280         if (ret == MAP_FAILED) {
281                 printf("can't map shared memory\n");
282                 exit(1);
283         }
284 #else
285         shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
286         if (shmid == -1) {
287                 printf("can't get shared memory\n");
288                 exit(1);
289         }
290         ret = (void *)shmat(shmid, 0, 0);
291         if (!ret || ret == (void *)-1) {
292                 printf("can't attach to shared memory\n");
293                 return NULL;
294         }
295         /* the following releases the ipc, but note that this process
296            and all its children will still have access to the memory, its
297            just that the shmid is no longer valid for other shm calls. This
298            means we don't leave behind lots of shm segments after we exit 
299
300            See Stevens "advanced programming in unix env" for details
301            */
302         shmctl(shmid, IPC_RMID, 0);
303 #endif
304         
305         return ret;
306 }
307
308
309 /**
310   check that a wire string matches the flags specified 
311   not 100% accurate, but close enough for testing
312 */
313 bool wire_bad_flags(struct smb_wire_string *str, int flags, 
314                     struct smbcli_transport *transport)
315 {
316         bool server_unicode;
317         int len;
318         if (!str || !str->s) return true;
319         len = strlen(str->s);
320         if (flags & STR_TERMINATE) len++;
321
322         server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
323         if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
324                 server_unicode = false;
325         }
326
327         if ((flags & STR_UNICODE) || server_unicode) {
328                 len *= 2;
329         } else if (flags & STR_TERMINATE_ASCII) {
330                 len++;
331         }
332         if (str->private_length != len) {
333                 printf("Expected wire_length %d but got %d for '%s'\n", 
334                        len, str->private_length, str->s);
335                 return true;
336         }
337         return false;
338 }
339
340 /*
341   dump a all_info QFILEINFO structure
342 */
343 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
344 {
345         d_printf("\tcreate_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
346         d_printf("\taccess_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
347         d_printf("\twrite_time:     %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
348         d_printf("\tchange_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
349         d_printf("\tattrib:         0x%x\n", finfo->all_info.out.attrib);
350         d_printf("\talloc_size:     %llu\n", (long long)finfo->all_info.out.alloc_size);
351         d_printf("\tsize:           %llu\n", (long long)finfo->all_info.out.size);
352         d_printf("\tnlink:          %u\n", finfo->all_info.out.nlink);
353         d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
354         d_printf("\tdirectory:      %u\n", finfo->all_info.out.directory);
355         d_printf("\tea_size:        %u\n", finfo->all_info.out.ea_size);
356         d_printf("\tfname:          '%s'\n", finfo->all_info.out.fname.s);
357 }
358
359 /*
360   dump file infor by name
361 */
362 void torture_all_info(struct smbcli_tree *tree, const char *fname)
363 {
364         TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
365         union smb_fileinfo finfo;
366         NTSTATUS status;
367
368         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
369         finfo.generic.in.file.path = fname;
370         status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
371         if (!NT_STATUS_IS_OK(status)) {
372                 d_printf("%s - %s\n", fname, nt_errstr(status));
373                 return;
374         }
375
376         d_printf("%s:\n", fname);
377         dump_all_info(mem_ctx, &finfo);
378         talloc_free(mem_ctx);
379 }
380
381
382 /*
383   set a attribute on a file
384 */
385 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
386 {
387         union smb_setfileinfo sfinfo;
388         NTSTATUS status;
389
390         ZERO_STRUCT(sfinfo.basic_info.in);
391         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
392         sfinfo.basic_info.in.file.path = fname;
393         sfinfo.basic_info.in.attrib = attrib;
394         status = smb_raw_setpathinfo(tree, &sfinfo);
395         return NT_STATUS_IS_OK(status);
396 }
397
398
399 /*
400   set a file descriptor as sparse
401 */
402 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
403 {
404         union smb_ioctl nt;
405         NTSTATUS status;
406         TALLOC_CTX *mem_ctx;
407
408         mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
409         if (!mem_ctx) {
410                 return NT_STATUS_NO_MEMORY;
411         }
412
413         nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
414         nt.ntioctl.in.function = FSCTL_SET_SPARSE;
415         nt.ntioctl.in.file.fnum = fnum;
416         nt.ntioctl.in.fsctl = true;
417         nt.ntioctl.in.filter = 0;
418         nt.ntioctl.in.max_data = 0;
419         nt.ntioctl.in.blob = data_blob(NULL, 0);
420
421         status = smb_raw_ioctl(tree, mem_ctx, &nt);
422
423         talloc_free(mem_ctx);
424
425         return status;
426 }
427
428 /*
429   check that an EA has the right value 
430 */
431 NTSTATUS torture_check_ea(struct smbcli_state *cli, 
432                           const char *fname, const char *eaname, const char *value)
433 {
434         union smb_fileinfo info;
435         NTSTATUS status;
436         struct ea_name ea;
437         TALLOC_CTX *mem_ctx = talloc_new(cli);
438
439         info.ea_list.level = RAW_FILEINFO_EA_LIST;
440         info.ea_list.in.file.path = fname;
441         info.ea_list.in.num_names = 1;
442         info.ea_list.in.ea_names = &ea;
443
444         ea.name.s = eaname;
445
446         status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
447         if (!NT_STATUS_IS_OK(status)) {
448                 talloc_free(mem_ctx);
449                 return status;
450         }
451
452         if (info.ea_list.out.num_eas != 1) {
453                 printf("Expected 1 ea in ea_list\n");
454                 talloc_free(mem_ctx);
455                 return NT_STATUS_EA_CORRUPT_ERROR;
456         }
457
458         if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
459                 printf("Expected ea '%s' not '%s' in ea_list\n",
460                        eaname, info.ea_list.out.eas[0].name.s);
461                 talloc_free(mem_ctx);
462                 return NT_STATUS_EA_CORRUPT_ERROR;
463         }
464
465         if (value == NULL) {
466                 if (info.ea_list.out.eas[0].value.length != 0) {
467                         printf("Expected zero length ea for %s\n", eaname);
468                         talloc_free(mem_ctx);
469                         return NT_STATUS_EA_CORRUPT_ERROR;
470                 }
471                 talloc_free(mem_ctx);
472                 return NT_STATUS_OK;
473         }
474
475         if (strlen(value) == info.ea_list.out.eas[0].value.length &&
476             memcmp(value, info.ea_list.out.eas[0].value.data,
477                    info.ea_list.out.eas[0].value.length) == 0) {
478                 talloc_free(mem_ctx);
479                 return NT_STATUS_OK;
480         }
481
482         printf("Expected value '%s' not '%*.*s' for ea %s\n",
483                value, 
484                (int)info.ea_list.out.eas[0].value.length,
485                (int)info.ea_list.out.eas[0].value.length,
486                info.ea_list.out.eas[0].value.data,
487                eaname);
488
489         talloc_free(mem_ctx);
490
491         return NT_STATUS_EA_CORRUPT_ERROR;
492 }
493
494 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
495                                    struct smbcli_state **c, 
496                                    struct torture_context *tctx,
497                                    const char *hostname, 
498                                    const char *sharename,
499                                    struct tevent_context *ev)
500 {
501         NTSTATUS status;
502
503         struct smbcli_options options;
504         struct smbcli_session_options session_options;
505
506         lpcfg_smbcli_options(tctx->lp_ctx, &options);
507         lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
508
509         options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
510         options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
511
512         status = smbcli_full_connection(mem_ctx, c, hostname, 
513                                         lpcfg_smb_ports(tctx->lp_ctx),
514                                         sharename, NULL,
515                                         lpcfg_socket_options(tctx->lp_ctx),
516                                         cmdline_credentials, 
517                                         lpcfg_resolve_context(tctx->lp_ctx),
518                                         ev, &options, &session_options,
519                                         lpcfg_gensec_settings(tctx, tctx->lp_ctx));
520         if (!NT_STATUS_IS_OK(status)) {
521                 printf("Failed to open connection - %s\n", nt_errstr(status));
522                 return false;
523         }
524
525         return true;
526 }
527
528 _PUBLIC_ bool torture_get_conn_index(int conn_index,
529                                      TALLOC_CTX *mem_ctx,
530                                      struct torture_context *tctx,
531                                      char **host, char **share)
532 {
533         char **unc_list = NULL;
534         int num_unc_names = 0;
535         const char *p;
536
537         (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
538         (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
539         
540         p = torture_setting_string(tctx, "unclist", NULL);
541         if (!p) {
542                 return true;
543         }
544
545         unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
546         if (!unc_list || num_unc_names <= 0) {
547                 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
548                 return false;
549         }
550
551         p = unc_list[conn_index % num_unc_names];
552         if (p[0] != '/' && p[0] != '\\') {
553                 /* allow UNC lists of hosts */
554                 (*host) = talloc_strdup(mem_ctx, p);
555         } else if (!smbcli_parse_unc(p, mem_ctx, host, share)) {
556                 DEBUG(0, ("Failed to parse UNC name %s\n",
557                           unc_list[conn_index % num_unc_names]));
558                 return false;
559         }
560
561         talloc_free(unc_list);
562         return true;
563 }
564
565
566
567 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
568                                          int conn_index,
569                                          struct torture_context *tctx,
570                                          struct tevent_context *ev)
571 {
572         char *host, *share;
573         bool ret;
574
575         if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
576                 return false;
577         }
578
579         ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
580         talloc_free(host);
581         talloc_free(share);
582
583         return ret;
584 }
585
586 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
587 {
588         return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
589 }
590
591
592
593 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
594 {
595         bool ret = true;
596         if (!c) return true;
597         if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
598                 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
599                 ret = false;
600         }
601         talloc_free(c);
602         return ret;
603 }
604
605
606 /* check if the server produced the expected error code */
607 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c, 
608                  uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
609 {
610         NTSTATUS status;
611         
612         status = smbcli_nt_error(c->tree);
613         if (NT_STATUS_IS_DOS(status)) {
614                 int classnum, num;
615                 classnum = NT_STATUS_DOS_CLASS(status);
616                 num = NT_STATUS_DOS_CODE(status);
617                 if (eclass != classnum || ecode != num) {
618                         printf("unexpected error code %s\n", nt_errstr(status));
619                         printf(" expected %s or %s (at %s)\n", 
620                                nt_errstr(NT_STATUS_DOS(eclass, ecode)), 
621                                nt_errstr(nterr), location);
622                         return false;
623                 }
624         } else {
625                 if (!NT_STATUS_EQUAL(nterr, status)) {
626                         printf("unexpected error code %s\n", nt_errstr(status));
627                         printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
628                         return false;
629                 }
630         }
631
632         return true;
633 }
634
635 static struct smbcli_state *current_cli;
636 static int procnum; /* records process count number when forking */
637
638 static void sigcont(int sig)
639 {
640 }
641
642 double torture_create_procs(struct torture_context *tctx, 
643                                                         bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
644 {
645         int i, status;
646         volatile pid_t *child_status;
647         volatile bool *child_status_out;
648         int synccount;
649         int tries = 8;
650         int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
651         double start_time_limit = 10 + (torture_nprocs * 1.5);
652         struct timeval tv;
653
654         *result = true;
655
656         synccount = 0;
657
658         signal(SIGCONT, sigcont);
659
660         child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
661         if (!child_status) {
662                 printf("Failed to setup shared memory\n");
663                 return -1;
664         }
665
666         child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
667         if (!child_status_out) {
668                 printf("Failed to setup result status shared memory\n");
669                 return -1;
670         }
671
672         for (i = 0; i < torture_nprocs; i++) {
673                 child_status[i] = 0;
674                 child_status_out[i] = true;
675         }
676
677         tv = timeval_current();
678
679         for (i=0;i<torture_nprocs;i++) {
680                 procnum = i;
681                 if (fork() == 0) {
682                         char *myname;
683
684                         pid_t mypid = getpid();
685                         srandom(((int)mypid) ^ ((int)time(NULL)));
686
687                         if (asprintf(&myname, "CLIENT%d", i) == -1) {
688                                 printf("asprintf failed\n");
689                                 return -1;
690                         }
691                         lpcfg_set_cmdline(tctx->lp_ctx, "netbios name", myname);
692                         free(myname);
693
694
695                         while (1) {
696                                 if (torture_open_connection(&current_cli, tctx, i)) {
697                                         break;
698                                 }
699                                 if (tries-- == 0) {
700                                         printf("pid %d failed to start\n", (int)getpid());
701                                         _exit(1);
702                                 }
703                                 smb_msleep(100);        
704                         }
705
706                         child_status[i] = getpid();
707
708                         pause();
709
710                         if (child_status[i]) {
711                                 printf("Child %d failed to start!\n", i);
712                                 child_status_out[i] = 1;
713                                 _exit(1);
714                         }
715
716                         child_status_out[i] = fn(tctx, current_cli, i);
717                         _exit(0);
718                 }
719         }
720
721         do {
722                 synccount = 0;
723                 for (i=0;i<torture_nprocs;i++) {
724                         if (child_status[i]) synccount++;
725                 }
726                 if (synccount == torture_nprocs) break;
727                 smb_msleep(100);
728         } while (timeval_elapsed(&tv) < start_time_limit);
729
730         if (synccount != torture_nprocs) {
731                 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
732                 *result = false;
733                 return timeval_elapsed(&tv);
734         }
735
736         printf("Starting %d clients\n", torture_nprocs);
737
738         /* start the client load */
739         tv = timeval_current();
740         for (i=0;i<torture_nprocs;i++) {
741                 child_status[i] = 0;
742         }
743
744         printf("%d clients started\n", torture_nprocs);
745
746         kill(0, SIGCONT);
747
748         for (i=0;i<torture_nprocs;i++) {
749                 int ret;
750                 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
751                 if (ret == -1 || WEXITSTATUS(status) != 0) {
752                         *result = false;
753                 }
754         }
755
756         printf("\n");
757         
758         for (i=0;i<torture_nprocs;i++) {
759                 if (!child_status_out[i]) {
760                         *result = false;
761                 }
762         }
763         return timeval_elapsed(&tv);
764 }
765
766 static bool wrap_smb_multi_test(struct torture_context *torture,
767                                                                 struct torture_tcase *tcase,
768                                                                 struct torture_test *test)
769 {
770         bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
771         bool result;
772
773         torture_create_procs(torture, fn, &result);
774
775         return result;
776 }
777
778 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
779                                                                         struct torture_suite *suite,
780                                                                         const char *name,
781                                                                         bool (*run) (struct torture_context *,
782                                                                                                  struct smbcli_state *,
783                                                                                                 int i))
784 {
785         struct torture_test *test; 
786         struct torture_tcase *tcase;
787         
788         tcase = torture_suite_add_tcase(suite, name);
789
790         test = talloc(tcase, struct torture_test);
791
792         test->name = talloc_strdup(test, name);
793         test->description = NULL;
794         test->run = wrap_smb_multi_test;
795         test->fn = run;
796         test->dangerous = false;
797
798         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
799
800         return test;
801
802 }
803
804 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
805                                                                         struct torture_tcase *tcase,
806                                                                         struct torture_test *test)
807 {
808         bool (*fn) (struct torture_context *, struct smbcli_state *,
809                                 struct smbcli_state *);
810         bool ret;
811
812         struct smbcli_state *cli1, *cli2;
813
814         if (!torture_open_connection(&cli1, torture_ctx, 0) || 
815                 !torture_open_connection(&cli2, torture_ctx, 1))
816                 return false;
817
818         fn = test->fn;
819
820         ret = fn(torture_ctx, cli1, cli2);
821
822         talloc_free(cli1);
823         talloc_free(cli2);
824
825         return ret;
826 }
827
828
829
830 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
831                                                                         struct torture_suite *suite,
832                                                                         const char *name,
833                                                                         bool (*run) (struct torture_context *,
834                                                                                                 struct smbcli_state *,
835                                                                                                 struct smbcli_state *))
836 {
837         struct torture_test *test; 
838         struct torture_tcase *tcase;
839         
840         tcase = torture_suite_add_tcase(suite, name);
841
842         test = talloc(tcase, struct torture_test);
843
844         test->name = talloc_strdup(test, name);
845         test->description = NULL;
846         test->run = wrap_simple_2smb_test;
847         test->fn = run;
848         test->dangerous = false;
849
850         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
851
852         return test;
853
854 }
855
856 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
857                                                                         struct torture_tcase *tcase,
858                                                                         struct torture_test *test)
859 {
860         bool (*fn) (struct torture_context *, struct smbcli_state *);
861         bool ret;
862
863         struct smbcli_state *cli1;
864
865         if (!torture_open_connection(&cli1, torture_ctx, 0))
866                 return false;
867
868         fn = test->fn;
869
870         ret = fn(torture_ctx, cli1);
871
872         talloc_free(cli1);
873
874         return ret;
875 }
876
877 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
878                                 struct torture_suite *suite,
879                                 const char *name,
880                                 bool (*run) (struct torture_context *, struct smbcli_state *))
881 {
882         struct torture_test *test; 
883         struct torture_tcase *tcase;
884         
885         tcase = torture_suite_add_tcase(suite, name);
886
887         test = talloc(tcase, struct torture_test);
888
889         test->name = talloc_strdup(test, name);
890         test->description = NULL;
891         test->run = wrap_simple_1smb_test;
892         test->fn = run;
893         test->dangerous = false;
894
895         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
896
897         return test;
898 }
899
900
901 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
902                              struct smbcli_session *session,
903                              const char *sharename,
904                              struct smbcli_tree **res)
905 {
906         union smb_tcon tcon;
907         struct smbcli_tree *result;
908         TALLOC_CTX *tmp_ctx;
909         NTSTATUS status;
910
911         if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
912                 return NT_STATUS_NO_MEMORY;
913         }
914
915         result = smbcli_tree_init(session, tmp_ctx, false);
916         if (result == NULL) {
917                 talloc_free(tmp_ctx);
918                 return NT_STATUS_NO_MEMORY;
919         }
920
921         tcon.generic.level = RAW_TCON_TCONX;
922         tcon.tconx.in.flags = 0;
923
924         /* Ignore share mode security here */
925         tcon.tconx.in.password = data_blob(NULL, 0);
926         tcon.tconx.in.path = sharename;
927         tcon.tconx.in.device = "?????";
928
929         status = smb_raw_tcon(result, tmp_ctx, &tcon);
930         if (!NT_STATUS_IS_OK(status)) {
931                 talloc_free(tmp_ctx);
932                 return status;
933         }
934
935         result->tid = tcon.tconx.out.tid;
936         *res = talloc_steal(mem_ctx, result);
937         talloc_free(tmp_ctx);
938         return NT_STATUS_OK;
939 }
940
941 /* 
942    a wrapper around smblsa_sid_check_privilege, that tries to take
943    account of the fact that the lsa privileges calls don't expand
944    group memberships, using an explicit check for administrator. There
945    must be a better way ...
946  */
947 NTSTATUS torture_check_privilege(struct smbcli_state *cli, 
948                                  const char *sid_str,
949                                  const char *privilege)
950 {
951         struct dom_sid *sid;
952         TALLOC_CTX *tmp_ctx = talloc_new(cli);
953         uint32_t rid;
954         NTSTATUS status;
955
956         sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
957         if (sid == NULL) {
958                 talloc_free(tmp_ctx);
959                 return NT_STATUS_INVALID_SID;
960         }
961
962         status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
963         NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
964
965         if (rid == DOMAIN_RID_ADMINISTRATOR) {
966                 /* assume the administrator has them all */
967                 return NT_STATUS_OK;
968         }
969
970         talloc_free(tmp_ctx);
971
972         return smblsa_sid_check_privilege(cli, sid_str, privilege);
973 }