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