s3:pylibsmb: Add ipc=True support for CLI_FULL_CONNECTION_IPC
[Samba.git] / source4 / torture / util_smb.c
blob7641b1fbc0bfb7ebeb53c3516af44d784427d52f
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/smb2/smb2.h"
37 #include "libcli/util/clilsa.h"
38 #include "torture/util.h"
39 #include "libcli/smb/smbXcli_base.h"
41 /**
42 setup a directory ready for a test
44 _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
46 smb_raw_exit(cli->session);
47 if (smbcli_deltree(cli->tree, dname) == -1 ||
48 NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
49 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
50 return false;
52 return true;
56 create a directory, returning a handle to it
58 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
60 NTSTATUS status;
61 union smb_open io;
62 TALLOC_CTX *mem_ctx;
64 mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
66 io.generic.level = RAW_OPEN_NTCREATEX;
67 io.ntcreatex.in.root_fid.fnum = 0;
68 io.ntcreatex.in.flags = 0;
69 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
70 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
71 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
72 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
73 io.ntcreatex.in.alloc_size = 0;
74 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
75 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
76 io.ntcreatex.in.security_flags = 0;
77 io.ntcreatex.in.fname = dname;
79 status = smb_raw_open(tree, mem_ctx, &io);
80 talloc_free(mem_ctx);
82 if (NT_STATUS_IS_OK(status)) {
83 *fnum = io.ntcreatex.out.file.fnum;
86 return status;
90 /**
91 sometimes we need a fairly complex file to work with, so we can test
92 all possible attributes.
94 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
96 int fnum;
97 char buf[7] = "abc";
98 union smb_setfileinfo setfile;
99 union smb_fileinfo fileinfo;
100 time_t t = (time(NULL) & ~1);
101 NTSTATUS status;
103 smbcli_unlink(cli->tree, fname);
104 fnum = smbcli_nt_create_full(cli->tree, fname, 0,
105 SEC_RIGHTS_FILE_ALL,
106 FILE_ATTRIBUTE_NORMAL,
107 NTCREATEX_SHARE_ACCESS_DELETE|
108 NTCREATEX_SHARE_ACCESS_READ|
109 NTCREATEX_SHARE_ACCESS_WRITE,
110 NTCREATEX_DISP_OVERWRITE_IF,
111 0, 0);
112 if (fnum == -1) return -1;
114 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
116 if (strchr(fname, ':') == NULL) {
117 /* setup some EAs */
118 setfile.generic.level = RAW_SFILEINFO_EA_SET;
119 setfile.generic.in.file.fnum = fnum;
120 setfile.ea_set.in.num_eas = 2;
121 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
122 setfile.ea_set.in.eas[0].flags = 0;
123 setfile.ea_set.in.eas[0].name.s = "EAONE";
124 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
125 setfile.ea_set.in.eas[1].flags = 0;
126 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
127 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
128 status = smb_raw_setfileinfo(cli->tree, &setfile);
129 if (!NT_STATUS_IS_OK(status)) {
130 printf("Failed to setup EAs\n");
134 /* make sure all the timestamps aren't the same */
135 ZERO_STRUCT(setfile);
136 setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
137 setfile.generic.in.file.fnum = fnum;
139 unix_to_nt_time(&setfile.basic_info.in.create_time,
140 t + 9*30*24*60*60);
141 unix_to_nt_time(&setfile.basic_info.in.access_time,
142 t + 6*30*24*60*60);
143 unix_to_nt_time(&setfile.basic_info.in.write_time,
144 t + 3*30*24*60*60);
146 status = smb_raw_setfileinfo(cli->tree, &setfile);
147 if (!NT_STATUS_IS_OK(status)) {
148 printf("Failed to setup file times - %s\n", nt_errstr(status));
151 /* make sure all the timestamps aren't the same */
152 fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
153 fileinfo.generic.in.file.fnum = fnum;
155 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
156 if (!NT_STATUS_IS_OK(status)) {
157 printf("Failed to query file times - %s\n", nt_errstr(status));
160 if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
161 printf("create_time not setup correctly\n");
163 if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
164 printf("access_time not setup correctly\n");
166 if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
167 printf("write_time not setup correctly\n");
170 return fnum;
175 sometimes we need a fairly complex directory to work with, so we can test
176 all possible attributes.
178 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
180 int fnum;
181 union smb_setfileinfo setfile;
182 union smb_fileinfo fileinfo;
183 time_t t = (time(NULL) & ~1);
184 NTSTATUS status;
186 smbcli_deltree(cli->tree, dname);
187 fnum = smbcli_nt_create_full(cli->tree, dname, 0,
188 SEC_RIGHTS_DIR_ALL,
189 FILE_ATTRIBUTE_DIRECTORY,
190 NTCREATEX_SHARE_ACCESS_READ|
191 NTCREATEX_SHARE_ACCESS_WRITE,
192 NTCREATEX_DISP_OPEN_IF,
193 NTCREATEX_OPTIONS_DIRECTORY, 0);
194 if (fnum == -1) return -1;
196 if (strchr(dname, ':') == NULL) {
197 /* setup some EAs */
198 setfile.generic.level = RAW_SFILEINFO_EA_SET;
199 setfile.generic.in.file.fnum = fnum;
200 setfile.ea_set.in.num_eas = 2;
201 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
202 setfile.ea_set.in.eas[0].flags = 0;
203 setfile.ea_set.in.eas[0].name.s = "EAONE";
204 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
205 setfile.ea_set.in.eas[1].flags = 0;
206 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
207 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
208 status = smb_raw_setfileinfo(cli->tree, &setfile);
209 if (!NT_STATUS_IS_OK(status)) {
210 printf("Failed to setup EAs\n");
214 /* make sure all the timestamps aren't the same */
215 ZERO_STRUCT(setfile);
216 setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
217 setfile.generic.in.file.fnum = fnum;
219 unix_to_nt_time(&setfile.basic_info.in.create_time,
220 t + 9*30*24*60*60);
221 unix_to_nt_time(&setfile.basic_info.in.access_time,
222 t + 6*30*24*60*60);
223 unix_to_nt_time(&setfile.basic_info.in.write_time,
224 t + 3*30*24*60*60);
226 status = smb_raw_setfileinfo(cli->tree, &setfile);
227 if (!NT_STATUS_IS_OK(status)) {
228 printf("Failed to setup file times - %s\n", nt_errstr(status));
231 /* make sure all the timestamps aren't the same */
232 fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
233 fileinfo.generic.in.file.fnum = fnum;
235 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
236 if (!NT_STATUS_IS_OK(status)) {
237 printf("Failed to query file times - %s\n", nt_errstr(status));
240 if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
241 printf("create_time not setup correctly\n");
243 if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
244 printf("access_time not setup correctly\n");
246 if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
247 printf("write_time not setup correctly\n");
250 return fnum;
254 check that a wire string matches the flags specified
255 not 100% accurate, but close enough for testing
257 bool wire_bad_flags(struct smb_wire_string *str, int flags,
258 struct smbcli_transport *transport)
260 bool server_unicode;
261 int len;
262 if (!str || !str->s) return true;
263 len = strlen(str->s);
264 if (flags & STR_TERMINATE) len++;
266 server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
267 if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
268 server_unicode = false;
271 if ((flags & STR_UNICODE) || server_unicode) {
272 len *= 2;
273 } else if (flags & STR_TERMINATE_ASCII) {
274 len++;
276 if (str->private_length != len) {
277 printf("Expected wire_length %d but got %d for '%s'\n",
278 len, str->private_length, str->s);
279 return true;
281 return false;
285 dump a all_info QFILEINFO structure
287 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
289 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
290 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
291 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
292 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
293 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
294 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
295 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
296 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
297 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
298 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
299 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
300 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
304 dump file infor by name
306 void torture_all_info(struct smbcli_tree *tree, const char *fname)
308 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
309 union smb_fileinfo finfo;
310 NTSTATUS status;
312 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
313 finfo.generic.in.file.path = fname;
314 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
315 if (!NT_STATUS_IS_OK(status)) {
316 d_printf("%s - %s\n", fname, nt_errstr(status));
317 return;
320 d_printf("%s:\n", fname);
321 dump_all_info(mem_ctx, &finfo);
322 talloc_free(mem_ctx);
327 set a attribute on a file
329 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
331 union smb_setfileinfo sfinfo;
332 NTSTATUS status;
334 ZERO_STRUCT(sfinfo.basic_info.in);
335 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
336 sfinfo.basic_info.in.file.path = fname;
337 sfinfo.basic_info.in.attrib = attrib;
338 status = smb_raw_setpathinfo(tree, &sfinfo);
339 return NT_STATUS_IS_OK(status);
344 set a file descriptor as sparse
346 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
348 union smb_ioctl nt;
349 NTSTATUS status;
350 TALLOC_CTX *mem_ctx;
352 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
353 if (!mem_ctx) {
354 return NT_STATUS_NO_MEMORY;
357 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
358 nt.ntioctl.in.function = FSCTL_SET_SPARSE;
359 nt.ntioctl.in.file.fnum = fnum;
360 nt.ntioctl.in.fsctl = true;
361 nt.ntioctl.in.filter = 0;
362 nt.ntioctl.in.max_data = 0;
363 nt.ntioctl.in.blob = data_blob(NULL, 0);
365 status = smb_raw_ioctl(tree, mem_ctx, &nt);
367 talloc_free(mem_ctx);
369 return status;
373 check that an EA has the right value
375 NTSTATUS torture_check_ea(struct smbcli_state *cli,
376 const char *fname, const char *eaname, const char *value)
378 union smb_fileinfo info;
379 NTSTATUS status;
380 struct ea_name ea;
381 TALLOC_CTX *mem_ctx = talloc_new(cli);
383 info.ea_list.level = RAW_FILEINFO_EA_LIST;
384 info.ea_list.in.file.path = fname;
385 info.ea_list.in.num_names = 1;
386 info.ea_list.in.ea_names = &ea;
388 ea.name.s = eaname;
390 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
391 if (!NT_STATUS_IS_OK(status)) {
392 talloc_free(mem_ctx);
393 return status;
396 if (info.ea_list.out.num_eas != 1) {
397 printf("Expected 1 ea in ea_list\n");
398 talloc_free(mem_ctx);
399 return NT_STATUS_EA_CORRUPT_ERROR;
402 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
403 printf("Expected ea '%s' not '%s' in ea_list\n",
404 eaname, info.ea_list.out.eas[0].name.s);
405 talloc_free(mem_ctx);
406 return NT_STATUS_EA_CORRUPT_ERROR;
409 if (value == NULL) {
410 if (info.ea_list.out.eas[0].value.length != 0) {
411 printf("Expected zero length ea for %s\n", eaname);
412 talloc_free(mem_ctx);
413 return NT_STATUS_EA_CORRUPT_ERROR;
415 talloc_free(mem_ctx);
416 return NT_STATUS_OK;
419 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
420 memcmp(value, info.ea_list.out.eas[0].value.data,
421 info.ea_list.out.eas[0].value.length) == 0) {
422 talloc_free(mem_ctx);
423 return NT_STATUS_OK;
426 printf("Expected value '%s' not '%*.*s' for ea %s\n",
427 value,
428 (int)info.ea_list.out.eas[0].value.length,
429 (int)info.ea_list.out.eas[0].value.length,
430 info.ea_list.out.eas[0].value.data,
431 eaname);
433 talloc_free(mem_ctx);
435 return NT_STATUS_EA_CORRUPT_ERROR;
438 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
439 struct smbcli_state **c,
440 struct torture_context *tctx,
441 const char *hostname,
442 const char *sharename,
443 struct tevent_context *ev)
445 NTSTATUS status;
447 struct smbcli_options options;
448 struct smbcli_session_options session_options;
450 lpcfg_smbcli_options(tctx->lp_ctx, &options);
451 lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
453 options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
454 options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
456 status = smbcli_full_connection(mem_ctx, c, hostname,
457 lpcfg_smb_ports(tctx->lp_ctx),
458 sharename, NULL,
459 lpcfg_socket_options(tctx->lp_ctx),
460 popt_get_cmdline_credentials(),
461 lpcfg_resolve_context(tctx->lp_ctx),
462 ev, &options, &session_options,
463 lpcfg_gensec_settings(tctx, tctx->lp_ctx));
464 if (!NT_STATUS_IS_OK(status)) {
465 printf("Failed to open connection - %s\n", nt_errstr(status));
466 return false;
469 return true;
472 _PUBLIC_ bool torture_get_conn_index(int conn_index,
473 TALLOC_CTX *mem_ctx,
474 struct torture_context *tctx,
475 char **host, char **share)
477 char **unc_list = NULL;
478 int num_unc_names = 0;
479 const char *p;
481 (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
482 (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
484 p = torture_setting_string(tctx, "unclist", NULL);
485 if (!p) {
486 return true;
489 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
490 if (!unc_list || num_unc_names <= 0) {
491 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
492 return false;
495 p = unc_list[conn_index % num_unc_names];
496 if (p[0] != '/' && p[0] != '\\') {
497 /* allow UNC lists of hosts */
498 (*host) = talloc_strdup(mem_ctx, p);
499 } else if (!smbcli_parse_unc(p, mem_ctx, host, share)) {
500 DEBUG(0, ("Failed to parse UNC name %s\n",
501 unc_list[conn_index % num_unc_names]));
502 return false;
505 talloc_free(unc_list);
506 return true;
511 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
512 int conn_index,
513 struct torture_context *tctx,
514 struct tevent_context *ev)
516 char *host, *share;
517 bool ret;
519 if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
520 return false;
523 ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
524 talloc_free(host);
525 talloc_free(share);
527 return ret;
530 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
532 return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
537 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
539 bool ret = true;
540 if (!c) return true;
541 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
542 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
543 ret = false;
545 talloc_free(c);
546 return ret;
550 /* check if the server produced the expected error code */
551 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
552 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
554 NTSTATUS status;
556 status = smbcli_nt_error(c->tree);
557 if (NT_STATUS_IS_DOS(status)) {
558 int classnum, num;
559 classnum = NT_STATUS_DOS_CLASS(status);
560 num = NT_STATUS_DOS_CODE(status);
561 if (eclass != classnum || ecode != num) {
562 printf("unexpected error code %s\n", nt_errstr(status));
563 printf(" expected %s or %s (at %s)\n",
564 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
565 nt_errstr(nterr), location);
566 return false;
568 } else {
569 if (!NT_STATUS_EQUAL(nterr, status)) {
570 printf("unexpected error code %s\n", nt_errstr(status));
571 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
572 return false;
576 return true;
579 static struct smbcli_state *current_cli;
580 static int procnum; /* records process count number when forking */
582 static void sigcont(int sig)
586 struct child_status {
587 pid_t pid;
588 bool start;
589 enum torture_result result;
590 char reason[1024];
593 double torture_create_procs(struct torture_context *tctx,
594 bool (*fn)(struct torture_context *, struct smbcli_state *, int),
595 bool *result)
597 int status;
598 size_t i;
599 struct child_status *child_status;
600 size_t synccount;
601 size_t tries = 8;
602 size_t torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
603 double start_time_limit = 10 + (torture_nprocs * 1.5);
604 struct timeval tv;
606 *result = true;
608 synccount = 0;
610 signal(SIGCONT, sigcont);
612 child_status = (struct child_status *)anonymous_shared_allocate(
613 sizeof(struct child_status)*torture_nprocs);
614 if (child_status == NULL) {
615 printf("Failed to setup shared memory\n");
616 return -1;
619 for (i = 0; i < torture_nprocs; i++) {
620 ZERO_STRUCT(child_status[i]);
623 tv = timeval_current();
625 for (i=0;i<torture_nprocs;i++) {
626 procnum = i;
627 if (fork() == 0) {
628 char *myname;
629 bool ok;
631 pid_t mypid = getpid();
632 srandom(((int)mypid) ^ ((int)time(NULL)));
634 if (asprintf(&myname, "CLIENT%zu", i) == -1) {
635 printf("asprintf failed\n");
636 return -1;
638 lpcfg_set_cmdline(tctx->lp_ctx, "netbios name", myname);
639 free(myname);
642 while (1) {
643 if (torture_open_connection(&current_cli, tctx, i)) {
644 break;
646 if (tries-- == 0) {
647 printf("pid %d failed to start\n", (int)getpid());
648 _exit(1);
650 smb_msleep(100);
653 child_status[i].pid = getpid();
655 pause();
657 if (!child_status[i].start) {
658 child_status[i].result = TORTURE_ERROR;
659 printf("Child %zu failed to start!\n", i);
660 _exit(1);
663 ok = fn(tctx, current_cli, i);
664 if (!ok) {
665 if (tctx->last_result == TORTURE_OK) {
666 torture_result(tctx, TORTURE_ERROR,
667 "unknown error: missing "
668 "torture_result call?\n");
671 child_status[i].result = tctx->last_result;
673 if (strlen(tctx->last_reason) > 1023) {
674 /* note: reason already contains \n */
675 torture_comment(tctx,
676 "child %zu (pid %u) failed: %s",
678 (unsigned)child_status[i].pid,
679 tctx->last_reason);
682 snprintf(child_status[i].reason,
683 1024, "child %zu (pid %u) failed: %s",
684 i, (unsigned)child_status[i].pid,
685 tctx->last_reason);
686 /* ensure proper "\n\0" termination: */
687 if (child_status[i].reason[1022] != '\0') {
688 child_status[i].reason[1022] = '\n';
689 child_status[i].reason[1023] = '\0';
692 _exit(0);
696 do {
697 synccount = 0;
698 for (i=0;i<torture_nprocs;i++) {
699 if (child_status[i].pid != 0) {
700 synccount++;
703 if (synccount == torture_nprocs) {
704 break;
706 smb_msleep(100);
707 } while (timeval_elapsed(&tv) < start_time_limit);
709 if (synccount != torture_nprocs) {
710 printf("FAILED TO START %zu CLIENTS (started %zu)\n", torture_nprocs, synccount);
712 /* cleanup child processes */
713 for (i = 0; i < torture_nprocs; i++) {
714 if (child_status[i].pid != 0) {
715 kill(child_status[i].pid, SIGTERM);
719 *result = false;
720 return timeval_elapsed(&tv);
723 printf("Starting %zu clients\n", torture_nprocs);
725 /* start the client load */
726 tv = timeval_current();
727 for (i=0;i<torture_nprocs;i++) {
728 child_status[i].start = true;
731 printf("%zu clients started\n", torture_nprocs);
733 kill(0, SIGCONT);
735 for (i=0;i<torture_nprocs;i++) {
736 int ret;
737 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
738 if (ret == -1 || WEXITSTATUS(status) != 0) {
739 *result = false;
743 printf("\n");
745 for (i=0;i<torture_nprocs;i++) {
746 if (child_status[i].result != TORTURE_OK) {
747 *result = false;
748 torture_result(tctx, child_status[i].result,
749 "%s", child_status[i].reason);
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);
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 = true;
802 struct smbcli_state *cli1 = NULL, *cli2 = NULL;
804 torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
805 torture_assert_goto(torture_ctx, torture_open_connection(&cli2, torture_ctx, 1), ret, fail, "Failed to open connection");
807 fn = test->fn;
809 ret = fn(torture_ctx, cli1, cli2);
810 fail:
811 talloc_free(cli1);
812 talloc_free(cli2);
814 return ret;
819 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
820 struct torture_suite *suite,
821 const char *name,
822 bool (*run) (struct torture_context *,
823 struct smbcli_state *,
824 struct smbcli_state *))
826 struct torture_test *test;
827 struct torture_tcase *tcase;
829 tcase = torture_suite_add_tcase(suite, name);
831 test = talloc(tcase, struct torture_test);
833 test->name = talloc_strdup(test, name);
834 test->description = NULL;
835 test->run = wrap_simple_2smb_test;
836 test->fn = run;
837 test->dangerous = false;
839 DLIST_ADD_END(tcase->tests, test);
841 return test;
845 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
846 struct torture_tcase *tcase,
847 struct torture_test *test)
849 bool (*fn) (struct torture_context *, struct smbcli_state *);
850 bool ret = true;
852 struct smbcli_state *cli1 = NULL;
854 torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
856 fn = test->fn;
858 ret = fn(torture_ctx, cli1);
859 fail:
860 talloc_free(cli1);
862 return ret;
865 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
866 struct torture_suite *suite,
867 const char *name,
868 bool (*run) (struct torture_context *, struct smbcli_state *))
870 struct torture_test *test;
871 struct torture_tcase *tcase;
873 tcase = torture_suite_add_tcase(suite, name);
875 test = talloc(tcase, struct torture_test);
877 test->name = talloc_strdup(test, name);
878 test->description = NULL;
879 test->run = wrap_simple_1smb_test;
880 test->fn = run;
881 test->dangerous = false;
883 DLIST_ADD_END(tcase->tests, test);
885 return test;
889 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
890 struct smbcli_session *session,
891 const char *sharename,
892 struct smbcli_tree **res)
894 union smb_tcon tcon;
895 struct smbcli_tree *result;
896 TALLOC_CTX *tmp_ctx;
897 NTSTATUS status;
899 if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
900 return NT_STATUS_NO_MEMORY;
903 result = smbcli_tree_init(session, tmp_ctx, false);
904 if (result == NULL) {
905 talloc_free(tmp_ctx);
906 return NT_STATUS_NO_MEMORY;
909 tcon.generic.level = RAW_TCON_TCONX;
910 tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
911 tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
913 /* Ignore share mode security here */
914 tcon.tconx.in.password = data_blob(NULL, 0);
915 tcon.tconx.in.path = sharename;
916 tcon.tconx.in.device = "?????";
918 status = smb_raw_tcon(result, tmp_ctx, &tcon);
919 if (!NT_STATUS_IS_OK(status)) {
920 talloc_free(tmp_ctx);
921 return status;
924 result->tid = tcon.tconx.out.tid;
926 if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
927 smb1cli_session_protect_session_key(result->session->smbXcli);
930 *res = talloc_steal(mem_ctx, result);
931 talloc_free(tmp_ctx);
932 return NT_STATUS_OK;
936 a wrapper around smblsa_sid_check_privilege, that tries to take
937 account of the fact that the lsa privileges calls don't expand
938 group memberships, using an explicit check for administrator. There
939 must be a better way ...
941 NTSTATUS torture_check_privilege(struct smbcli_state *cli,
942 const char *sid_str,
943 const char *privilege)
945 struct dom_sid *sid;
946 TALLOC_CTX *tmp_ctx = talloc_new(cli);
947 uint32_t rid;
948 NTSTATUS status;
950 sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
951 if (sid == NULL) {
952 talloc_free(tmp_ctx);
953 return NT_STATUS_INVALID_SID;
956 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
957 if (!NT_STATUS_IS_OK(status)) {
958 TALLOC_FREE(tmp_ctx);
959 return status;
962 if (rid == DOMAIN_RID_ADMINISTRATOR) {
963 /* assume the administrator has them all */
964 return NT_STATUS_OK;
967 talloc_free(tmp_ctx);
969 return smblsa_sid_check_privilege(cli, sid_str, privilege);