s4-torture: use tctx variable name in raw notify test consistently.
[Samba.git] / source4 / torture / util_smb.c
blob0520f275a4cd88a8690748a7876a80c61d8d2538
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"
38 #include "libcli/smb/smbXcli_base.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;
253 check that a wire string matches the flags specified
254 not 100% accurate, but close enough for testing
256 bool wire_bad_flags(struct smb_wire_string *str, int flags,
257 struct smbcli_transport *transport)
259 bool server_unicode;
260 int len;
261 if (!str || !str->s) return true;
262 len = strlen(str->s);
263 if (flags & STR_TERMINATE) len++;
265 server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
266 if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
267 server_unicode = false;
270 if ((flags & STR_UNICODE) || server_unicode) {
271 len *= 2;
272 } else if (flags & STR_TERMINATE_ASCII) {
273 len++;
275 if (str->private_length != len) {
276 printf("Expected wire_length %d but got %d for '%s'\n",
277 len, str->private_length, str->s);
278 return true;
280 return false;
284 dump a all_info QFILEINFO structure
286 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
288 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
289 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
290 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
291 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
292 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
293 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
294 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
295 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
296 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
297 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
298 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
299 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
303 dump file infor by name
305 void torture_all_info(struct smbcli_tree *tree, const char *fname)
307 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
308 union smb_fileinfo finfo;
309 NTSTATUS status;
311 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
312 finfo.generic.in.file.path = fname;
313 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
314 if (!NT_STATUS_IS_OK(status)) {
315 d_printf("%s - %s\n", fname, nt_errstr(status));
316 return;
319 d_printf("%s:\n", fname);
320 dump_all_info(mem_ctx, &finfo);
321 talloc_free(mem_ctx);
326 set a attribute on a file
328 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
330 union smb_setfileinfo sfinfo;
331 NTSTATUS status;
333 ZERO_STRUCT(sfinfo.basic_info.in);
334 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
335 sfinfo.basic_info.in.file.path = fname;
336 sfinfo.basic_info.in.attrib = attrib;
337 status = smb_raw_setpathinfo(tree, &sfinfo);
338 return NT_STATUS_IS_OK(status);
343 set a file descriptor as sparse
345 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
347 union smb_ioctl nt;
348 NTSTATUS status;
349 TALLOC_CTX *mem_ctx;
351 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
352 if (!mem_ctx) {
353 return NT_STATUS_NO_MEMORY;
356 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
357 nt.ntioctl.in.function = FSCTL_SET_SPARSE;
358 nt.ntioctl.in.file.fnum = fnum;
359 nt.ntioctl.in.fsctl = true;
360 nt.ntioctl.in.filter = 0;
361 nt.ntioctl.in.max_data = 0;
362 nt.ntioctl.in.blob = data_blob(NULL, 0);
364 status = smb_raw_ioctl(tree, mem_ctx, &nt);
366 talloc_free(mem_ctx);
368 return status;
372 check that an EA has the right value
374 NTSTATUS torture_check_ea(struct smbcli_state *cli,
375 const char *fname, const char *eaname, const char *value)
377 union smb_fileinfo info;
378 NTSTATUS status;
379 struct ea_name ea;
380 TALLOC_CTX *mem_ctx = talloc_new(cli);
382 info.ea_list.level = RAW_FILEINFO_EA_LIST;
383 info.ea_list.in.file.path = fname;
384 info.ea_list.in.num_names = 1;
385 info.ea_list.in.ea_names = &ea;
387 ea.name.s = eaname;
389 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
390 if (!NT_STATUS_IS_OK(status)) {
391 talloc_free(mem_ctx);
392 return status;
395 if (info.ea_list.out.num_eas != 1) {
396 printf("Expected 1 ea in ea_list\n");
397 talloc_free(mem_ctx);
398 return NT_STATUS_EA_CORRUPT_ERROR;
401 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
402 printf("Expected ea '%s' not '%s' in ea_list\n",
403 eaname, info.ea_list.out.eas[0].name.s);
404 talloc_free(mem_ctx);
405 return NT_STATUS_EA_CORRUPT_ERROR;
408 if (value == NULL) {
409 if (info.ea_list.out.eas[0].value.length != 0) {
410 printf("Expected zero length ea for %s\n", eaname);
411 talloc_free(mem_ctx);
412 return NT_STATUS_EA_CORRUPT_ERROR;
414 talloc_free(mem_ctx);
415 return NT_STATUS_OK;
418 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
419 memcmp(value, info.ea_list.out.eas[0].value.data,
420 info.ea_list.out.eas[0].value.length) == 0) {
421 talloc_free(mem_ctx);
422 return NT_STATUS_OK;
425 printf("Expected value '%s' not '%*.*s' for ea %s\n",
426 value,
427 (int)info.ea_list.out.eas[0].value.length,
428 (int)info.ea_list.out.eas[0].value.length,
429 info.ea_list.out.eas[0].value.data,
430 eaname);
432 talloc_free(mem_ctx);
434 return NT_STATUS_EA_CORRUPT_ERROR;
437 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
438 struct smbcli_state **c,
439 struct torture_context *tctx,
440 const char *hostname,
441 const char *sharename,
442 struct tevent_context *ev)
444 NTSTATUS status;
446 struct smbcli_options options;
447 struct smbcli_session_options session_options;
449 lpcfg_smbcli_options(tctx->lp_ctx, &options);
450 lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
452 options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
453 options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
455 status = smbcli_full_connection(mem_ctx, c, hostname,
456 lpcfg_smb_ports(tctx->lp_ctx),
457 sharename, NULL,
458 lpcfg_socket_options(tctx->lp_ctx),
459 cmdline_credentials,
460 lpcfg_resolve_context(tctx->lp_ctx),
461 ev, &options, &session_options,
462 lpcfg_gensec_settings(tctx, tctx->lp_ctx));
463 if (!NT_STATUS_IS_OK(status)) {
464 printf("Failed to open connection - %s\n", nt_errstr(status));
465 return false;
468 return true;
471 _PUBLIC_ bool torture_get_conn_index(int conn_index,
472 TALLOC_CTX *mem_ctx,
473 struct torture_context *tctx,
474 char **host, char **share)
476 char **unc_list = NULL;
477 int num_unc_names = 0;
478 const char *p;
480 (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
481 (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
483 p = torture_setting_string(tctx, "unclist", NULL);
484 if (!p) {
485 return true;
488 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
489 if (!unc_list || num_unc_names <= 0) {
490 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
491 return false;
494 p = unc_list[conn_index % num_unc_names];
495 if (p[0] != '/' && p[0] != '\\') {
496 /* allow UNC lists of hosts */
497 (*host) = talloc_strdup(mem_ctx, p);
498 } else if (!smbcli_parse_unc(p, mem_ctx, host, share)) {
499 DEBUG(0, ("Failed to parse UNC name %s\n",
500 unc_list[conn_index % num_unc_names]));
501 return false;
504 talloc_free(unc_list);
505 return true;
510 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
511 int conn_index,
512 struct torture_context *tctx,
513 struct tevent_context *ev)
515 char *host, *share;
516 bool ret;
518 if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
519 return false;
522 ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
523 talloc_free(host);
524 talloc_free(share);
526 return ret;
529 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
531 return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
536 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
538 bool ret = true;
539 if (!c) return true;
540 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
541 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
542 ret = false;
544 talloc_free(c);
545 return ret;
549 /* check if the server produced the expected error code */
550 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
551 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
553 NTSTATUS status;
555 status = smbcli_nt_error(c->tree);
556 if (NT_STATUS_IS_DOS(status)) {
557 int classnum, num;
558 classnum = NT_STATUS_DOS_CLASS(status);
559 num = NT_STATUS_DOS_CODE(status);
560 if (eclass != classnum || ecode != num) {
561 printf("unexpected error code %s\n", nt_errstr(status));
562 printf(" expected %s or %s (at %s)\n",
563 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
564 nt_errstr(nterr), location);
565 return false;
567 } else {
568 if (!NT_STATUS_EQUAL(nterr, status)) {
569 printf("unexpected error code %s\n", nt_errstr(status));
570 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
571 return false;
575 return true;
578 static struct smbcli_state *current_cli;
579 static int procnum; /* records process count number when forking */
581 static void sigcont(int sig)
585 struct child_status {
586 pid_t pid;
587 bool start;
588 enum torture_result result;
589 char reason[1024];
592 double torture_create_procs(struct torture_context *tctx,
593 bool (*fn)(struct torture_context *, struct smbcli_state *, int),
594 bool *result)
596 int i, status;
597 struct child_status *child_status;
598 int synccount;
599 int tries = 8;
600 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
601 double start_time_limit = 10 + (torture_nprocs * 1.5);
602 struct timeval tv;
604 *result = true;
606 synccount = 0;
608 signal(SIGCONT, sigcont);
610 child_status = (struct child_status *)anonymous_shared_allocate(
611 sizeof(struct child_status)*torture_nprocs);
612 if (child_status == NULL) {
613 printf("Failed to setup shared memory\n");
614 return -1;
617 for (i = 0; i < torture_nprocs; i++) {
618 ZERO_STRUCT(child_status[i]);
621 tv = timeval_current();
623 for (i=0;i<torture_nprocs;i++) {
624 procnum = i;
625 if (fork() == 0) {
626 char *myname;
627 bool ok;
629 pid_t mypid = getpid();
630 srandom(((int)mypid) ^ ((int)time(NULL)));
632 if (asprintf(&myname, "CLIENT%d", i) == -1) {
633 printf("asprintf failed\n");
634 return -1;
636 lpcfg_set_cmdline(tctx->lp_ctx, "netbios name", myname);
637 free(myname);
640 while (1) {
641 if (torture_open_connection(&current_cli, tctx, i)) {
642 break;
644 if (tries-- == 0) {
645 printf("pid %d failed to start\n", (int)getpid());
646 _exit(1);
648 smb_msleep(100);
651 child_status[i].pid = getpid();
653 pause();
655 if (!child_status[i].start) {
656 child_status[i].result = TORTURE_ERROR;
657 printf("Child %d failed to start!\n", i);
658 _exit(1);
661 ok = fn(tctx, current_cli, i);
662 if (!ok) {
663 if (tctx->last_result == TORTURE_OK) {
664 torture_result(tctx, TORTURE_ERROR,
665 "unknown error: missing "
666 "torture_result call?\n");
669 child_status[i].result = tctx->last_result;
671 if (strlen(tctx->last_reason) > 1023) {
672 /* note: reason already contains \n */
673 torture_comment(tctx,
674 "child %d (pid %u) failed: %s",
676 (unsigned)child_status[i].pid,
677 tctx->last_reason);
680 snprintf(child_status[i].reason,
681 1024, "child %d (pid %u) failed: %s",
682 i, (unsigned)child_status[i].pid,
683 tctx->last_reason);
684 /* ensure proper "\n\0" termination: */
685 if (child_status[i].reason[1022] != '\0') {
686 child_status[i].reason[1022] = '\n';
687 child_status[i].reason[1023] = '\0';
690 _exit(0);
694 do {
695 synccount = 0;
696 for (i=0;i<torture_nprocs;i++) {
697 if (child_status[i].pid != 0) {
698 synccount++;
701 if (synccount == torture_nprocs) {
702 break;
704 smb_msleep(100);
705 } while (timeval_elapsed(&tv) < start_time_limit);
707 if (synccount != torture_nprocs) {
708 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
710 /* cleanup child processes */
711 for (i = 0; i < torture_nprocs; i++) {
712 if (child_status[i].pid != 0) {
713 kill(child_status[i].pid, SIGTERM);
717 *result = false;
718 return timeval_elapsed(&tv);
721 printf("Starting %d clients\n", torture_nprocs);
723 /* start the client load */
724 tv = timeval_current();
725 for (i=0;i<torture_nprocs;i++) {
726 child_status[i].start = true;
729 printf("%d clients started\n", torture_nprocs);
731 kill(0, SIGCONT);
733 for (i=0;i<torture_nprocs;i++) {
734 int ret;
735 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
736 if (ret == -1 || WEXITSTATUS(status) != 0) {
737 *result = false;
741 printf("\n");
743 for (i=0;i<torture_nprocs;i++) {
744 if (child_status[i].result != TORTURE_OK) {
745 *result = false;
746 torture_result(tctx, child_status[i].result,
747 "%s", child_status[i].reason);
751 return timeval_elapsed(&tv);
754 static bool wrap_smb_multi_test(struct torture_context *torture,
755 struct torture_tcase *tcase,
756 struct torture_test *test)
758 bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
759 bool result;
761 torture_create_procs(torture, fn, &result);
763 return result;
766 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
767 struct torture_suite *suite,
768 const char *name,
769 bool (*run) (struct torture_context *,
770 struct smbcli_state *,
771 int i))
773 struct torture_test *test;
774 struct torture_tcase *tcase;
776 tcase = torture_suite_add_tcase(suite, name);
778 test = talloc(tcase, struct torture_test);
780 test->name = talloc_strdup(test, name);
781 test->description = NULL;
782 test->run = wrap_smb_multi_test;
783 test->fn = run;
784 test->dangerous = false;
786 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
788 return test;
792 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
793 struct torture_tcase *tcase,
794 struct torture_test *test)
796 bool (*fn) (struct torture_context *, struct smbcli_state *,
797 struct smbcli_state *);
798 bool ret = true;
800 struct smbcli_state *cli1 = NULL, *cli2 = NULL;
802 torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
803 torture_assert_goto(torture_ctx, torture_open_connection(&cli2, torture_ctx, 1), ret, fail, "Failed to open connection");
805 fn = test->fn;
807 ret = fn(torture_ctx, cli1, cli2);
808 fail:
809 talloc_free(cli1);
810 talloc_free(cli2);
812 return ret;
817 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
818 struct torture_suite *suite,
819 const char *name,
820 bool (*run) (struct torture_context *,
821 struct smbcli_state *,
822 struct smbcli_state *))
824 struct torture_test *test;
825 struct torture_tcase *tcase;
827 tcase = torture_suite_add_tcase(suite, name);
829 test = talloc(tcase, struct torture_test);
831 test->name = talloc_strdup(test, name);
832 test->description = NULL;
833 test->run = wrap_simple_2smb_test;
834 test->fn = run;
835 test->dangerous = false;
837 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
839 return test;
843 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
844 struct torture_tcase *tcase,
845 struct torture_test *test)
847 bool (*fn) (struct torture_context *, struct smbcli_state *);
848 bool ret = true;
850 struct smbcli_state *cli1 = NULL;
852 torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
854 fn = test->fn;
856 ret = fn(torture_ctx, cli1);
857 fail:
858 talloc_free(cli1);
860 return ret;
863 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
864 struct torture_suite *suite,
865 const char *name,
866 bool (*run) (struct torture_context *, struct smbcli_state *))
868 struct torture_test *test;
869 struct torture_tcase *tcase;
871 tcase = torture_suite_add_tcase(suite, name);
873 test = talloc(tcase, struct torture_test);
875 test->name = talloc_strdup(test, name);
876 test->description = NULL;
877 test->run = wrap_simple_1smb_test;
878 test->fn = run;
879 test->dangerous = false;
881 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
883 return test;
887 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
888 struct smbcli_session *session,
889 const char *sharename,
890 struct smbcli_tree **res)
892 union smb_tcon tcon;
893 struct smbcli_tree *result;
894 TALLOC_CTX *tmp_ctx;
895 NTSTATUS status;
897 if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
898 return NT_STATUS_NO_MEMORY;
901 result = smbcli_tree_init(session, tmp_ctx, false);
902 if (result == NULL) {
903 talloc_free(tmp_ctx);
904 return NT_STATUS_NO_MEMORY;
907 tcon.generic.level = RAW_TCON_TCONX;
908 tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
909 tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
911 /* Ignore share mode security here */
912 tcon.tconx.in.password = data_blob(NULL, 0);
913 tcon.tconx.in.path = sharename;
914 tcon.tconx.in.device = "?????";
916 status = smb_raw_tcon(result, tmp_ctx, &tcon);
917 if (!NT_STATUS_IS_OK(status)) {
918 talloc_free(tmp_ctx);
919 return status;
922 result->tid = tcon.tconx.out.tid;
924 if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
925 smb1cli_session_protect_session_key(result->session->smbXcli);
928 *res = talloc_steal(mem_ctx, result);
929 talloc_free(tmp_ctx);
930 return NT_STATUS_OK;
934 a wrapper around smblsa_sid_check_privilege, that tries to take
935 account of the fact that the lsa privileges calls don't expand
936 group memberships, using an explicit check for administrator. There
937 must be a better way ...
939 NTSTATUS torture_check_privilege(struct smbcli_state *cli,
940 const char *sid_str,
941 const char *privilege)
943 struct dom_sid *sid;
944 TALLOC_CTX *tmp_ctx = talloc_new(cli);
945 uint32_t rid;
946 NTSTATUS status;
948 sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
949 if (sid == NULL) {
950 talloc_free(tmp_ctx);
951 return NT_STATUS_INVALID_SID;
954 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
955 if (!NT_STATUS_IS_OK(status)) {
956 TALLOC_FREE(tmp_ctx);
957 return status;
960 if (rid == DOMAIN_RID_ADMINISTRATOR) {
961 /* assume the administrator has them all */
962 return NT_STATUS_OK;
965 talloc_free(tmp_ctx);
967 return smblsa_sid_check_privilege(cli, sid_str, privilege);