s3: Fix bug #9085.
[Samba.git] / source4 / torture / util_smb.c
blob99b00d232939febb7f42dcb967a3e5c16b0727a9
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 "auth/credentials/credentials.h"
34 #include "libcli/resolve/resolve.h"
35 #include "param/param.h"
38 /**
39 setup a directory ready for a test
41 _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
43 smb_raw_exit(cli->session);
44 if (smbcli_deltree(cli->tree, dname) == -1 ||
45 NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
46 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
47 return false;
49 return true;
53 create a directory, returning a handle to it
55 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
57 NTSTATUS status;
58 union smb_open io;
59 TALLOC_CTX *mem_ctx;
61 mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
63 io.generic.level = RAW_OPEN_NTCREATEX;
64 io.ntcreatex.in.root_fid = 0;
65 io.ntcreatex.in.flags = 0;
66 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
67 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
68 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
69 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
70 io.ntcreatex.in.alloc_size = 0;
71 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
72 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
73 io.ntcreatex.in.security_flags = 0;
74 io.ntcreatex.in.fname = dname;
76 status = smb_raw_open(tree, mem_ctx, &io);
77 talloc_free(mem_ctx);
79 if (NT_STATUS_IS_OK(status)) {
80 *fnum = io.ntcreatex.out.file.fnum;
83 return status;
87 /**
88 sometimes we need a fairly complex file to work with, so we can test
89 all possible attributes.
91 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
93 int fnum;
94 char buf[7] = "abc";
95 union smb_setfileinfo setfile;
96 union smb_fileinfo fileinfo;
97 time_t t = (time(NULL) & ~1);
98 NTSTATUS status;
100 smbcli_unlink(cli->tree, fname);
101 fnum = smbcli_nt_create_full(cli->tree, fname, 0,
102 SEC_RIGHTS_FILE_ALL,
103 FILE_ATTRIBUTE_NORMAL,
104 NTCREATEX_SHARE_ACCESS_DELETE|
105 NTCREATEX_SHARE_ACCESS_READ|
106 NTCREATEX_SHARE_ACCESS_WRITE,
107 NTCREATEX_DISP_OVERWRITE_IF,
108 0, 0);
109 if (fnum == -1) return -1;
111 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
113 if (strchr(fname, ':') == NULL) {
114 /* setup some EAs */
115 setfile.generic.level = RAW_SFILEINFO_EA_SET;
116 setfile.generic.in.file.fnum = fnum;
117 setfile.ea_set.in.num_eas = 2;
118 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
119 setfile.ea_set.in.eas[0].flags = 0;
120 setfile.ea_set.in.eas[0].name.s = "EAONE";
121 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
122 setfile.ea_set.in.eas[1].flags = 0;
123 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
124 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
125 status = smb_raw_setfileinfo(cli->tree, &setfile);
126 if (!NT_STATUS_IS_OK(status)) {
127 printf("Failed to setup EAs\n");
131 /* make sure all the timestamps aren't the same, and are also
132 in different DST zones*/
133 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
134 setfile.generic.in.file.fnum = fnum;
136 setfile.setattre.in.create_time = t + 9*30*24*60*60;
137 setfile.setattre.in.access_time = t + 6*30*24*60*60;
138 setfile.setattre.in.write_time = t + 3*30*24*60*60;
140 status = smb_raw_setfileinfo(cli->tree, &setfile);
141 if (!NT_STATUS_IS_OK(status)) {
142 printf("Failed to setup file times - %s\n", nt_errstr(status));
145 /* make sure all the timestamps aren't the same */
146 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
147 fileinfo.generic.in.file.fnum = fnum;
149 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
150 if (!NT_STATUS_IS_OK(status)) {
151 printf("Failed to query file times - %s\n", nt_errstr(status));
154 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
155 printf("create_time not setup correctly\n");
157 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
158 printf("access_time not setup correctly\n");
160 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
161 printf("write_time not setup correctly\n");
164 return fnum;
169 sometimes we need a fairly complex directory to work with, so we can test
170 all possible attributes.
172 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
174 int fnum;
175 union smb_setfileinfo setfile;
176 union smb_fileinfo fileinfo;
177 time_t t = (time(NULL) & ~1);
178 NTSTATUS status;
180 smbcli_deltree(cli->tree, dname);
181 fnum = smbcli_nt_create_full(cli->tree, dname, 0,
182 SEC_RIGHTS_DIR_ALL,
183 FILE_ATTRIBUTE_DIRECTORY,
184 NTCREATEX_SHARE_ACCESS_READ|
185 NTCREATEX_SHARE_ACCESS_WRITE,
186 NTCREATEX_DISP_OPEN_IF,
187 NTCREATEX_OPTIONS_DIRECTORY, 0);
188 if (fnum == -1) return -1;
190 if (strchr(dname, ':') == NULL) {
191 /* setup some EAs */
192 setfile.generic.level = RAW_SFILEINFO_EA_SET;
193 setfile.generic.in.file.fnum = fnum;
194 setfile.ea_set.in.num_eas = 2;
195 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
196 setfile.ea_set.in.eas[0].flags = 0;
197 setfile.ea_set.in.eas[0].name.s = "EAONE";
198 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
199 setfile.ea_set.in.eas[1].flags = 0;
200 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
201 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
202 status = smb_raw_setfileinfo(cli->tree, &setfile);
203 if (!NT_STATUS_IS_OK(status)) {
204 printf("Failed to setup EAs\n");
208 /* make sure all the timestamps aren't the same, and are also
209 in different DST zones*/
210 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
211 setfile.generic.in.file.fnum = fnum;
213 setfile.setattre.in.create_time = t + 9*30*24*60*60;
214 setfile.setattre.in.access_time = t + 6*30*24*60*60;
215 setfile.setattre.in.write_time = t + 3*30*24*60*60;
217 status = smb_raw_setfileinfo(cli->tree, &setfile);
218 if (!NT_STATUS_IS_OK(status)) {
219 printf("Failed to setup file times - %s\n", nt_errstr(status));
222 /* make sure all the timestamps aren't the same */
223 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
224 fileinfo.generic.in.file.fnum = fnum;
226 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
227 if (!NT_STATUS_IS_OK(status)) {
228 printf("Failed to query file times - %s\n", nt_errstr(status));
231 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
232 printf("create_time not setup correctly\n");
234 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
235 printf("access_time not setup correctly\n");
237 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
238 printf("write_time not setup correctly\n");
241 return fnum;
246 /* return a pointer to a anonymous shared memory segment of size "size"
247 which will persist across fork() but will disappear when all processes
248 exit
250 The memory is not zeroed
252 This function uses system5 shared memory. It takes advantage of a property
253 that the memory is not destroyed if it is attached when the id is removed
255 void *shm_setup(int size)
257 int shmid;
258 void *ret;
260 #ifdef __QNXNTO__
261 shmid = shm_open("private", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
262 if (shmid == -1) {
263 printf("can't get shared memory\n");
264 exit(1);
266 shm_unlink("private");
267 if (ftruncate(shmid, size) == -1) {
268 printf("can't set shared memory size\n");
269 exit(1);
271 ret = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0);
272 if (ret == MAP_FAILED) {
273 printf("can't map shared memory\n");
274 exit(1);
276 #else
277 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
278 if (shmid == -1) {
279 printf("can't get shared memory\n");
280 exit(1);
282 ret = (void *)shmat(shmid, 0, 0);
283 if (!ret || ret == (void *)-1) {
284 printf("can't attach to shared memory\n");
285 return NULL;
287 /* the following releases the ipc, but note that this process
288 and all its children will still have access to the memory, its
289 just that the shmid is no longer valid for other shm calls. This
290 means we don't leave behind lots of shm segments after we exit
292 See Stevens "advanced programming in unix env" for details
294 shmctl(shmid, IPC_RMID, 0);
295 #endif
297 return ret;
302 check that a wire string matches the flags specified
303 not 100% accurate, but close enough for testing
305 bool wire_bad_flags(struct smb_wire_string *str, int flags,
306 struct smbcli_transport *transport)
308 bool server_unicode;
309 int len;
310 if (!str || !str->s) return true;
311 len = strlen(str->s);
312 if (flags & STR_TERMINATE) len++;
314 server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
315 if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
316 server_unicode = false;
319 if ((flags & STR_UNICODE) || server_unicode) {
320 len *= 2;
321 } else if (flags & STR_TERMINATE_ASCII) {
322 len++;
324 if (str->private_length != len) {
325 printf("Expected wire_length %d but got %d for '%s'\n",
326 len, str->private_length, str->s);
327 return true;
329 return false;
333 dump a all_info QFILEINFO structure
335 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
337 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
338 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
339 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
340 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
341 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
342 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
343 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
344 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
345 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
346 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
347 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
348 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
352 dump file infor by name
354 void torture_all_info(struct smbcli_tree *tree, const char *fname)
356 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
357 union smb_fileinfo finfo;
358 NTSTATUS status;
360 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
361 finfo.generic.in.file.path = fname;
362 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
363 if (!NT_STATUS_IS_OK(status)) {
364 d_printf("%s - %s\n", fname, nt_errstr(status));
365 return;
368 d_printf("%s:\n", fname);
369 dump_all_info(mem_ctx, &finfo);
370 talloc_free(mem_ctx);
375 set a attribute on a file
377 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
379 union smb_setfileinfo sfinfo;
380 NTSTATUS status;
382 ZERO_STRUCT(sfinfo.basic_info.in);
383 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
384 sfinfo.basic_info.in.file.path = fname;
385 sfinfo.basic_info.in.attrib = attrib;
386 status = smb_raw_setpathinfo(tree, &sfinfo);
387 return NT_STATUS_IS_OK(status);
392 set a file descriptor as sparse
394 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
396 union smb_ioctl nt;
397 NTSTATUS status;
398 TALLOC_CTX *mem_ctx;
400 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
401 if (!mem_ctx) {
402 return NT_STATUS_NO_MEMORY;
405 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
406 nt.ntioctl.in.function = FSCTL_SET_SPARSE;
407 nt.ntioctl.in.file.fnum = fnum;
408 nt.ntioctl.in.fsctl = true;
409 nt.ntioctl.in.filter = 0;
410 nt.ntioctl.in.max_data = 0;
411 nt.ntioctl.in.blob = data_blob(NULL, 0);
413 status = smb_raw_ioctl(tree, mem_ctx, &nt);
415 talloc_free(mem_ctx);
417 return status;
421 check that an EA has the right value
423 NTSTATUS torture_check_ea(struct smbcli_state *cli,
424 const char *fname, const char *eaname, const char *value)
426 union smb_fileinfo info;
427 NTSTATUS status;
428 struct ea_name ea;
429 TALLOC_CTX *mem_ctx = talloc_new(cli);
431 info.ea_list.level = RAW_FILEINFO_EA_LIST;
432 info.ea_list.in.file.path = fname;
433 info.ea_list.in.num_names = 1;
434 info.ea_list.in.ea_names = &ea;
436 ea.name.s = eaname;
438 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
439 if (!NT_STATUS_IS_OK(status)) {
440 talloc_free(mem_ctx);
441 return status;
444 if (info.ea_list.out.num_eas != 1) {
445 printf("Expected 1 ea in ea_list\n");
446 talloc_free(mem_ctx);
447 return NT_STATUS_EA_CORRUPT_ERROR;
450 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
451 printf("Expected ea '%s' not '%s' in ea_list\n",
452 eaname, info.ea_list.out.eas[0].name.s);
453 talloc_free(mem_ctx);
454 return NT_STATUS_EA_CORRUPT_ERROR;
457 if (value == NULL) {
458 if (info.ea_list.out.eas[0].value.length != 0) {
459 printf("Expected zero length ea for %s\n", eaname);
460 talloc_free(mem_ctx);
461 return NT_STATUS_EA_CORRUPT_ERROR;
463 talloc_free(mem_ctx);
464 return NT_STATUS_OK;
467 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
468 memcmp(value, info.ea_list.out.eas[0].value.data,
469 info.ea_list.out.eas[0].value.length) == 0) {
470 talloc_free(mem_ctx);
471 return NT_STATUS_OK;
474 printf("Expected value '%s' not '%*.*s' for ea %s\n",
475 value,
476 (int)info.ea_list.out.eas[0].value.length,
477 (int)info.ea_list.out.eas[0].value.length,
478 info.ea_list.out.eas[0].value.data,
479 eaname);
481 talloc_free(mem_ctx);
483 return NT_STATUS_EA_CORRUPT_ERROR;
486 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
487 struct smbcli_state **c,
488 struct torture_context *tctx,
489 const char *hostname,
490 const char *sharename,
491 struct tevent_context *ev)
493 NTSTATUS status;
495 struct smbcli_options options;
496 struct smbcli_session_options session_options;
498 lp_smbcli_options(tctx->lp_ctx, &options);
499 lp_smbcli_session_options(tctx->lp_ctx, &session_options);
501 options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
502 options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
504 status = smbcli_full_connection(mem_ctx, c, hostname,
505 lp_smb_ports(tctx->lp_ctx),
506 sharename, NULL,
507 lp_socket_options(tctx->lp_ctx),
508 cmdline_credentials,
509 lp_resolve_context(tctx->lp_ctx),
510 ev, &options, &session_options,
511 lp_iconv_convenience(tctx->lp_ctx),
512 lp_gensec_settings(tctx, tctx->lp_ctx));
513 if (!NT_STATUS_IS_OK(status)) {
514 printf("Failed to open connection - %s\n", nt_errstr(status));
515 return false;
518 return true;
521 _PUBLIC_ bool torture_get_conn_index(int conn_index,
522 TALLOC_CTX *mem_ctx,
523 struct torture_context *tctx,
524 char **host, char **share)
526 char **unc_list = NULL;
527 int num_unc_names = 0;
528 const char *p;
530 (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
531 (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
533 p = torture_setting_string(tctx, "unclist", NULL);
534 if (!p) {
535 return true;
538 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
539 if (!unc_list || num_unc_names <= 0) {
540 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
541 return false;
544 if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
545 mem_ctx, host, share)) {
546 DEBUG(0, ("Failed to parse UNC name %s\n",
547 unc_list[conn_index % num_unc_names]));
548 return false;
551 talloc_free(unc_list);
552 return true;
557 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
558 int conn_index,
559 struct torture_context *tctx,
560 struct tevent_context *ev)
562 char *host, *share;
563 bool ret;
565 if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
566 return false;
569 ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
570 talloc_free(host);
571 talloc_free(share);
573 return ret;
576 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
578 return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
583 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
585 bool ret = true;
586 if (!c) return true;
587 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
588 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
589 ret = false;
591 talloc_free(c);
592 return ret;
596 /* check if the server produced the expected error code */
597 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
598 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
600 NTSTATUS status;
602 status = smbcli_nt_error(c->tree);
603 if (NT_STATUS_IS_DOS(status)) {
604 int classnum, num;
605 classnum = NT_STATUS_DOS_CLASS(status);
606 num = NT_STATUS_DOS_CODE(status);
607 if (eclass != classnum || ecode != num) {
608 printf("unexpected error code %s\n", nt_errstr(status));
609 printf(" expected %s or %s (at %s)\n",
610 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
611 nt_errstr(nterr), location);
612 return false;
614 } else {
615 if (!NT_STATUS_EQUAL(nterr, status)) {
616 printf("unexpected error code %s\n", nt_errstr(status));
617 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
618 return false;
622 return true;
625 static struct smbcli_state *current_cli;
626 static int procnum; /* records process count number when forking */
628 static void sigcont(int sig)
632 double torture_create_procs(struct torture_context *tctx,
633 bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
635 int i, status;
636 volatile pid_t *child_status;
637 volatile bool *child_status_out;
638 int synccount;
639 int tries = 8;
640 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
641 double start_time_limit = 10 + (torture_nprocs * 1.5);
642 struct timeval tv;
644 *result = true;
646 synccount = 0;
648 signal(SIGCONT, sigcont);
650 child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
651 if (!child_status) {
652 printf("Failed to setup shared memory\n");
653 return -1;
656 child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
657 if (!child_status_out) {
658 printf("Failed to setup result status shared memory\n");
659 return -1;
662 for (i = 0; i < torture_nprocs; i++) {
663 child_status[i] = 0;
664 child_status_out[i] = true;
667 tv = timeval_current();
669 for (i=0;i<torture_nprocs;i++) {
670 procnum = i;
671 if (fork() == 0) {
672 char *myname;
674 pid_t mypid = getpid();
675 srandom(((int)mypid) ^ ((int)time(NULL)));
677 if (asprintf(&myname, "CLIENT%d", i) == -1) {
678 printf("asprintf failed\n");
679 return -1;
681 lp_set_cmdline(tctx->lp_ctx, "netbios name", myname);
682 free(myname);
685 while (1) {
686 if (torture_open_connection(&current_cli, tctx, i)) {
687 break;
689 if (tries-- == 0) {
690 printf("pid %d failed to start\n", (int)getpid());
691 _exit(1);
693 msleep(100);
696 child_status[i] = getpid();
698 pause();
700 if (child_status[i]) {
701 printf("Child %d failed to start!\n", i);
702 child_status_out[i] = 1;
703 _exit(1);
706 child_status_out[i] = fn(tctx, current_cli, i);
707 _exit(0);
711 do {
712 synccount = 0;
713 for (i=0;i<torture_nprocs;i++) {
714 if (child_status[i]) synccount++;
716 if (synccount == torture_nprocs) break;
717 msleep(100);
718 } while (timeval_elapsed(&tv) < start_time_limit);
720 if (synccount != torture_nprocs) {
721 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
722 *result = false;
723 return timeval_elapsed(&tv);
726 printf("Starting %d clients\n", torture_nprocs);
728 /* start the client load */
729 tv = timeval_current();
730 for (i=0;i<torture_nprocs;i++) {
731 child_status[i] = 0;
734 printf("%d clients started\n", torture_nprocs);
736 kill(0, SIGCONT);
738 for (i=0;i<torture_nprocs;i++) {
739 int ret;
740 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
741 if (ret == -1 || WEXITSTATUS(status) != 0) {
742 *result = false;
746 printf("\n");
748 for (i=0;i<torture_nprocs;i++) {
749 if (!child_status_out[i]) {
750 *result = false;
753 return timeval_elapsed(&tv);
756 static bool wrap_smb_multi_test(struct torture_context *torture,
757 struct torture_tcase *tcase,
758 struct torture_test *test)
760 bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
761 bool result;
763 torture_create_procs(torture, fn, &result);
765 return result;
768 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
769 struct torture_suite *suite,
770 const char *name,
771 bool (*run) (struct torture_context *,
772 struct smbcli_state *,
773 int i))
775 struct torture_test *test;
776 struct torture_tcase *tcase;
778 tcase = torture_suite_add_tcase(suite, name);
780 test = talloc(tcase, struct torture_test);
782 test->name = talloc_strdup(test, name);
783 test->description = NULL;
784 test->run = wrap_smb_multi_test;
785 test->fn = run;
786 test->dangerous = false;
788 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
790 return test;
794 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
795 struct torture_tcase *tcase,
796 struct torture_test *test)
798 bool (*fn) (struct torture_context *, struct smbcli_state *,
799 struct smbcli_state *);
800 bool ret;
802 struct smbcli_state *cli1, *cli2;
804 if (!torture_open_connection(&cli1, torture_ctx, 0) ||
805 !torture_open_connection(&cli2, torture_ctx, 1))
806 return false;
808 fn = test->fn;
810 ret = fn(torture_ctx, cli1, cli2);
812 talloc_free(cli1);
813 talloc_free(cli2);
815 return ret;
820 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
821 struct torture_suite *suite,
822 const char *name,
823 bool (*run) (struct torture_context *,
824 struct smbcli_state *,
825 struct smbcli_state *))
827 struct torture_test *test;
828 struct torture_tcase *tcase;
830 tcase = torture_suite_add_tcase(suite, name);
832 test = talloc(tcase, struct torture_test);
834 test->name = talloc_strdup(test, name);
835 test->description = NULL;
836 test->run = wrap_simple_2smb_test;
837 test->fn = run;
838 test->dangerous = false;
840 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
842 return test;
846 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
847 struct torture_tcase *tcase,
848 struct torture_test *test)
850 bool (*fn) (struct torture_context *, struct smbcli_state *);
851 bool ret;
853 struct smbcli_state *cli1;
855 if (!torture_open_connection(&cli1, torture_ctx, 0))
856 return false;
858 fn = test->fn;
860 ret = fn(torture_ctx, cli1);
862 talloc_free(cli1);
864 return ret;
867 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
868 struct torture_suite *suite,
869 const char *name,
870 bool (*run) (struct torture_context *, struct smbcli_state *))
872 struct torture_test *test;
873 struct torture_tcase *tcase;
875 tcase = torture_suite_add_tcase(suite, name);
877 test = talloc(tcase, struct torture_test);
879 test->name = talloc_strdup(test, name);
880 test->description = NULL;
881 test->run = wrap_simple_1smb_test;
882 test->fn = run;
883 test->dangerous = false;
885 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
887 return test;
891 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
892 struct smbcli_session *session,
893 const char *sharename,
894 struct smbcli_tree **res)
896 union smb_tcon tcon;
897 struct smbcli_tree *result;
898 TALLOC_CTX *tmp_ctx;
899 NTSTATUS status;
901 if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
902 return NT_STATUS_NO_MEMORY;
905 result = smbcli_tree_init(session, tmp_ctx, false);
906 if (result == NULL) {
907 talloc_free(tmp_ctx);
908 return NT_STATUS_NO_MEMORY;
911 tcon.generic.level = RAW_TCON_TCONX;
912 tcon.tconx.in.flags = 0;
914 /* Ignore share mode security here */
915 tcon.tconx.in.password = data_blob(NULL, 0);
916 tcon.tconx.in.path = sharename;
917 tcon.tconx.in.device = "?????";
919 status = smb_raw_tcon(result, tmp_ctx, &tcon);
920 if (!NT_STATUS_IS_OK(status)) {
921 talloc_free(tmp_ctx);
922 return status;
925 result->tid = tcon.tconx.out.tid;
926 *res = talloc_steal(mem_ctx, result);
927 talloc_free(tmp_ctx);
928 return NT_STATUS_OK;