Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-gmake4
[amitay/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/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, tctx->ev);
557 }
558
559
560
561 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
562 {
563         bool ret = true;
564         if (!c) return true;
565         if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
566                 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
567                 ret = false;
568         }
569         talloc_free(c);
570         return ret;
571 }
572
573
574 /* check if the server produced the expected error code */
575 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c, 
576                  uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
577 {
578         NTSTATUS status;
579         
580         status = smbcli_nt_error(c->tree);
581         if (NT_STATUS_IS_DOS(status)) {
582                 int class, num;
583                 class = NT_STATUS_DOS_CLASS(status);
584                 num = NT_STATUS_DOS_CODE(status);
585                 if (eclass != class || ecode != num) {
586                         printf("unexpected error code %s\n", nt_errstr(status));
587                         printf(" expected %s or %s (at %s)\n", 
588                                nt_errstr(NT_STATUS_DOS(eclass, ecode)), 
589                                nt_errstr(nterr), location);
590                         return false;
591                 }
592         } else {
593                 if (!NT_STATUS_EQUAL(nterr, status)) {
594                         printf("unexpected error code %s\n", nt_errstr(status));
595                         printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
596                         return false;
597                 }
598         }
599
600         return true;
601 }
602
603 static struct smbcli_state *current_cli;
604 static int procnum; /* records process count number when forking */
605
606 static void sigcont(int sig)
607 {
608 }
609
610 double torture_create_procs(struct torture_context *tctx, 
611                                                         bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
612 {
613         int i, status;
614         volatile pid_t *child_status;
615         volatile bool *child_status_out;
616         int synccount;
617         int tries = 8;
618         int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
619         double start_time_limit = 10 + (torture_nprocs * 1.5);
620         struct timeval tv;
621
622         *result = true;
623
624         synccount = 0;
625
626         signal(SIGCONT, sigcont);
627
628         child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
629         if (!child_status) {
630                 printf("Failed to setup shared memory\n");
631                 return -1;
632         }
633
634         child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
635         if (!child_status_out) {
636                 printf("Failed to setup result status shared memory\n");
637                 return -1;
638         }
639
640         for (i = 0; i < torture_nprocs; i++) {
641                 child_status[i] = 0;
642                 child_status_out[i] = true;
643         }
644
645         tv = timeval_current();
646
647         for (i=0;i<torture_nprocs;i++) {
648                 procnum = i;
649                 if (fork() == 0) {
650                         char *myname;
651
652                         pid_t mypid = getpid();
653                         srandom(((int)mypid) ^ ((int)time(NULL)));
654
655                         asprintf(&myname, "CLIENT%d", i);
656                         lp_set_cmdline(tctx->lp_ctx, "netbios name", myname);
657                         free(myname);
658
659
660                         while (1) {
661                                 if (torture_open_connection(&current_cli, tctx, i)) {
662                                         break;
663                                 }
664                                 if (tries-- == 0) {
665                                         printf("pid %d failed to start\n", (int)getpid());
666                                         _exit(1);
667                                 }
668                                 msleep(100);    
669                         }
670
671                         child_status[i] = getpid();
672
673                         pause();
674
675                         if (child_status[i]) {
676                                 printf("Child %d failed to start!\n", i);
677                                 child_status_out[i] = 1;
678                                 _exit(1);
679                         }
680
681                         child_status_out[i] = fn(tctx, current_cli, i);
682                         _exit(0);
683                 }
684         }
685
686         do {
687                 synccount = 0;
688                 for (i=0;i<torture_nprocs;i++) {
689                         if (child_status[i]) synccount++;
690                 }
691                 if (synccount == torture_nprocs) break;
692                 msleep(100);
693         } while (timeval_elapsed(&tv) < start_time_limit);
694
695         if (synccount != torture_nprocs) {
696                 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
697                 *result = false;
698                 return timeval_elapsed(&tv);
699         }
700
701         printf("Starting %d clients\n", torture_nprocs);
702
703         /* start the client load */
704         tv = timeval_current();
705         for (i=0;i<torture_nprocs;i++) {
706                 child_status[i] = 0;
707         }
708
709         printf("%d clients started\n", torture_nprocs);
710
711         kill(0, SIGCONT);
712
713         for (i=0;i<torture_nprocs;i++) {
714                 int ret;
715                 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
716                 if (ret == -1 || WEXITSTATUS(status) != 0) {
717                         *result = false;
718                 }
719         }
720
721         printf("\n");
722         
723         for (i=0;i<torture_nprocs;i++) {
724                 if (!child_status_out[i]) {
725                         *result = false;
726                 }
727         }
728         return timeval_elapsed(&tv);
729 }
730
731 static bool wrap_smb_multi_test(struct torture_context *torture,
732                                                                 struct torture_tcase *tcase,
733                                                                 struct torture_test *test)
734 {
735         bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
736         bool result;
737
738         torture_create_procs(torture, fn, &result);
739
740         return result;
741 }
742
743 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
744                                                                         struct torture_suite *suite,
745                                                                         const char *name,
746                                                                         bool (*run) (struct torture_context *,
747                                                                                                  struct smbcli_state *,
748                                                                                                 int i))
749 {
750         struct torture_test *test; 
751         struct torture_tcase *tcase;
752         
753         tcase = torture_suite_add_tcase(suite, name);
754
755         test = talloc(tcase, struct torture_test);
756
757         test->name = talloc_strdup(test, name);
758         test->description = NULL;
759         test->run = wrap_smb_multi_test;
760         test->fn = run;
761         test->dangerous = false;
762
763         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
764
765         return test;
766
767 }
768
769 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
770                                                                         struct torture_tcase *tcase,
771                                                                         struct torture_test *test)
772 {
773         bool (*fn) (struct torture_context *, struct smbcli_state *,
774                                 struct smbcli_state *);
775         bool ret;
776
777         struct smbcli_state *cli1, *cli2;
778
779         if (!torture_open_connection(&cli1, torture_ctx, 0) || 
780                 !torture_open_connection(&cli2, torture_ctx, 1))
781                 return false;
782
783         fn = test->fn;
784
785         ret = fn(torture_ctx, cli1, cli2);
786
787         talloc_free(cli1);
788         talloc_free(cli2);
789
790         return ret;
791 }
792
793
794
795 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
796                                                                         struct torture_suite *suite,
797                                                                         const char *name,
798                                                                         bool (*run) (struct torture_context *,
799                                                                                                 struct smbcli_state *,
800                                                                                                 struct smbcli_state *))
801 {
802         struct torture_test *test; 
803         struct torture_tcase *tcase;
804         
805         tcase = torture_suite_add_tcase(suite, name);
806
807         test = talloc(tcase, struct torture_test);
808
809         test->name = talloc_strdup(test, name);
810         test->description = NULL;
811         test->run = wrap_simple_2smb_test;
812         test->fn = run;
813         test->dangerous = false;
814
815         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
816
817         return test;
818
819 }
820
821 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
822                                                                         struct torture_tcase *tcase,
823                                                                         struct torture_test *test)
824 {
825         bool (*fn) (struct torture_context *, struct smbcli_state *);
826         bool ret;
827
828         struct smbcli_state *cli1;
829
830         if (!torture_open_connection(&cli1, torture_ctx, 0))
831                 return false;
832
833         fn = test->fn;
834
835         ret = fn(torture_ctx, cli1);
836
837         talloc_free(cli1);
838
839         return ret;
840 }
841
842 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
843                                 struct torture_suite *suite,
844                                 const char *name,
845                                 bool (*run) (struct torture_context *, struct smbcli_state *))
846 {
847         struct torture_test *test; 
848         struct torture_tcase *tcase;
849         
850         tcase = torture_suite_add_tcase(suite, name);
851
852         test = talloc(tcase, struct torture_test);
853
854         test->name = talloc_strdup(test, name);
855         test->description = NULL;
856         test->run = wrap_simple_1smb_test;
857         test->fn = run;
858         test->dangerous = false;
859
860         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
861
862         return test;
863 }
864
865
866 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
867                              struct smbcli_session *session,
868                              const char *sharename,
869                              struct smbcli_tree **res)
870 {
871         union smb_tcon tcon;
872         struct smbcli_tree *result;
873         TALLOC_CTX *tmp_ctx;
874         NTSTATUS status;
875
876         if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
877                 return NT_STATUS_NO_MEMORY;
878         }
879
880         result = smbcli_tree_init(session, tmp_ctx, false);
881         if (result == NULL) {
882                 talloc_free(tmp_ctx);
883                 return NT_STATUS_NO_MEMORY;
884         }
885
886         tcon.generic.level = RAW_TCON_TCONX;
887         tcon.tconx.in.flags = 0;
888
889         /* Ignore share mode security here */
890         tcon.tconx.in.password = data_blob(NULL, 0);
891         tcon.tconx.in.path = sharename;
892         tcon.tconx.in.device = "?????";
893
894         status = smb_raw_tcon(result, tmp_ctx, &tcon);
895         if (!NT_STATUS_IS_OK(status)) {
896                 talloc_free(tmp_ctx);
897                 return status;
898         }
899
900         result->tid = tcon.tconx.out.tid;
901         *res = talloc_steal(mem_ctx, result);
902         talloc_free(tmp_ctx);
903         return NT_STATUS_OK;
904 }