Part 4 of bug #7028 - include scannedonly VFS module
[Samba/gebeck_regimport.git] / source4 / torture / util_smb.c
blobb35a1cb207697d8c86ac4903d9dca066b0778a81
1 /*
2 Unix SMB/CIFS implementation.
3 SMB torture tester utility functions
4 Copyright (C) Andrew Tridgell 2003
5 Copyright (C) Jelmer Vernooij 2006
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.
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.
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/>.
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"
39 /**
40 setup a directory ready for a test
42 _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
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;
50 return true;
54 create a directory, returning a handle to it
56 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
58 NTSTATUS status;
59 union smb_open io;
60 TALLOC_CTX *mem_ctx;
62 mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
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;
77 status = smb_raw_open(tree, mem_ctx, &io);
78 talloc_free(mem_ctx);
80 if (NT_STATUS_IS_OK(status)) {
81 *fnum = io.ntcreatex.out.file.fnum;
84 return status;
88 /**
89 sometimes we need a fairly complex file to work with, so we can test
90 all possible attributes.
92 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
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;
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;
112 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
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");
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;
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);
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));
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;
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));
158 if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
159 printf("create_time not setup correctly\n");
161 if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
162 printf("access_time not setup correctly\n");
164 if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
165 printf("write_time not setup correctly\n");
168 return fnum;
173 sometimes we need a fairly complex directory to work with, so we can test
174 all possible attributes.
176 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
178 int fnum;
179 union smb_setfileinfo setfile;
180 union smb_fileinfo fileinfo;
181 time_t t = (time(NULL) & ~1);
182 NTSTATUS status;
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;
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");
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;
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);
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));
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;
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));
238 if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
239 printf("create_time not setup correctly\n");
241 if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
242 printf("access_time not setup correctly\n");
244 if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
245 printf("write_time not setup correctly\n");
248 return fnum;
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
257 The memory is not zeroed
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
262 void *shm_setup(int size)
264 int shmid;
265 void *ret;
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);
273 shm_unlink("private");
274 if (ftruncate(shmid, size) == -1) {
275 printf("can't set shared memory size\n");
276 exit(1);
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);
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);
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;
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
299 See Stevens "advanced programming in unix env" for details
301 shmctl(shmid, IPC_RMID, 0);
302 #endif
304 return ret;
309 check that a wire string matches the flags specified
310 not 100% accurate, but close enough for testing
312 bool wire_bad_flags(struct smb_wire_string *str, int flags,
313 struct smbcli_transport *transport)
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++;
321 server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
322 if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
323 server_unicode = false;
326 if ((flags & STR_UNICODE) || server_unicode) {
327 len *= 2;
328 } else if (flags & STR_TERMINATE_ASCII) {
329 len++;
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;
336 return false;
340 dump a all_info QFILEINFO structure
342 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
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);
359 dump file infor by name
361 void torture_all_info(struct smbcli_tree *tree, const char *fname)
363 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
364 union smb_fileinfo finfo;
365 NTSTATUS status;
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;
375 d_printf("%s:\n", fname);
376 dump_all_info(mem_ctx, &finfo);
377 talloc_free(mem_ctx);
382 set a attribute on a file
384 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
386 union smb_setfileinfo sfinfo;
387 NTSTATUS status;
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);
399 set a file descriptor as sparse
401 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
403 union smb_ioctl nt;
404 NTSTATUS status;
405 TALLOC_CTX *mem_ctx;
407 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
408 if (!mem_ctx) {
409 return NT_STATUS_NO_MEMORY;
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);
420 status = smb_raw_ioctl(tree, mem_ctx, &nt);
422 talloc_free(mem_ctx);
424 return status;
428 check that an EA has the right value
430 NTSTATUS torture_check_ea(struct smbcli_state *cli,
431 const char *fname, const char *eaname, const char *value)
433 union smb_fileinfo info;
434 NTSTATUS status;
435 struct ea_name ea;
436 TALLOC_CTX *mem_ctx = talloc_new(cli);
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;
443 ea.name.s = eaname;
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;
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;
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;
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;
470 talloc_free(mem_ctx);
471 return NT_STATUS_OK;
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;
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);
488 talloc_free(mem_ctx);
490 return NT_STATUS_EA_CORRUPT_ERROR;
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)
500 NTSTATUS status;
502 struct smbcli_options options;
503 struct smbcli_session_options session_options;
505 lp_smbcli_options(tctx->lp_ctx, &options);
506 lp_smbcli_session_options(tctx->lp_ctx, &session_options);
508 options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
509 options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
511 status = smbcli_full_connection(mem_ctx, c, hostname,
512 lp_smb_ports(tctx->lp_ctx),
513 sharename, NULL,
514 lp_socket_options(tctx->lp_ctx),
515 cmdline_credentials,
516 lp_resolve_context(tctx->lp_ctx),
517 ev, &options, &session_options,
518 lp_iconv_convenience(tctx->lp_ctx),
519 lp_gensec_settings(tctx, tctx->lp_ctx));
520 if (!NT_STATUS_IS_OK(status)) {
521 printf("Failed to open connection - %s\n", nt_errstr(status));
522 return false;
525 return true;
528 _PUBLIC_ bool torture_get_conn_index(int conn_index,
529 TALLOC_CTX *mem_ctx,
530 struct torture_context *tctx,
531 char **host, char **share)
533 char **unc_list = NULL;
534 int num_unc_names = 0;
535 const char *p;
537 (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
538 (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
540 p = torture_setting_string(tctx, "unclist", NULL);
541 if (!p) {
542 return true;
545 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
546 if (!unc_list || num_unc_names <= 0) {
547 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
548 return false;
551 if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
552 mem_ctx, host, share)) {
553 DEBUG(0, ("Failed to parse UNC name %s\n",
554 unc_list[conn_index % num_unc_names]));
555 return false;
558 talloc_free(unc_list);
559 return true;
564 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
565 int conn_index,
566 struct torture_context *tctx,
567 struct tevent_context *ev)
569 char *host, *share;
570 bool ret;
572 if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
573 return false;
576 ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
577 talloc_free(host);
578 talloc_free(share);
580 return ret;
583 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
585 return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
590 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
592 bool ret = true;
593 if (!c) return true;
594 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
595 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
596 ret = false;
598 talloc_free(c);
599 return ret;
603 /* check if the server produced the expected error code */
604 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
605 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
607 NTSTATUS status;
609 status = smbcli_nt_error(c->tree);
610 if (NT_STATUS_IS_DOS(status)) {
611 int classnum, num;
612 classnum = NT_STATUS_DOS_CLASS(status);
613 num = NT_STATUS_DOS_CODE(status);
614 if (eclass != classnum || ecode != num) {
615 printf("unexpected error code %s\n", nt_errstr(status));
616 printf(" expected %s or %s (at %s)\n",
617 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
618 nt_errstr(nterr), location);
619 return false;
621 } else {
622 if (!NT_STATUS_EQUAL(nterr, status)) {
623 printf("unexpected error code %s\n", nt_errstr(status));
624 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
625 return false;
629 return true;
632 static struct smbcli_state *current_cli;
633 static int procnum; /* records process count number when forking */
635 static void sigcont(int sig)
639 double torture_create_procs(struct torture_context *tctx,
640 bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
642 int i, status;
643 volatile pid_t *child_status;
644 volatile bool *child_status_out;
645 int synccount;
646 int tries = 8;
647 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
648 double start_time_limit = 10 + (torture_nprocs * 1.5);
649 struct timeval tv;
651 *result = true;
653 synccount = 0;
655 signal(SIGCONT, sigcont);
657 child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
658 if (!child_status) {
659 printf("Failed to setup shared memory\n");
660 return -1;
663 child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
664 if (!child_status_out) {
665 printf("Failed to setup result status shared memory\n");
666 return -1;
669 for (i = 0; i < torture_nprocs; i++) {
670 child_status[i] = 0;
671 child_status_out[i] = true;
674 tv = timeval_current();
676 for (i=0;i<torture_nprocs;i++) {
677 procnum = i;
678 if (fork() == 0) {
679 char *myname;
681 pid_t mypid = getpid();
682 srandom(((int)mypid) ^ ((int)time(NULL)));
684 if (asprintf(&myname, "CLIENT%d", i) == -1) {
685 printf("asprintf failed\n");
686 return -1;
688 lp_set_cmdline(tctx->lp_ctx, "netbios name", myname);
689 free(myname);
692 while (1) {
693 if (torture_open_connection(&current_cli, tctx, i)) {
694 break;
696 if (tries-- == 0) {
697 printf("pid %d failed to start\n", (int)getpid());
698 _exit(1);
700 msleep(100);
703 child_status[i] = getpid();
705 pause();
707 if (child_status[i]) {
708 printf("Child %d failed to start!\n", i);
709 child_status_out[i] = 1;
710 _exit(1);
713 child_status_out[i] = fn(tctx, current_cli, i);
714 _exit(0);
718 do {
719 synccount = 0;
720 for (i=0;i<torture_nprocs;i++) {
721 if (child_status[i]) synccount++;
723 if (synccount == torture_nprocs) break;
724 msleep(100);
725 } while (timeval_elapsed(&tv) < start_time_limit);
727 if (synccount != torture_nprocs) {
728 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
729 *result = false;
730 return timeval_elapsed(&tv);
733 printf("Starting %d clients\n", torture_nprocs);
735 /* start the client load */
736 tv = timeval_current();
737 for (i=0;i<torture_nprocs;i++) {
738 child_status[i] = 0;
741 printf("%d clients started\n", torture_nprocs);
743 kill(0, SIGCONT);
745 for (i=0;i<torture_nprocs;i++) {
746 int ret;
747 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
748 if (ret == -1 || WEXITSTATUS(status) != 0) {
749 *result = false;
753 printf("\n");
755 for (i=0;i<torture_nprocs;i++) {
756 if (!child_status_out[i]) {
757 *result = false;
760 return timeval_elapsed(&tv);
763 static bool wrap_smb_multi_test(struct torture_context *torture,
764 struct torture_tcase *tcase,
765 struct torture_test *test)
767 bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
768 bool result;
770 torture_create_procs(torture, fn, &result);
772 return result;
775 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
776 struct torture_suite *suite,
777 const char *name,
778 bool (*run) (struct torture_context *,
779 struct smbcli_state *,
780 int i))
782 struct torture_test *test;
783 struct torture_tcase *tcase;
785 tcase = torture_suite_add_tcase(suite, name);
787 test = talloc(tcase, struct torture_test);
789 test->name = talloc_strdup(test, name);
790 test->description = NULL;
791 test->run = wrap_smb_multi_test;
792 test->fn = run;
793 test->dangerous = false;
795 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
797 return test;
801 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
802 struct torture_tcase *tcase,
803 struct torture_test *test)
805 bool (*fn) (struct torture_context *, struct smbcli_state *,
806 struct smbcli_state *);
807 bool ret;
809 struct smbcli_state *cli1, *cli2;
811 if (!torture_open_connection(&cli1, torture_ctx, 0) ||
812 !torture_open_connection(&cli2, torture_ctx, 1))
813 return false;
815 fn = test->fn;
817 ret = fn(torture_ctx, cli1, cli2);
819 talloc_free(cli1);
820 talloc_free(cli2);
822 return ret;
827 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
828 struct torture_suite *suite,
829 const char *name,
830 bool (*run) (struct torture_context *,
831 struct smbcli_state *,
832 struct smbcli_state *))
834 struct torture_test *test;
835 struct torture_tcase *tcase;
837 tcase = torture_suite_add_tcase(suite, name);
839 test = talloc(tcase, struct torture_test);
841 test->name = talloc_strdup(test, name);
842 test->description = NULL;
843 test->run = wrap_simple_2smb_test;
844 test->fn = run;
845 test->dangerous = false;
847 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
849 return test;
853 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
854 struct torture_tcase *tcase,
855 struct torture_test *test)
857 bool (*fn) (struct torture_context *, struct smbcli_state *);
858 bool ret;
860 struct smbcli_state *cli1;
862 if (!torture_open_connection(&cli1, torture_ctx, 0))
863 return false;
865 fn = test->fn;
867 ret = fn(torture_ctx, cli1);
869 talloc_free(cli1);
871 return ret;
874 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
875 struct torture_suite *suite,
876 const char *name,
877 bool (*run) (struct torture_context *, struct smbcli_state *))
879 struct torture_test *test;
880 struct torture_tcase *tcase;
882 tcase = torture_suite_add_tcase(suite, name);
884 test = talloc(tcase, struct torture_test);
886 test->name = talloc_strdup(test, name);
887 test->description = NULL;
888 test->run = wrap_simple_1smb_test;
889 test->fn = run;
890 test->dangerous = false;
892 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
894 return test;
898 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
899 struct smbcli_session *session,
900 const char *sharename,
901 struct smbcli_tree **res)
903 union smb_tcon tcon;
904 struct smbcli_tree *result;
905 TALLOC_CTX *tmp_ctx;
906 NTSTATUS status;
908 if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
909 return NT_STATUS_NO_MEMORY;
912 result = smbcli_tree_init(session, tmp_ctx, false);
913 if (result == NULL) {
914 talloc_free(tmp_ctx);
915 return NT_STATUS_NO_MEMORY;
918 tcon.generic.level = RAW_TCON_TCONX;
919 tcon.tconx.in.flags = 0;
921 /* Ignore share mode security here */
922 tcon.tconx.in.password = data_blob(NULL, 0);
923 tcon.tconx.in.path = sharename;
924 tcon.tconx.in.device = "?????";
926 status = smb_raw_tcon(result, tmp_ctx, &tcon);
927 if (!NT_STATUS_IS_OK(status)) {
928 talloc_free(tmp_ctx);
929 return status;
932 result->tid = tcon.tconx.out.tid;
933 *res = talloc_steal(mem_ctx, result);
934 talloc_free(tmp_ctx);
935 return NT_STATUS_OK;
939 a wrapper around smblsa_sid_check_privilege, that tries to take
940 account of the fact that the lsa privileges calls don't expand
941 group memberships, using an explicit check for administrator. There
942 must be a better way ...
944 NTSTATUS torture_check_privilege(struct smbcli_state *cli,
945 const char *sid_str,
946 const char *privilege)
948 struct dom_sid *sid;
949 TALLOC_CTX *tmp_ctx = talloc_new(cli);
950 uint32_t rid;
951 NTSTATUS status;
953 sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
954 if (sid == NULL) {
955 talloc_free(tmp_ctx);
956 return NT_STATUS_INVALID_SID;
959 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
960 NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
962 if (rid == DOMAIN_RID_ADMINISTRATOR) {
963 /* assume the administrator has them all */
964 return NT_STATUS_OK;
967 talloc_free(tmp_ctx);
969 return smblsa_sid_check_privilege(cli, sid_str, privilege);