s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_CLOSE test to smb2.compound_async.
[Samba.git] / source4 / torture / util_smb.c
blobf13132915618106ccf87d0ef4f285c651d590e54
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/cmdline.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/smb2/smb2.h"
37 #include "libcli/util/clilsa.h"
38 #include "torture/util.h"
39 #include "libcli/smb/smbXcli_base.h"
40 #include "auth/credentials/credentials.h"
41 #include "auth/credentials/credentials_krb5.h"
43 /**
44 setup a directory ready for a test
46 _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
48 smb_raw_exit(cli->session);
49 if (smbcli_deltree(cli->tree, dname) == -1 ||
50 NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
51 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
52 return false;
54 return true;
58 create a directory, returning a handle to it
60 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
62 NTSTATUS status;
63 union smb_open io;
64 TALLOC_CTX *mem_ctx;
66 mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
68 io.generic.level = RAW_OPEN_NTCREATEX;
69 io.ntcreatex.in.root_fid.fnum = 0;
70 io.ntcreatex.in.flags = 0;
71 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
72 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
73 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
74 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
75 io.ntcreatex.in.alloc_size = 0;
76 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
77 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
78 io.ntcreatex.in.security_flags = 0;
79 io.ntcreatex.in.fname = dname;
81 status = smb_raw_open(tree, mem_ctx, &io);
82 talloc_free(mem_ctx);
84 if (NT_STATUS_IS_OK(status)) {
85 *fnum = io.ntcreatex.out.file.fnum;
88 return status;
92 /**
93 sometimes we need a fairly complex file to work with, so we can test
94 all possible attributes.
96 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
98 int fnum;
99 char buf[7] = "abc";
100 union smb_setfileinfo setfile;
101 union smb_fileinfo fileinfo;
102 time_t t = (time(NULL) & ~1);
103 NTSTATUS status;
105 smbcli_unlink(cli->tree, fname);
106 fnum = smbcli_nt_create_full(cli->tree, fname, 0,
107 SEC_RIGHTS_FILE_ALL,
108 FILE_ATTRIBUTE_NORMAL,
109 NTCREATEX_SHARE_ACCESS_DELETE|
110 NTCREATEX_SHARE_ACCESS_READ|
111 NTCREATEX_SHARE_ACCESS_WRITE,
112 NTCREATEX_DISP_OVERWRITE_IF,
113 0, 0);
114 if (fnum == -1) return -1;
116 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
118 if (strchr(fname, ':') == NULL) {
119 /* setup some EAs */
120 setfile.generic.level = RAW_SFILEINFO_EA_SET;
121 setfile.generic.in.file.fnum = fnum;
122 setfile.ea_set.in.num_eas = 2;
123 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
124 setfile.ea_set.in.eas[0].flags = 0;
125 setfile.ea_set.in.eas[0].name.s = "EAONE";
126 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
127 setfile.ea_set.in.eas[1].flags = 0;
128 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
129 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
130 status = smb_raw_setfileinfo(cli->tree, &setfile);
131 if (!NT_STATUS_IS_OK(status)) {
132 printf("Failed to setup EAs\n");
136 /* make sure all the timestamps aren't the same */
137 ZERO_STRUCT(setfile);
138 setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
139 setfile.generic.in.file.fnum = fnum;
141 unix_to_nt_time(&setfile.basic_info.in.create_time,
142 t + 9*30*24*60*60);
143 unix_to_nt_time(&setfile.basic_info.in.access_time,
144 t + 6*30*24*60*60);
145 unix_to_nt_time(&setfile.basic_info.in.write_time,
146 t + 3*30*24*60*60);
148 status = smb_raw_setfileinfo(cli->tree, &setfile);
149 if (!NT_STATUS_IS_OK(status)) {
150 printf("Failed to setup file times - %s\n", nt_errstr(status));
153 /* make sure all the timestamps aren't the same */
154 fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
155 fileinfo.generic.in.file.fnum = fnum;
157 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
158 if (!NT_STATUS_IS_OK(status)) {
159 printf("Failed to query file times - %s\n", nt_errstr(status));
162 if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
163 printf("create_time not setup correctly\n");
165 if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
166 printf("access_time not setup correctly\n");
168 if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
169 printf("write_time not setup correctly\n");
172 return fnum;
177 sometimes we need a fairly complex directory to work with, so we can test
178 all possible attributes.
180 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
182 int fnum;
183 union smb_setfileinfo setfile;
184 union smb_fileinfo fileinfo;
185 time_t t = (time(NULL) & ~1);
186 NTSTATUS status;
188 smbcli_deltree(cli->tree, dname);
189 fnum = smbcli_nt_create_full(cli->tree, dname, 0,
190 SEC_RIGHTS_DIR_ALL,
191 FILE_ATTRIBUTE_DIRECTORY,
192 NTCREATEX_SHARE_ACCESS_READ|
193 NTCREATEX_SHARE_ACCESS_WRITE,
194 NTCREATEX_DISP_OPEN_IF,
195 NTCREATEX_OPTIONS_DIRECTORY, 0);
196 if (fnum == -1) return -1;
198 if (strchr(dname, ':') == NULL) {
199 /* setup some EAs */
200 setfile.generic.level = RAW_SFILEINFO_EA_SET;
201 setfile.generic.in.file.fnum = fnum;
202 setfile.ea_set.in.num_eas = 2;
203 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
204 setfile.ea_set.in.eas[0].flags = 0;
205 setfile.ea_set.in.eas[0].name.s = "EAONE";
206 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
207 setfile.ea_set.in.eas[1].flags = 0;
208 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
209 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
210 status = smb_raw_setfileinfo(cli->tree, &setfile);
211 if (!NT_STATUS_IS_OK(status)) {
212 printf("Failed to setup EAs\n");
216 /* make sure all the timestamps aren't the same */
217 ZERO_STRUCT(setfile);
218 setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
219 setfile.generic.in.file.fnum = fnum;
221 unix_to_nt_time(&setfile.basic_info.in.create_time,
222 t + 9*30*24*60*60);
223 unix_to_nt_time(&setfile.basic_info.in.access_time,
224 t + 6*30*24*60*60);
225 unix_to_nt_time(&setfile.basic_info.in.write_time,
226 t + 3*30*24*60*60);
228 status = smb_raw_setfileinfo(cli->tree, &setfile);
229 if (!NT_STATUS_IS_OK(status)) {
230 printf("Failed to setup file times - %s\n", nt_errstr(status));
233 /* make sure all the timestamps aren't the same */
234 fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
235 fileinfo.generic.in.file.fnum = fnum;
237 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
238 if (!NT_STATUS_IS_OK(status)) {
239 printf("Failed to query file times - %s\n", nt_errstr(status));
242 if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
243 printf("create_time not setup correctly\n");
245 if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
246 printf("access_time not setup correctly\n");
248 if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
249 printf("write_time not setup correctly\n");
252 return fnum;
256 check that a wire string matches the flags specified
257 not 100% accurate, but close enough for testing
259 bool wire_bad_flags(struct smb_wire_string *str, int flags,
260 struct smbcli_transport *transport)
262 bool server_unicode;
263 int len;
264 if (!str || !str->s) return true;
265 len = strlen(str->s);
266 if (flags & STR_TERMINATE) len++;
268 server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
269 if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
270 server_unicode = false;
273 if ((flags & STR_UNICODE) || server_unicode) {
274 len *= 2;
275 } else if (flags & STR_TERMINATE_ASCII) {
276 len++;
278 if (str->private_length != len) {
279 printf("Expected wire_length %d but got %d for '%s'\n",
280 len, str->private_length, str->s);
281 return true;
283 return false;
287 dump a all_info QFILEINFO structure
289 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
291 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
292 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
293 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
294 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
295 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
296 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
297 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
298 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
299 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
300 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
301 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
302 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
306 dump file infor by name
308 void torture_all_info(struct smbcli_tree *tree, const char *fname)
310 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
311 union smb_fileinfo finfo;
312 NTSTATUS status;
314 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
315 finfo.generic.in.file.path = fname;
316 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
317 if (!NT_STATUS_IS_OK(status)) {
318 d_printf("%s - %s\n", fname, nt_errstr(status));
319 return;
322 d_printf("%s:\n", fname);
323 dump_all_info(mem_ctx, &finfo);
324 talloc_free(mem_ctx);
329 set a attribute on a file
331 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
333 union smb_setfileinfo sfinfo;
334 NTSTATUS status;
336 ZERO_STRUCT(sfinfo.basic_info.in);
337 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
338 sfinfo.basic_info.in.file.path = fname;
339 sfinfo.basic_info.in.attrib = attrib;
340 status = smb_raw_setpathinfo(tree, &sfinfo);
341 return NT_STATUS_IS_OK(status);
346 set a file descriptor as sparse
348 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
350 union smb_ioctl nt;
351 NTSTATUS status;
352 TALLOC_CTX *mem_ctx;
354 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
355 if (!mem_ctx) {
356 return NT_STATUS_NO_MEMORY;
359 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
360 nt.ntioctl.in.function = FSCTL_SET_SPARSE;
361 nt.ntioctl.in.file.fnum = fnum;
362 nt.ntioctl.in.fsctl = true;
363 nt.ntioctl.in.filter = 0;
364 nt.ntioctl.in.max_data = 0;
365 nt.ntioctl.in.blob = data_blob(NULL, 0);
367 status = smb_raw_ioctl(tree, mem_ctx, &nt);
369 talloc_free(mem_ctx);
371 return status;
375 check that an EA has the right value
377 NTSTATUS torture_check_ea(struct smbcli_state *cli,
378 const char *fname, const char *eaname, const char *value)
380 union smb_fileinfo info;
381 NTSTATUS status;
382 struct ea_name ea;
383 TALLOC_CTX *mem_ctx = talloc_new(cli);
385 info.ea_list.level = RAW_FILEINFO_EA_LIST;
386 info.ea_list.in.file.path = fname;
387 info.ea_list.in.num_names = 1;
388 info.ea_list.in.ea_names = &ea;
390 ea.name.s = eaname;
392 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
393 if (!NT_STATUS_IS_OK(status)) {
394 talloc_free(mem_ctx);
395 return status;
398 if (info.ea_list.out.num_eas != 1) {
399 printf("Expected 1 ea in ea_list\n");
400 talloc_free(mem_ctx);
401 return NT_STATUS_EA_CORRUPT_ERROR;
404 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
405 printf("Expected ea '%s' not '%s' in ea_list\n",
406 eaname, info.ea_list.out.eas[0].name.s);
407 talloc_free(mem_ctx);
408 return NT_STATUS_EA_CORRUPT_ERROR;
411 if (value == NULL) {
412 if (info.ea_list.out.eas[0].value.length != 0) {
413 printf("Expected zero length ea for %s\n", eaname);
414 talloc_free(mem_ctx);
415 return NT_STATUS_EA_CORRUPT_ERROR;
417 talloc_free(mem_ctx);
418 return NT_STATUS_OK;
421 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
422 memcmp(value, info.ea_list.out.eas[0].value.data,
423 info.ea_list.out.eas[0].value.length) == 0) {
424 talloc_free(mem_ctx);
425 return NT_STATUS_OK;
428 printf("Expected value '%s' not '%*.*s' for ea %s\n",
429 value,
430 (int)info.ea_list.out.eas[0].value.length,
431 (int)info.ea_list.out.eas[0].value.length,
432 info.ea_list.out.eas[0].value.data,
433 eaname);
435 talloc_free(mem_ctx);
437 return NT_STATUS_EA_CORRUPT_ERROR;
440 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
441 struct smbcli_state **c,
442 struct torture_context *tctx,
443 const char *hostname,
444 const char *sharename,
445 struct tevent_context *ev)
447 NTSTATUS status;
449 struct smbcli_options options;
450 struct smbcli_session_options session_options;
452 lpcfg_smbcli_options(tctx->lp_ctx, &options);
453 lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
455 options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
456 options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
458 status = smbcli_full_connection(mem_ctx, c, hostname,
459 lpcfg_smb_ports(tctx->lp_ctx),
460 sharename, NULL,
461 lpcfg_socket_options(tctx->lp_ctx),
462 samba_cmdline_get_creds(),
463 lpcfg_resolve_context(tctx->lp_ctx),
464 ev, &options, &session_options,
465 lpcfg_gensec_settings(tctx, tctx->lp_ctx));
466 if (!NT_STATUS_IS_OK(status)) {
467 printf("Failed to open connection - %s\n", nt_errstr(status));
468 return false;
471 return true;
474 _PUBLIC_ bool torture_get_conn_index(int conn_index,
475 TALLOC_CTX *mem_ctx,
476 struct torture_context *tctx,
477 char **host, char **share)
479 char **unc_list = NULL;
480 int num_unc_names = 0;
481 const char *p;
483 (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
484 (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
486 p = torture_setting_string(tctx, "unclist", NULL);
487 if (!p) {
488 return true;
491 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
492 if (!unc_list || num_unc_names <= 0) {
493 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
494 return false;
497 p = unc_list[conn_index % num_unc_names];
498 if (p[0] != '/' && p[0] != '\\') {
499 /* allow UNC lists of hosts */
500 (*host) = talloc_strdup(mem_ctx, p);
501 } else if (!smbcli_parse_unc(p, mem_ctx, host, share)) {
502 DEBUG(0, ("Failed to parse UNC name %s\n",
503 unc_list[conn_index % num_unc_names]));
504 return false;
507 talloc_free(unc_list);
508 return true;
513 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
514 int conn_index,
515 struct torture_context *tctx,
516 struct tevent_context *ev)
518 char *host, *share;
519 bool ret;
521 if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
522 return false;
525 ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
526 talloc_free(host);
527 talloc_free(share);
529 return ret;
532 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
534 return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
539 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
541 bool ret = true;
542 if (!c) return true;
543 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
544 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
545 ret = false;
547 talloc_free(c);
548 return ret;
552 /* check if the server produced the expected error code */
553 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
554 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
556 NTSTATUS status;
558 status = smbcli_nt_error(c->tree);
559 if (NT_STATUS_IS_DOS(status)) {
560 int classnum, num;
561 classnum = NT_STATUS_DOS_CLASS(status);
562 num = NT_STATUS_DOS_CODE(status);
563 if (eclass != classnum || ecode != num) {
564 printf("unexpected error code %s\n", nt_errstr(status));
565 printf(" expected %s or %s (at %s)\n",
566 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
567 nt_errstr(nterr), location);
568 return false;
570 } else {
571 if (!NT_STATUS_EQUAL(nterr, status)) {
572 printf("unexpected error code %s\n", nt_errstr(status));
573 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
574 return false;
578 return true;
581 static struct smbcli_state *current_cli;
582 static int procnum; /* records process count number when forking */
584 static void sigcont(int sig)
588 struct child_status {
589 pid_t pid;
590 bool start;
591 enum torture_result result;
592 char reason[1024];
595 double torture_create_procs(struct torture_context *tctx,
596 bool (*fn)(struct torture_context *, struct smbcli_state *, int),
597 bool *result)
599 int status;
600 size_t i;
601 struct child_status *child_status;
602 size_t synccount;
603 size_t tries = 8;
604 size_t torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
605 double start_time_limit = 10 + (torture_nprocs * 1.5);
606 struct timeval tv;
608 *result = true;
610 synccount = 0;
612 signal(SIGCONT, sigcont);
614 child_status = (struct child_status *)anonymous_shared_allocate(
615 sizeof(struct child_status)*torture_nprocs);
616 if (child_status == NULL) {
617 printf("Failed to setup shared memory\n");
618 return -1;
621 for (i = 0; i < torture_nprocs; i++) {
622 ZERO_STRUCT(child_status[i]);
625 tv = timeval_current();
627 for (i=0;i<torture_nprocs;i++) {
628 procnum = i;
629 if (fork() == 0) {
630 char *myname;
631 bool ok;
633 pid_t mypid = getpid();
634 srandom(((int)mypid) ^ ((int)time(NULL)));
636 if (asprintf(&myname, "CLIENT%zu", i) == -1) {
637 printf("asprintf failed\n");
638 return -1;
640 lpcfg_set_cmdline(tctx->lp_ctx, "netbios name", myname);
641 free(myname);
644 while (1) {
645 if (torture_open_connection(&current_cli, tctx, i)) {
646 break;
648 if (tries-- == 0) {
649 printf("pid %d failed to start\n", (int)getpid());
650 _exit(1);
652 smb_msleep(100);
655 child_status[i].pid = getpid();
657 pause();
659 if (!child_status[i].start) {
660 child_status[i].result = TORTURE_ERROR;
661 printf("Child %zu failed to start!\n", i);
662 _exit(1);
665 ok = fn(tctx, current_cli, i);
666 if (!ok) {
667 if (tctx->last_result == TORTURE_OK) {
668 torture_result(tctx, TORTURE_ERROR,
669 "unknown error: missing "
670 "torture_result call?\n");
673 child_status[i].result = tctx->last_result;
675 if (strlen(tctx->last_reason) > 1023) {
676 /* note: reason already contains \n */
677 torture_comment(tctx,
678 "child %zu (pid %u) failed: %s",
680 (unsigned)child_status[i].pid,
681 tctx->last_reason);
684 snprintf(child_status[i].reason,
685 1024, "child %zu (pid %u) failed: %s",
686 i, (unsigned)child_status[i].pid,
687 tctx->last_reason);
688 /* ensure proper "\n\0" termination: */
689 if (child_status[i].reason[1022] != '\0') {
690 child_status[i].reason[1022] = '\n';
691 child_status[i].reason[1023] = '\0';
694 _exit(0);
698 do {
699 synccount = 0;
700 for (i=0;i<torture_nprocs;i++) {
701 if (child_status[i].pid != 0) {
702 synccount++;
705 if (synccount == torture_nprocs) {
706 break;
708 smb_msleep(100);
709 } while (timeval_elapsed(&tv) < start_time_limit);
711 if (synccount != torture_nprocs) {
712 printf("FAILED TO START %zu CLIENTS (started %zu)\n", torture_nprocs, synccount);
714 /* cleanup child processes */
715 for (i = 0; i < torture_nprocs; i++) {
716 if (child_status[i].pid != 0) {
717 kill(child_status[i].pid, SIGTERM);
721 *result = false;
722 return timeval_elapsed(&tv);
725 printf("Starting %zu clients\n", torture_nprocs);
727 /* start the client load */
728 tv = timeval_current();
729 for (i=0;i<torture_nprocs;i++) {
730 child_status[i].start = true;
733 printf("%zu clients started\n", torture_nprocs);
735 kill(0, SIGCONT);
737 for (i=0;i<torture_nprocs;i++) {
738 int ret;
739 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
740 if (ret == -1 || WEXITSTATUS(status) != 0) {
741 *result = false;
745 printf("\n");
747 for (i=0;i<torture_nprocs;i++) {
748 if (child_status[i].result != TORTURE_OK) {
749 *result = false;
750 torture_result(tctx, child_status[i].result,
751 "%s", child_status[i].reason);
755 return timeval_elapsed(&tv);
758 static bool wrap_smb_multi_test(struct torture_context *torture,
759 struct torture_tcase *tcase,
760 struct torture_test *test)
762 bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
763 bool result;
765 torture_create_procs(torture, fn, &result);
767 return result;
770 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
771 struct torture_suite *suite,
772 const char *name,
773 bool (*run) (struct torture_context *,
774 struct smbcli_state *,
775 int i))
777 struct torture_test *test;
778 struct torture_tcase *tcase;
780 tcase = torture_suite_add_tcase(suite, name);
782 test = talloc(tcase, struct torture_test);
784 test->name = talloc_strdup(test, name);
785 test->description = NULL;
786 test->run = wrap_smb_multi_test;
787 test->fn = run;
788 test->dangerous = false;
790 DLIST_ADD_END(tcase->tests, test);
792 return test;
796 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
797 struct torture_tcase *tcase,
798 struct torture_test *test)
800 bool (*fn) (struct torture_context *, struct smbcli_state *,
801 struct smbcli_state *);
802 bool ret = true;
804 struct smbcli_state *cli1 = NULL, *cli2 = NULL;
806 torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
807 torture_assert_goto(torture_ctx, torture_open_connection(&cli2, torture_ctx, 1), ret, fail, "Failed to open connection");
809 fn = test->fn;
811 ret = fn(torture_ctx, cli1, cli2);
812 fail:
813 talloc_free(cli1);
814 talloc_free(cli2);
816 return ret;
821 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
822 struct torture_suite *suite,
823 const char *name,
824 bool (*run) (struct torture_context *,
825 struct smbcli_state *,
826 struct smbcli_state *))
828 struct torture_test *test;
829 struct torture_tcase *tcase;
831 tcase = torture_suite_add_tcase(suite, name);
833 test = talloc(tcase, struct torture_test);
835 test->name = talloc_strdup(test, name);
836 test->description = NULL;
837 test->run = wrap_simple_2smb_test;
838 test->fn = run;
839 test->dangerous = false;
841 DLIST_ADD_END(tcase->tests, test);
843 return test;
847 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
848 struct torture_tcase *tcase,
849 struct torture_test *test)
851 bool (*fn) (struct torture_context *, struct smbcli_state *);
852 bool ret = true;
854 struct smbcli_state *cli1 = NULL;
856 torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
858 fn = test->fn;
860 ret = fn(torture_ctx, cli1);
861 fail:
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);
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 = TCONX_FLAG_EXTENDED_RESPONSE;
913 tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
915 /* Ignore share mode security here */
916 tcon.tconx.in.password = data_blob(NULL, 0);
917 tcon.tconx.in.path = sharename;
918 tcon.tconx.in.device = "?????";
920 status = smb_raw_tcon(result, tmp_ctx, &tcon);
921 if (!NT_STATUS_IS_OK(status)) {
922 talloc_free(tmp_ctx);
923 return status;
926 result->tid = tcon.tconx.out.tid;
928 if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
929 smb1cli_session_protect_session_key(result->session->smbXcli);
932 *res = talloc_steal(mem_ctx, result);
933 talloc_free(tmp_ctx);
934 return NT_STATUS_OK;
938 a wrapper around smblsa_sid_check_privilege, that tries to take
939 account of the fact that the lsa privileges calls don't expand
940 group memberships, using an explicit check for administrator. There
941 must be a better way ...
943 NTSTATUS torture_check_privilege(struct smbcli_state *cli,
944 const char *sid_str,
945 const char *privilege)
947 struct dom_sid *sid;
948 TALLOC_CTX *tmp_ctx = talloc_new(cli);
949 uint32_t rid;
950 NTSTATUS status;
952 sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
953 if (sid == NULL) {
954 talloc_free(tmp_ctx);
955 return NT_STATUS_INVALID_SID;
958 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
959 if (!NT_STATUS_IS_OK(status)) {
960 TALLOC_FREE(tmp_ctx);
961 return status;
964 if (rid == DOMAIN_RID_ADMINISTRATOR) {
965 /* assume the administrator has them all */
966 return NT_STATUS_OK;
969 talloc_free(tmp_ctx);
971 return smblsa_sid_check_privilege(cli, sid_str, privilege);
975 * Use this to pass a 2nd user:
977 * --option='torture:user2name=user2'
978 * --option='torture:user2domain=domain2'
979 * --option='torture:user2password=password2'
981 struct cli_credentials *torture_user2_credentials(struct torture_context *tctx,
982 TALLOC_CTX *mem_ctx)
984 struct cli_credentials *credentials1 = samba_cmdline_get_creds();
985 const char *user1domain = cli_credentials_get_domain(credentials1);
986 const char *user2name = torture_setting_string(tctx, "user2name", NULL);
987 const char *user2domain = torture_setting_string(tctx, "user2domain", user1domain);
988 const char *user2password = torture_setting_string(tctx, "user2password", NULL);
989 struct cli_credentials *credentials2 = NULL;
991 credentials2 = cli_credentials_shallow_copy(mem_ctx, credentials1);
992 if (credentials2 == NULL) {
993 torture_comment(tctx,
994 "%s: cli_credentials_shallow_copy() failed\n",
995 __func__);
996 return NULL;
998 if (user2name != NULL) {
999 torture_comment(tctx,
1000 "Using "
1001 "'torture:user2name'='%s' "
1002 "'torture:user2domain'='%s' "
1003 "'torture:user2password'='REDACTED'",
1004 user2name,
1005 user2domain);
1006 cli_credentials_set_username(credentials2, user2name, CRED_SPECIFIED);
1007 cli_credentials_set_domain(credentials2, user2domain, CRED_SPECIFIED);
1008 cli_credentials_set_password(credentials2, user2password, CRED_SPECIFIED);
1009 } else {
1010 torture_comment(tctx,
1011 "Fallback to anonymous for "
1012 "'torture:user2name'=NULL "
1013 "'torture:user2domain'='%s' "
1014 "'torture:user2password'='REDACTED'",
1015 user2domain);
1016 cli_credentials_set_anonymous(credentials2);
1019 return credentials2;