0520f275a4cd88a8690748a7876a80c61d8d2538
[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 #include "libcli/smb/smbXcli_base.h"
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   check that a wire string matches the flags specified 
254   not 100% accurate, but close enough for testing
255 */
256 bool wire_bad_flags(struct smb_wire_string *str, int flags, 
257                     struct smbcli_transport *transport)
258 {
259         bool server_unicode;
260         int len;
261         if (!str || !str->s) return true;
262         len = strlen(str->s);
263         if (flags & STR_TERMINATE) len++;
264
265         server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
266         if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
267                 server_unicode = false;
268         }
269
270         if ((flags & STR_UNICODE) || server_unicode) {
271                 len *= 2;
272         } else if (flags & STR_TERMINATE_ASCII) {
273                 len++;
274         }
275         if (str->private_length != len) {
276                 printf("Expected wire_length %d but got %d for '%s'\n", 
277                        len, str->private_length, str->s);
278                 return true;
279         }
280         return false;
281 }
282
283 /*
284   dump a all_info QFILEINFO structure
285 */
286 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
287 {
288         d_printf("\tcreate_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
289         d_printf("\taccess_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
290         d_printf("\twrite_time:     %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
291         d_printf("\tchange_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
292         d_printf("\tattrib:         0x%x\n", finfo->all_info.out.attrib);
293         d_printf("\talloc_size:     %llu\n", (long long)finfo->all_info.out.alloc_size);
294         d_printf("\tsize:           %llu\n", (long long)finfo->all_info.out.size);
295         d_printf("\tnlink:          %u\n", finfo->all_info.out.nlink);
296         d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
297         d_printf("\tdirectory:      %u\n", finfo->all_info.out.directory);
298         d_printf("\tea_size:        %u\n", finfo->all_info.out.ea_size);
299         d_printf("\tfname:          '%s'\n", finfo->all_info.out.fname.s);
300 }
301
302 /*
303   dump file infor by name
304 */
305 void torture_all_info(struct smbcli_tree *tree, const char *fname)
306 {
307         TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
308         union smb_fileinfo finfo;
309         NTSTATUS status;
310
311         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
312         finfo.generic.in.file.path = fname;
313         status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
314         if (!NT_STATUS_IS_OK(status)) {
315                 d_printf("%s - %s\n", fname, nt_errstr(status));
316                 return;
317         }
318
319         d_printf("%s:\n", fname);
320         dump_all_info(mem_ctx, &finfo);
321         talloc_free(mem_ctx);
322 }
323
324
325 /*
326   set a attribute on a file
327 */
328 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
329 {
330         union smb_setfileinfo sfinfo;
331         NTSTATUS status;
332
333         ZERO_STRUCT(sfinfo.basic_info.in);
334         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
335         sfinfo.basic_info.in.file.path = fname;
336         sfinfo.basic_info.in.attrib = attrib;
337         status = smb_raw_setpathinfo(tree, &sfinfo);
338         return NT_STATUS_IS_OK(status);
339 }
340
341
342 /*
343   set a file descriptor as sparse
344 */
345 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
346 {
347         union smb_ioctl nt;
348         NTSTATUS status;
349         TALLOC_CTX *mem_ctx;
350
351         mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
352         if (!mem_ctx) {
353                 return NT_STATUS_NO_MEMORY;
354         }
355
356         nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
357         nt.ntioctl.in.function = FSCTL_SET_SPARSE;
358         nt.ntioctl.in.file.fnum = fnum;
359         nt.ntioctl.in.fsctl = true;
360         nt.ntioctl.in.filter = 0;
361         nt.ntioctl.in.max_data = 0;
362         nt.ntioctl.in.blob = data_blob(NULL, 0);
363
364         status = smb_raw_ioctl(tree, mem_ctx, &nt);
365
366         talloc_free(mem_ctx);
367
368         return status;
369 }
370
371 /*
372   check that an EA has the right value 
373 */
374 NTSTATUS torture_check_ea(struct smbcli_state *cli, 
375                           const char *fname, const char *eaname, const char *value)
376 {
377         union smb_fileinfo info;
378         NTSTATUS status;
379         struct ea_name ea;
380         TALLOC_CTX *mem_ctx = talloc_new(cli);
381
382         info.ea_list.level = RAW_FILEINFO_EA_LIST;
383         info.ea_list.in.file.path = fname;
384         info.ea_list.in.num_names = 1;
385         info.ea_list.in.ea_names = &ea;
386
387         ea.name.s = eaname;
388
389         status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
390         if (!NT_STATUS_IS_OK(status)) {
391                 talloc_free(mem_ctx);
392                 return status;
393         }
394
395         if (info.ea_list.out.num_eas != 1) {
396                 printf("Expected 1 ea in ea_list\n");
397                 talloc_free(mem_ctx);
398                 return NT_STATUS_EA_CORRUPT_ERROR;
399         }
400
401         if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
402                 printf("Expected ea '%s' not '%s' in ea_list\n",
403                        eaname, info.ea_list.out.eas[0].name.s);
404                 talloc_free(mem_ctx);
405                 return NT_STATUS_EA_CORRUPT_ERROR;
406         }
407
408         if (value == NULL) {
409                 if (info.ea_list.out.eas[0].value.length != 0) {
410                         printf("Expected zero length ea for %s\n", eaname);
411                         talloc_free(mem_ctx);
412                         return NT_STATUS_EA_CORRUPT_ERROR;
413                 }
414                 talloc_free(mem_ctx);
415                 return NT_STATUS_OK;
416         }
417
418         if (strlen(value) == info.ea_list.out.eas[0].value.length &&
419             memcmp(value, info.ea_list.out.eas[0].value.data,
420                    info.ea_list.out.eas[0].value.length) == 0) {
421                 talloc_free(mem_ctx);
422                 return NT_STATUS_OK;
423         }
424
425         printf("Expected value '%s' not '%*.*s' for ea %s\n",
426                value, 
427                (int)info.ea_list.out.eas[0].value.length,
428                (int)info.ea_list.out.eas[0].value.length,
429                info.ea_list.out.eas[0].value.data,
430                eaname);
431
432         talloc_free(mem_ctx);
433
434         return NT_STATUS_EA_CORRUPT_ERROR;
435 }
436
437 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
438                                    struct smbcli_state **c, 
439                                    struct torture_context *tctx,
440                                    const char *hostname, 
441                                    const char *sharename,
442                                    struct tevent_context *ev)
443 {
444         NTSTATUS status;
445
446         struct smbcli_options options;
447         struct smbcli_session_options session_options;
448
449         lpcfg_smbcli_options(tctx->lp_ctx, &options);
450         lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
451
452         options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
453         options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
454
455         status = smbcli_full_connection(mem_ctx, c, hostname, 
456                                         lpcfg_smb_ports(tctx->lp_ctx),
457                                         sharename, NULL,
458                                         lpcfg_socket_options(tctx->lp_ctx),
459                                         cmdline_credentials, 
460                                         lpcfg_resolve_context(tctx->lp_ctx),
461                                         ev, &options, &session_options,
462                                         lpcfg_gensec_settings(tctx, tctx->lp_ctx));
463         if (!NT_STATUS_IS_OK(status)) {
464                 printf("Failed to open connection - %s\n", nt_errstr(status));
465                 return false;
466         }
467
468         return true;
469 }
470
471 _PUBLIC_ bool torture_get_conn_index(int conn_index,
472                                      TALLOC_CTX *mem_ctx,
473                                      struct torture_context *tctx,
474                                      char **host, char **share)
475 {
476         char **unc_list = NULL;
477         int num_unc_names = 0;
478         const char *p;
479
480         (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
481         (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
482         
483         p = torture_setting_string(tctx, "unclist", NULL);
484         if (!p) {
485                 return true;
486         }
487
488         unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
489         if (!unc_list || num_unc_names <= 0) {
490                 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
491                 return false;
492         }
493
494         p = unc_list[conn_index % num_unc_names];
495         if (p[0] != '/' && p[0] != '\\') {
496                 /* allow UNC lists of hosts */
497                 (*host) = talloc_strdup(mem_ctx, p);
498         } else if (!smbcli_parse_unc(p, mem_ctx, host, share)) {
499                 DEBUG(0, ("Failed to parse UNC name %s\n",
500                           unc_list[conn_index % num_unc_names]));
501                 return false;
502         }
503
504         talloc_free(unc_list);
505         return true;
506 }
507
508
509
510 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
511                                          int conn_index,
512                                          struct torture_context *tctx,
513                                          struct tevent_context *ev)
514 {
515         char *host, *share;
516         bool ret;
517
518         if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
519                 return false;
520         }
521
522         ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
523         talloc_free(host);
524         talloc_free(share);
525
526         return ret;
527 }
528
529 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
530 {
531         return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
532 }
533
534
535
536 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
537 {
538         bool ret = true;
539         if (!c) return true;
540         if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
541                 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
542                 ret = false;
543         }
544         talloc_free(c);
545         return ret;
546 }
547
548
549 /* check if the server produced the expected error code */
550 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c, 
551                  uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
552 {
553         NTSTATUS status;
554         
555         status = smbcli_nt_error(c->tree);
556         if (NT_STATUS_IS_DOS(status)) {
557                 int classnum, num;
558                 classnum = NT_STATUS_DOS_CLASS(status);
559                 num = NT_STATUS_DOS_CODE(status);
560                 if (eclass != classnum || ecode != num) {
561                         printf("unexpected error code %s\n", nt_errstr(status));
562                         printf(" expected %s or %s (at %s)\n", 
563                                nt_errstr(NT_STATUS_DOS(eclass, ecode)), 
564                                nt_errstr(nterr), location);
565                         return false;
566                 }
567         } else {
568                 if (!NT_STATUS_EQUAL(nterr, status)) {
569                         printf("unexpected error code %s\n", nt_errstr(status));
570                         printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
571                         return false;
572                 }
573         }
574
575         return true;
576 }
577
578 static struct smbcli_state *current_cli;
579 static int procnum; /* records process count number when forking */
580
581 static void sigcont(int sig)
582 {
583 }
584
585 struct child_status {
586         pid_t pid;
587         bool start;
588         enum torture_result result;
589         char reason[1024];
590 };
591
592 double torture_create_procs(struct torture_context *tctx,
593         bool (*fn)(struct torture_context *, struct smbcli_state *, int),
594         bool *result)
595 {
596         int i, status;
597         struct child_status *child_status;
598         int synccount;
599         int tries = 8;
600         int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
601         double start_time_limit = 10 + (torture_nprocs * 1.5);
602         struct timeval tv;
603
604         *result = true;
605
606         synccount = 0;
607
608         signal(SIGCONT, sigcont);
609
610         child_status = (struct child_status *)anonymous_shared_allocate(
611                                 sizeof(struct child_status)*torture_nprocs);
612         if (child_status == NULL) {
613                 printf("Failed to setup shared memory\n");
614                 return -1;
615         }
616
617         for (i = 0; i < torture_nprocs; i++) {
618                 ZERO_STRUCT(child_status[i]);
619         }
620
621         tv = timeval_current();
622
623         for (i=0;i<torture_nprocs;i++) {
624                 procnum = i;
625                 if (fork() == 0) {
626                         char *myname;
627                         bool ok;
628
629                         pid_t mypid = getpid();
630                         srandom(((int)mypid) ^ ((int)time(NULL)));
631
632                         if (asprintf(&myname, "CLIENT%d", i) == -1) {
633                                 printf("asprintf failed\n");
634                                 return -1;
635                         }
636                         lpcfg_set_cmdline(tctx->lp_ctx, "netbios name", myname);
637                         free(myname);
638
639
640                         while (1) {
641                                 if (torture_open_connection(&current_cli, tctx, i)) {
642                                         break;
643                                 }
644                                 if (tries-- == 0) {
645                                         printf("pid %d failed to start\n", (int)getpid());
646                                         _exit(1);
647                                 }
648                                 smb_msleep(100);        
649                         }
650
651                         child_status[i].pid = getpid();
652
653                         pause();
654
655                         if (!child_status[i].start) {
656                                 child_status[i].result = TORTURE_ERROR;
657                                 printf("Child %d failed to start!\n", i);
658                                 _exit(1);
659                         }
660
661                         ok = fn(tctx, current_cli, i);
662                         if (!ok) {
663                                 if (tctx->last_result == TORTURE_OK) {
664                                         torture_result(tctx, TORTURE_ERROR,
665                                                 "unknown error: missing "
666                                                 "torture_result call?\n");
667                                 }
668
669                                 child_status[i].result = tctx->last_result;
670
671                                 if (strlen(tctx->last_reason) > 1023) {
672                                         /* note: reason already contains \n */
673                                         torture_comment(tctx,
674                                                 "child %d (pid %u) failed: %s",
675                                                 i,
676                                                 (unsigned)child_status[i].pid,
677                                                 tctx->last_reason);
678                                 }
679
680                                 snprintf(child_status[i].reason,
681                                          1024, "child %d (pid %u) failed: %s",
682                                          i, (unsigned)child_status[i].pid,
683                                          tctx->last_reason);
684                                 /* ensure proper "\n\0" termination: */
685                                 if (child_status[i].reason[1022] != '\0') {
686                                         child_status[i].reason[1022] = '\n';
687                                         child_status[i].reason[1023] = '\0';
688                                 }
689                         }
690                         _exit(0);
691                 }
692         }
693
694         do {
695                 synccount = 0;
696                 for (i=0;i<torture_nprocs;i++) {
697                         if (child_status[i].pid != 0) {
698                                 synccount++;
699                         }
700                 }
701                 if (synccount == torture_nprocs) {
702                         break;
703                 }
704                 smb_msleep(100);
705         } while (timeval_elapsed(&tv) < start_time_limit);
706
707         if (synccount != torture_nprocs) {
708                 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
709
710                 /* cleanup child processes */
711                 for (i = 0; i < torture_nprocs; i++) {
712                         if (child_status[i].pid != 0) {
713                                 kill(child_status[i].pid, SIGTERM);
714                         }
715                 }
716
717                 *result = false;
718                 return timeval_elapsed(&tv);
719         }
720
721         printf("Starting %d clients\n", torture_nprocs);
722
723         /* start the client load */
724         tv = timeval_current();
725         for (i=0;i<torture_nprocs;i++) {
726                 child_status[i].start = true;
727         }
728
729         printf("%d clients started\n", torture_nprocs);
730
731         kill(0, SIGCONT);
732
733         for (i=0;i<torture_nprocs;i++) {
734                 int ret;
735                 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
736                 if (ret == -1 || WEXITSTATUS(status) != 0) {
737                         *result = false;
738                 }
739         }
740
741         printf("\n");
742
743         for (i=0;i<torture_nprocs;i++) {
744                 if (child_status[i].result != TORTURE_OK) {
745                         *result = false;
746                         torture_result(tctx, child_status[i].result,
747                                        "%s", child_status[i].reason);
748                 }
749         }
750
751         return timeval_elapsed(&tv);
752 }
753
754 static bool wrap_smb_multi_test(struct torture_context *torture,
755                                                                 struct torture_tcase *tcase,
756                                                                 struct torture_test *test)
757 {
758         bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
759         bool result;
760
761         torture_create_procs(torture, fn, &result);
762
763         return result;
764 }
765
766 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
767                                                                         struct torture_suite *suite,
768                                                                         const char *name,
769                                                                         bool (*run) (struct torture_context *,
770                                                                                                  struct smbcli_state *,
771                                                                                                 int i))
772 {
773         struct torture_test *test; 
774         struct torture_tcase *tcase;
775         
776         tcase = torture_suite_add_tcase(suite, name);
777
778         test = talloc(tcase, struct torture_test);
779
780         test->name = talloc_strdup(test, name);
781         test->description = NULL;
782         test->run = wrap_smb_multi_test;
783         test->fn = run;
784         test->dangerous = false;
785
786         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
787
788         return test;
789
790 }
791
792 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
793                                                                         struct torture_tcase *tcase,
794                                                                         struct torture_test *test)
795 {
796         bool (*fn) (struct torture_context *, struct smbcli_state *,
797                                 struct smbcli_state *);
798         bool ret = true;
799
800         struct smbcli_state *cli1 = NULL, *cli2 = NULL;
801
802         torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
803         torture_assert_goto(torture_ctx, torture_open_connection(&cli2, torture_ctx, 1), ret, fail, "Failed to open connection");
804
805         fn = test->fn;
806
807         ret = fn(torture_ctx, cli1, cli2);
808 fail:
809         talloc_free(cli1);
810         talloc_free(cli2);
811
812         return ret;
813 }
814
815
816
817 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
818                                                                         struct torture_suite *suite,
819                                                                         const char *name,
820                                                                         bool (*run) (struct torture_context *,
821                                                                                                 struct smbcli_state *,
822                                                                                                 struct smbcli_state *))
823 {
824         struct torture_test *test; 
825         struct torture_tcase *tcase;
826         
827         tcase = torture_suite_add_tcase(suite, name);
828
829         test = talloc(tcase, struct torture_test);
830
831         test->name = talloc_strdup(test, name);
832         test->description = NULL;
833         test->run = wrap_simple_2smb_test;
834         test->fn = run;
835         test->dangerous = false;
836
837         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
838
839         return test;
840
841 }
842
843 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
844                                                                         struct torture_tcase *tcase,
845                                                                         struct torture_test *test)
846 {
847         bool (*fn) (struct torture_context *, struct smbcli_state *);
848         bool ret = true;
849
850         struct smbcli_state *cli1 = NULL;
851
852         torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
853
854         fn = test->fn;
855
856         ret = fn(torture_ctx, cli1);
857 fail:
858         talloc_free(cli1);
859
860         return ret;
861 }
862
863 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
864                                 struct torture_suite *suite,
865                                 const char *name,
866                                 bool (*run) (struct torture_context *, struct smbcli_state *))
867 {
868         struct torture_test *test; 
869         struct torture_tcase *tcase;
870         
871         tcase = torture_suite_add_tcase(suite, name);
872
873         test = talloc(tcase, struct torture_test);
874
875         test->name = talloc_strdup(test, name);
876         test->description = NULL;
877         test->run = wrap_simple_1smb_test;
878         test->fn = run;
879         test->dangerous = false;
880
881         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
882
883         return test;
884 }
885
886
887 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
888                              struct smbcli_session *session,
889                              const char *sharename,
890                              struct smbcli_tree **res)
891 {
892         union smb_tcon tcon;
893         struct smbcli_tree *result;
894         TALLOC_CTX *tmp_ctx;
895         NTSTATUS status;
896
897         if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
898                 return NT_STATUS_NO_MEMORY;
899         }
900
901         result = smbcli_tree_init(session, tmp_ctx, false);
902         if (result == NULL) {
903                 talloc_free(tmp_ctx);
904                 return NT_STATUS_NO_MEMORY;
905         }
906
907         tcon.generic.level = RAW_TCON_TCONX;
908         tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
909         tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
910
911         /* Ignore share mode security here */
912         tcon.tconx.in.password = data_blob(NULL, 0);
913         tcon.tconx.in.path = sharename;
914         tcon.tconx.in.device = "?????";
915
916         status = smb_raw_tcon(result, tmp_ctx, &tcon);
917         if (!NT_STATUS_IS_OK(status)) {
918                 talloc_free(tmp_ctx);
919                 return status;
920         }
921
922         result->tid = tcon.tconx.out.tid;
923
924         if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
925                 smb1cli_session_protect_session_key(result->session->smbXcli);
926         }
927
928         *res = talloc_steal(mem_ctx, result);
929         talloc_free(tmp_ctx);
930         return NT_STATUS_OK;
931 }
932
933 /* 
934    a wrapper around smblsa_sid_check_privilege, that tries to take
935    account of the fact that the lsa privileges calls don't expand
936    group memberships, using an explicit check for administrator. There
937    must be a better way ...
938  */
939 NTSTATUS torture_check_privilege(struct smbcli_state *cli, 
940                                  const char *sid_str,
941                                  const char *privilege)
942 {
943         struct dom_sid *sid;
944         TALLOC_CTX *tmp_ctx = talloc_new(cli);
945         uint32_t rid;
946         NTSTATUS status;
947
948         sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
949         if (sid == NULL) {
950                 talloc_free(tmp_ctx);
951                 return NT_STATUS_INVALID_SID;
952         }
953
954         status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
955         if (!NT_STATUS_IS_OK(status)) {
956                 TALLOC_FREE(tmp_ctx);
957                 return status;
958         }
959
960         if (rid == DOMAIN_RID_ADMINISTRATOR) {
961                 /* assume the administrator has them all */
962                 return NT_STATUS_OK;
963         }
964
965         talloc_free(tmp_ctx);
966
967         return smblsa_sid_check_privilege(cli, sid_str, privilege);
968 }