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