s3:connections: add a CNUM_OFFSET for mapping between cnum and the bitmap index
[Samba.git] / source4 / torture / util_smb.c
blob93993fd80f6c07eb780e9615c56fab8cc99018f6
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/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"
40 /**
41 setup a directory ready for a test
43 _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
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;
51 return true;
55 create a directory, returning a handle to it
57 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
59 NTSTATUS status;
60 union smb_open io;
61 TALLOC_CTX *mem_ctx;
63 mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
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;
78 status = smb_raw_open(tree, mem_ctx, &io);
79 talloc_free(mem_ctx);
81 if (NT_STATUS_IS_OK(status)) {
82 *fnum = io.ntcreatex.out.file.fnum;
85 return status;
89 /**
90 sometimes we need a fairly complex file to work with, so we can test
91 all possible attributes.
93 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
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;
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;
113 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
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");
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;
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);
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));
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;
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));
159 if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
160 printf("create_time not setup correctly\n");
162 if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
163 printf("access_time not setup correctly\n");
165 if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
166 printf("write_time not setup correctly\n");
169 return fnum;
174 sometimes we need a fairly complex directory to work with, so we can test
175 all possible attributes.
177 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
179 int fnum;
180 union smb_setfileinfo setfile;
181 union smb_fileinfo fileinfo;
182 time_t t = (time(NULL) & ~1);
183 NTSTATUS status;
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;
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");
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;
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);
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));
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;
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));
239 if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
240 printf("create_time not setup correctly\n");
242 if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
243 printf("access_time not setup correctly\n");
245 if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
246 printf("write_time not setup correctly\n");
249 return fnum;
254 /* return a pointer to a anonymous shared memory segment of size "size"
255 which will persist across fork() but will disappear when all processes
256 exit
258 The memory is not zeroed
260 This function uses system5 shared memory. It takes advantage of a property
261 that the memory is not destroyed if it is attached when the id is removed
263 void *shm_setup(int size)
265 int shmid;
266 void *ret;
268 #ifdef __QNXNTO__
269 shmid = shm_open("private", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
270 if (shmid == -1) {
271 printf("can't get shared memory\n");
272 exit(1);
274 shm_unlink("private");
275 if (ftruncate(shmid, size) == -1) {
276 printf("can't set shared memory size\n");
277 exit(1);
279 ret = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0);
280 if (ret == MAP_FAILED) {
281 printf("can't map shared memory\n");
282 exit(1);
284 #else
285 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
286 if (shmid == -1) {
287 printf("can't get shared memory\n");
288 exit(1);
290 ret = (void *)shmat(shmid, 0, 0);
291 if (!ret || ret == (void *)-1) {
292 printf("can't attach to shared memory\n");
293 return NULL;
295 /* the following releases the ipc, but note that this process
296 and all its children will still have access to the memory, its
297 just that the shmid is no longer valid for other shm calls. This
298 means we don't leave behind lots of shm segments after we exit
300 See Stevens "advanced programming in unix env" for details
302 shmctl(shmid, IPC_RMID, 0);
303 #endif
305 return ret;
310 check that a wire string matches the flags specified
311 not 100% accurate, but close enough for testing
313 bool wire_bad_flags(struct smb_wire_string *str, int flags,
314 struct smbcli_transport *transport)
316 bool server_unicode;
317 int len;
318 if (!str || !str->s) return true;
319 len = strlen(str->s);
320 if (flags & STR_TERMINATE) len++;
322 server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
323 if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
324 server_unicode = false;
327 if ((flags & STR_UNICODE) || server_unicode) {
328 len *= 2;
329 } else if (flags & STR_TERMINATE_ASCII) {
330 len++;
332 if (str->private_length != len) {
333 printf("Expected wire_length %d but got %d for '%s'\n",
334 len, str->private_length, str->s);
335 return true;
337 return false;
341 dump a all_info QFILEINFO structure
343 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
345 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
346 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
347 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
348 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
349 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
350 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
351 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
352 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
353 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
354 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
355 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
356 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
360 dump file infor by name
362 void torture_all_info(struct smbcli_tree *tree, const char *fname)
364 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
365 union smb_fileinfo finfo;
366 NTSTATUS status;
368 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
369 finfo.generic.in.file.path = fname;
370 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
371 if (!NT_STATUS_IS_OK(status)) {
372 d_printf("%s - %s\n", fname, nt_errstr(status));
373 return;
376 d_printf("%s:\n", fname);
377 dump_all_info(mem_ctx, &finfo);
378 talloc_free(mem_ctx);
383 set a attribute on a file
385 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
387 union smb_setfileinfo sfinfo;
388 NTSTATUS status;
390 ZERO_STRUCT(sfinfo.basic_info.in);
391 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
392 sfinfo.basic_info.in.file.path = fname;
393 sfinfo.basic_info.in.attrib = attrib;
394 status = smb_raw_setpathinfo(tree, &sfinfo);
395 return NT_STATUS_IS_OK(status);
400 set a file descriptor as sparse
402 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
404 union smb_ioctl nt;
405 NTSTATUS status;
406 TALLOC_CTX *mem_ctx;
408 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
409 if (!mem_ctx) {
410 return NT_STATUS_NO_MEMORY;
413 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
414 nt.ntioctl.in.function = FSCTL_SET_SPARSE;
415 nt.ntioctl.in.file.fnum = fnum;
416 nt.ntioctl.in.fsctl = true;
417 nt.ntioctl.in.filter = 0;
418 nt.ntioctl.in.max_data = 0;
419 nt.ntioctl.in.blob = data_blob(NULL, 0);
421 status = smb_raw_ioctl(tree, mem_ctx, &nt);
423 talloc_free(mem_ctx);
425 return status;
429 check that an EA has the right value
431 NTSTATUS torture_check_ea(struct smbcli_state *cli,
432 const char *fname, const char *eaname, const char *value)
434 union smb_fileinfo info;
435 NTSTATUS status;
436 struct ea_name ea;
437 TALLOC_CTX *mem_ctx = talloc_new(cli);
439 info.ea_list.level = RAW_FILEINFO_EA_LIST;
440 info.ea_list.in.file.path = fname;
441 info.ea_list.in.num_names = 1;
442 info.ea_list.in.ea_names = &ea;
444 ea.name.s = eaname;
446 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
447 if (!NT_STATUS_IS_OK(status)) {
448 talloc_free(mem_ctx);
449 return status;
452 if (info.ea_list.out.num_eas != 1) {
453 printf("Expected 1 ea in ea_list\n");
454 talloc_free(mem_ctx);
455 return NT_STATUS_EA_CORRUPT_ERROR;
458 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
459 printf("Expected ea '%s' not '%s' in ea_list\n",
460 eaname, info.ea_list.out.eas[0].name.s);
461 talloc_free(mem_ctx);
462 return NT_STATUS_EA_CORRUPT_ERROR;
465 if (value == NULL) {
466 if (info.ea_list.out.eas[0].value.length != 0) {
467 printf("Expected zero length ea for %s\n", eaname);
468 talloc_free(mem_ctx);
469 return NT_STATUS_EA_CORRUPT_ERROR;
471 talloc_free(mem_ctx);
472 return NT_STATUS_OK;
475 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
476 memcmp(value, info.ea_list.out.eas[0].value.data,
477 info.ea_list.out.eas[0].value.length) == 0) {
478 talloc_free(mem_ctx);
479 return NT_STATUS_OK;
482 printf("Expected value '%s' not '%*.*s' for ea %s\n",
483 value,
484 (int)info.ea_list.out.eas[0].value.length,
485 (int)info.ea_list.out.eas[0].value.length,
486 info.ea_list.out.eas[0].value.data,
487 eaname);
489 talloc_free(mem_ctx);
491 return NT_STATUS_EA_CORRUPT_ERROR;
494 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
495 struct smbcli_state **c,
496 struct torture_context *tctx,
497 const char *hostname,
498 const char *sharename,
499 struct tevent_context *ev)
501 NTSTATUS status;
503 struct smbcli_options options;
504 struct smbcli_session_options session_options;
506 lpcfg_smbcli_options(tctx->lp_ctx, &options);
507 lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
509 options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
510 options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
512 status = smbcli_full_connection(mem_ctx, c, hostname,
513 lpcfg_smb_ports(tctx->lp_ctx),
514 sharename, NULL,
515 lpcfg_socket_options(tctx->lp_ctx),
516 cmdline_credentials,
517 lpcfg_resolve_context(tctx->lp_ctx),
518 ev, &options, &session_options,
519 lpcfg_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 p = unc_list[conn_index % num_unc_names];
552 if (p[0] != '/' && p[0] != '\\') {
553 /* allow UNC lists of hosts */
554 (*host) = talloc_strdup(mem_ctx, p);
555 } else if (!smbcli_parse_unc(p, mem_ctx, host, share)) {
556 DEBUG(0, ("Failed to parse UNC name %s\n",
557 unc_list[conn_index % num_unc_names]));
558 return false;
561 talloc_free(unc_list);
562 return true;
567 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
568 int conn_index,
569 struct torture_context *tctx,
570 struct tevent_context *ev)
572 char *host, *share;
573 bool ret;
575 if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
576 return false;
579 ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
580 talloc_free(host);
581 talloc_free(share);
583 return ret;
586 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
588 return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
593 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
595 bool ret = true;
596 if (!c) return true;
597 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
598 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
599 ret = false;
601 talloc_free(c);
602 return ret;
606 /* check if the server produced the expected error code */
607 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
608 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
610 NTSTATUS status;
612 status = smbcli_nt_error(c->tree);
613 if (NT_STATUS_IS_DOS(status)) {
614 int classnum, num;
615 classnum = NT_STATUS_DOS_CLASS(status);
616 num = NT_STATUS_DOS_CODE(status);
617 if (eclass != classnum || ecode != num) {
618 printf("unexpected error code %s\n", nt_errstr(status));
619 printf(" expected %s or %s (at %s)\n",
620 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
621 nt_errstr(nterr), location);
622 return false;
624 } else {
625 if (!NT_STATUS_EQUAL(nterr, status)) {
626 printf("unexpected error code %s\n", nt_errstr(status));
627 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
628 return false;
632 return true;
635 static struct smbcli_state *current_cli;
636 static int procnum; /* records process count number when forking */
638 static void sigcont(int sig)
642 double torture_create_procs(struct torture_context *tctx,
643 bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
645 int i, status;
646 volatile pid_t *child_status;
647 volatile bool *child_status_out;
648 int synccount;
649 int tries = 8;
650 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
651 double start_time_limit = 10 + (torture_nprocs * 1.5);
652 struct timeval tv;
654 *result = true;
656 synccount = 0;
658 signal(SIGCONT, sigcont);
660 child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
661 if (!child_status) {
662 printf("Failed to setup shared memory\n");
663 return -1;
666 child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
667 if (!child_status_out) {
668 printf("Failed to setup result status shared memory\n");
669 return -1;
672 for (i = 0; i < torture_nprocs; i++) {
673 child_status[i] = 0;
674 child_status_out[i] = true;
677 tv = timeval_current();
679 for (i=0;i<torture_nprocs;i++) {
680 procnum = i;
681 if (fork() == 0) {
682 char *myname;
684 pid_t mypid = getpid();
685 srandom(((int)mypid) ^ ((int)time(NULL)));
687 if (asprintf(&myname, "CLIENT%d", i) == -1) {
688 printf("asprintf failed\n");
689 return -1;
691 lpcfg_set_cmdline(tctx->lp_ctx, "netbios name", myname);
692 free(myname);
695 while (1) {
696 if (torture_open_connection(&current_cli, tctx, i)) {
697 break;
699 if (tries-- == 0) {
700 printf("pid %d failed to start\n", (int)getpid());
701 _exit(1);
703 smb_msleep(100);
706 child_status[i] = getpid();
708 pause();
710 if (child_status[i]) {
711 printf("Child %d failed to start!\n", i);
712 child_status_out[i] = 1;
713 _exit(1);
716 child_status_out[i] = fn(tctx, current_cli, i);
717 _exit(0);
721 do {
722 synccount = 0;
723 for (i=0;i<torture_nprocs;i++) {
724 if (child_status[i]) synccount++;
726 if (synccount == torture_nprocs) break;
727 smb_msleep(100);
728 } while (timeval_elapsed(&tv) < start_time_limit);
730 if (synccount != torture_nprocs) {
731 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
733 /* cleanup child processes */
734 for (i = 0; i < torture_nprocs; i++) {
735 if (child_status[i]) {
736 kill(child_status[i], SIGTERM);
740 *result = false;
741 return timeval_elapsed(&tv);
744 printf("Starting %d clients\n", torture_nprocs);
746 /* start the client load */
747 tv = timeval_current();
748 for (i=0;i<torture_nprocs;i++) {
749 child_status[i] = 0;
752 printf("%d clients started\n", torture_nprocs);
754 kill(0, SIGCONT);
756 for (i=0;i<torture_nprocs;i++) {
757 int ret;
758 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
759 if (ret == -1 || WEXITSTATUS(status) != 0) {
760 *result = false;
764 printf("\n");
766 for (i=0;i<torture_nprocs;i++) {
767 if (!child_status_out[i]) {
768 *result = false;
771 return timeval_elapsed(&tv);
774 static bool wrap_smb_multi_test(struct torture_context *torture,
775 struct torture_tcase *tcase,
776 struct torture_test *test)
778 bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
779 bool result;
781 torture_create_procs(torture, fn, &result);
783 return result;
786 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
787 struct torture_suite *suite,
788 const char *name,
789 bool (*run) (struct torture_context *,
790 struct smbcli_state *,
791 int i))
793 struct torture_test *test;
794 struct torture_tcase *tcase;
796 tcase = torture_suite_add_tcase(suite, name);
798 test = talloc(tcase, struct torture_test);
800 test->name = talloc_strdup(test, name);
801 test->description = NULL;
802 test->run = wrap_smb_multi_test;
803 test->fn = run;
804 test->dangerous = false;
806 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
808 return test;
812 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
813 struct torture_tcase *tcase,
814 struct torture_test *test)
816 bool (*fn) (struct torture_context *, struct smbcli_state *,
817 struct smbcli_state *);
818 bool ret = true;
820 struct smbcli_state *cli1 = NULL, *cli2 = NULL;
822 torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
823 torture_assert_goto(torture_ctx, torture_open_connection(&cli2, torture_ctx, 1), ret, fail, "Failed to open connection");
825 fn = test->fn;
827 ret = fn(torture_ctx, cli1, cli2);
828 fail:
829 talloc_free(cli1);
830 talloc_free(cli2);
832 return ret;
837 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
838 struct torture_suite *suite,
839 const char *name,
840 bool (*run) (struct torture_context *,
841 struct smbcli_state *,
842 struct smbcli_state *))
844 struct torture_test *test;
845 struct torture_tcase *tcase;
847 tcase = torture_suite_add_tcase(suite, name);
849 test = talloc(tcase, struct torture_test);
851 test->name = talloc_strdup(test, name);
852 test->description = NULL;
853 test->run = wrap_simple_2smb_test;
854 test->fn = run;
855 test->dangerous = false;
857 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
859 return test;
863 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
864 struct torture_tcase *tcase,
865 struct torture_test *test)
867 bool (*fn) (struct torture_context *, struct smbcli_state *);
868 bool ret = true;
870 struct smbcli_state *cli1 = NULL;
872 torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
874 fn = test->fn;
876 ret = fn(torture_ctx, cli1);
877 fail:
878 talloc_free(cli1);
880 return ret;
883 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
884 struct torture_suite *suite,
885 const char *name,
886 bool (*run) (struct torture_context *, struct smbcli_state *))
888 struct torture_test *test;
889 struct torture_tcase *tcase;
891 tcase = torture_suite_add_tcase(suite, name);
893 test = talloc(tcase, struct torture_test);
895 test->name = talloc_strdup(test, name);
896 test->description = NULL;
897 test->run = wrap_simple_1smb_test;
898 test->fn = run;
899 test->dangerous = false;
901 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
903 return test;
907 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
908 struct smbcli_session *session,
909 const char *sharename,
910 struct smbcli_tree **res)
912 union smb_tcon tcon;
913 struct smbcli_tree *result;
914 TALLOC_CTX *tmp_ctx;
915 NTSTATUS status;
917 if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
918 return NT_STATUS_NO_MEMORY;
921 result = smbcli_tree_init(session, tmp_ctx, false);
922 if (result == NULL) {
923 talloc_free(tmp_ctx);
924 return NT_STATUS_NO_MEMORY;
927 tcon.generic.level = RAW_TCON_TCONX;
928 tcon.tconx.in.flags = 0;
930 /* Ignore share mode security here */
931 tcon.tconx.in.password = data_blob(NULL, 0);
932 tcon.tconx.in.path = sharename;
933 tcon.tconx.in.device = "?????";
935 status = smb_raw_tcon(result, tmp_ctx, &tcon);
936 if (!NT_STATUS_IS_OK(status)) {
937 talloc_free(tmp_ctx);
938 return status;
941 result->tid = tcon.tconx.out.tid;
942 *res = talloc_steal(mem_ctx, result);
943 talloc_free(tmp_ctx);
944 return NT_STATUS_OK;
948 a wrapper around smblsa_sid_check_privilege, that tries to take
949 account of the fact that the lsa privileges calls don't expand
950 group memberships, using an explicit check for administrator. There
951 must be a better way ...
953 NTSTATUS torture_check_privilege(struct smbcli_state *cli,
954 const char *sid_str,
955 const char *privilege)
957 struct dom_sid *sid;
958 TALLOC_CTX *tmp_ctx = talloc_new(cli);
959 uint32_t rid;
960 NTSTATUS status;
962 sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
963 if (sid == NULL) {
964 talloc_free(tmp_ctx);
965 return NT_STATUS_INVALID_SID;
968 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
969 NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
971 if (rid == DOMAIN_RID_ADMINISTRATOR) {
972 /* assume the administrator has them all */
973 return NT_STATUS_OK;
976 talloc_free(tmp_ctx);
978 return smblsa_sid_check_privilege(cli, sid_str, privilege);