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/>.
22 #include "lib/cmdline/popt_common.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "libcli/raw/ioctl.h"
26 #include "libcli/libcli.h"
27 #include "system/filesys.h"
28 #include "system/shmem.h"
29 #include "system/wait.h"
30 #include "system/time.h"
31 #include "torture/ui.h"
32 #include "torture/torture.h"
33 #include "util/dlinklist.h"
34 #include "auth/credentials/credentials.h"
35 #include "libcli/resolve/resolve.h"
36 #include "param/param.h"
40 setup a directory ready for a test
42 _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
44 smb_raw_exit(cli->session);
45 if (smbcli_deltree(cli->tree, dname) == -1 ||
46 NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
47 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
54 create a directory, returning a handle to it
56 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
62 mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
64 io.generic.level = RAW_OPEN_NTCREATEX;
65 io.ntcreatex.in.root_fid = 0;
66 io.ntcreatex.in.flags = 0;
67 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
68 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
69 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
70 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
71 io.ntcreatex.in.alloc_size = 0;
72 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
73 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
74 io.ntcreatex.in.security_flags = 0;
75 io.ntcreatex.in.fname = dname;
77 status = smb_raw_open(tree, mem_ctx, &io);
80 if (NT_STATUS_IS_OK(status)) {
81 *fnum = io.ntcreatex.out.file.fnum;
89 sometimes we need a fairly complex file to work with, so we can test
90 all possible attributes.
92 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
96 union smb_setfileinfo setfile;
97 union smb_fileinfo fileinfo;
98 time_t t = (time(NULL) & ~1);
101 smbcli_unlink(cli->tree, fname);
102 fnum = smbcli_nt_create_full(cli->tree, fname, 0,
104 FILE_ATTRIBUTE_NORMAL,
105 NTCREATEX_SHARE_ACCESS_DELETE|
106 NTCREATEX_SHARE_ACCESS_READ|
107 NTCREATEX_SHARE_ACCESS_WRITE,
108 NTCREATEX_DISP_OVERWRITE_IF,
110 if (fnum == -1) return -1;
112 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
114 if (strchr(fname, ':') == NULL) {
116 setfile.generic.level = RAW_SFILEINFO_EA_SET;
117 setfile.generic.in.file.fnum = fnum;
118 setfile.ea_set.in.num_eas = 2;
119 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
120 setfile.ea_set.in.eas[0].flags = 0;
121 setfile.ea_set.in.eas[0].name.s = "EAONE";
122 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
123 setfile.ea_set.in.eas[1].flags = 0;
124 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
125 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
126 status = smb_raw_setfileinfo(cli->tree, &setfile);
127 if (!NT_STATUS_IS_OK(status)) {
128 printf("Failed to setup EAs\n");
132 /* make sure all the timestamps aren't the same, and are also
133 in different DST zones*/
134 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
135 setfile.generic.in.file.fnum = fnum;
137 setfile.setattre.in.create_time = t + 9*30*24*60*60;
138 setfile.setattre.in.access_time = t + 6*30*24*60*60;
139 setfile.setattre.in.write_time = t + 3*30*24*60*60;
141 status = smb_raw_setfileinfo(cli->tree, &setfile);
142 if (!NT_STATUS_IS_OK(status)) {
143 printf("Failed to setup file times - %s\n", nt_errstr(status));
146 /* make sure all the timestamps aren't the same */
147 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
148 fileinfo.generic.in.file.fnum = fnum;
150 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
151 if (!NT_STATUS_IS_OK(status)) {
152 printf("Failed to query file times - %s\n", nt_errstr(status));
155 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
156 printf("create_time not setup correctly\n");
158 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
159 printf("access_time not setup correctly\n");
161 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
162 printf("write_time not setup correctly\n");
170 sometimes we need a fairly complex directory to work with, so we can test
171 all possible attributes.
173 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
176 union smb_setfileinfo setfile;
177 union smb_fileinfo fileinfo;
178 time_t t = (time(NULL) & ~1);
181 smbcli_deltree(cli->tree, dname);
182 fnum = smbcli_nt_create_full(cli->tree, dname, 0,
184 FILE_ATTRIBUTE_DIRECTORY,
185 NTCREATEX_SHARE_ACCESS_READ|
186 NTCREATEX_SHARE_ACCESS_WRITE,
187 NTCREATEX_DISP_OPEN_IF,
188 NTCREATEX_OPTIONS_DIRECTORY, 0);
189 if (fnum == -1) return -1;
191 if (strchr(dname, ':') == NULL) {
193 setfile.generic.level = RAW_SFILEINFO_EA_SET;
194 setfile.generic.in.file.fnum = fnum;
195 setfile.ea_set.in.num_eas = 2;
196 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
197 setfile.ea_set.in.eas[0].flags = 0;
198 setfile.ea_set.in.eas[0].name.s = "EAONE";
199 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
200 setfile.ea_set.in.eas[1].flags = 0;
201 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
202 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
203 status = smb_raw_setfileinfo(cli->tree, &setfile);
204 if (!NT_STATUS_IS_OK(status)) {
205 printf("Failed to setup EAs\n");
209 /* make sure all the timestamps aren't the same, and are also
210 in different DST zones*/
211 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
212 setfile.generic.in.file.fnum = fnum;
214 setfile.setattre.in.create_time = t + 9*30*24*60*60;
215 setfile.setattre.in.access_time = t + 6*30*24*60*60;
216 setfile.setattre.in.write_time = t + 3*30*24*60*60;
218 status = smb_raw_setfileinfo(cli->tree, &setfile);
219 if (!NT_STATUS_IS_OK(status)) {
220 printf("Failed to setup file times - %s\n", nt_errstr(status));
223 /* make sure all the timestamps aren't the same */
224 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
225 fileinfo.generic.in.file.fnum = fnum;
227 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
228 if (!NT_STATUS_IS_OK(status)) {
229 printf("Failed to query file times - %s\n", nt_errstr(status));
232 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
233 printf("create_time not setup correctly\n");
235 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
236 printf("access_time not setup correctly\n");
238 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
239 printf("write_time not setup correctly\n");
247 /* return a pointer to a anonymous shared memory segment of size "size"
248 which will persist across fork() but will disappear when all processes
251 The memory is not zeroed
253 This function uses system5 shared memory. It takes advantage of a property
254 that the memory is not destroyed if it is attached when the id is removed
256 void *shm_setup(int size)
261 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
263 printf("can't get shared memory\n");
266 ret = (void *)shmat(shmid, 0, 0);
267 if (!ret || ret == (void *)-1) {
268 printf("can't attach to shared memory\n");
271 /* the following releases the ipc, but note that this process
272 and all its children will still have access to the memory, its
273 just that the shmid is no longer valid for other shm calls. This
274 means we don't leave behind lots of shm segments after we exit
276 See Stevens "advanced programming in unix env" for details
278 shmctl(shmid, IPC_RMID, 0);
285 check that a wire string matches the flags specified
286 not 100% accurate, but close enough for testing
288 bool wire_bad_flags(struct smb_wire_string *str, int flags,
289 struct smbcli_transport *transport)
293 if (!str || !str->s) return true;
294 len = strlen(str->s);
295 if (flags & STR_TERMINATE) len++;
297 server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
298 if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
299 server_unicode = false;
302 if ((flags & STR_UNICODE) || server_unicode) {
304 } else if (flags & STR_TERMINATE_ASCII) {
307 if (str->private_length != len) {
308 printf("Expected wire_length %d but got %d for '%s'\n",
309 len, str->private_length, str->s);
316 dump a all_info QFILEINFO structure
318 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
320 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
321 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
322 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
323 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
324 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
325 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
326 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
327 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
328 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
329 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
330 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
331 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
335 dump file infor by name
337 void torture_all_info(struct smbcli_tree *tree, const char *fname)
339 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
340 union smb_fileinfo finfo;
343 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
344 finfo.generic.in.file.path = fname;
345 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
346 if (!NT_STATUS_IS_OK(status)) {
347 d_printf("%s - %s\n", fname, nt_errstr(status));
351 d_printf("%s:\n", fname);
352 dump_all_info(mem_ctx, &finfo);
353 talloc_free(mem_ctx);
358 set a attribute on a file
360 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
362 union smb_setfileinfo sfinfo;
365 ZERO_STRUCT(sfinfo.basic_info.in);
366 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
367 sfinfo.basic_info.in.file.path = fname;
368 sfinfo.basic_info.in.attrib = attrib;
369 status = smb_raw_setpathinfo(tree, &sfinfo);
370 return NT_STATUS_IS_OK(status);
375 set a file descriptor as sparse
377 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
383 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
385 return NT_STATUS_NO_MEMORY;
388 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
389 nt.ntioctl.in.function = FSCTL_SET_SPARSE;
390 nt.ntioctl.in.file.fnum = fnum;
391 nt.ntioctl.in.fsctl = true;
392 nt.ntioctl.in.filter = 0;
393 nt.ntioctl.in.max_data = 0;
394 nt.ntioctl.in.blob = data_blob(NULL, 0);
396 status = smb_raw_ioctl(tree, mem_ctx, &nt);
398 talloc_free(mem_ctx);
404 check that an EA has the right value
406 NTSTATUS torture_check_ea(struct smbcli_state *cli,
407 const char *fname, const char *eaname, const char *value)
409 union smb_fileinfo info;
412 TALLOC_CTX *mem_ctx = talloc_new(cli);
414 info.ea_list.level = RAW_FILEINFO_EA_LIST;
415 info.ea_list.in.file.path = fname;
416 info.ea_list.in.num_names = 1;
417 info.ea_list.in.ea_names = &ea;
421 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
422 if (!NT_STATUS_IS_OK(status)) {
423 talloc_free(mem_ctx);
427 if (info.ea_list.out.num_eas != 1) {
428 printf("Expected 1 ea in ea_list\n");
429 talloc_free(mem_ctx);
430 return NT_STATUS_EA_CORRUPT_ERROR;
433 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
434 printf("Expected ea '%s' not '%s' in ea_list\n",
435 eaname, info.ea_list.out.eas[0].name.s);
436 talloc_free(mem_ctx);
437 return NT_STATUS_EA_CORRUPT_ERROR;
441 if (info.ea_list.out.eas[0].value.length != 0) {
442 printf("Expected zero length ea for %s\n", eaname);
443 talloc_free(mem_ctx);
444 return NT_STATUS_EA_CORRUPT_ERROR;
446 talloc_free(mem_ctx);
450 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
451 memcmp(value, info.ea_list.out.eas[0].value.data,
452 info.ea_list.out.eas[0].value.length) == 0) {
453 talloc_free(mem_ctx);
457 printf("Expected value '%s' not '%*.*s' for ea %s\n",
459 (int)info.ea_list.out.eas[0].value.length,
460 (int)info.ea_list.out.eas[0].value.length,
461 info.ea_list.out.eas[0].value.data,
464 talloc_free(mem_ctx);
466 return NT_STATUS_EA_CORRUPT_ERROR;
469 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
470 struct smbcli_state **c,
471 struct torture_context *tctx,
472 const char *hostname,
473 const char *sharename,
474 struct event_context *ev)
478 struct smbcli_options options;
480 lp_smbcli_options(tctx->lp_ctx, &options);
482 options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
483 options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
485 status = smbcli_full_connection(mem_ctx, c, hostname,
486 lp_smb_ports(tctx->lp_ctx),
489 lp_resolve_context(tctx->lp_ctx),
491 if (!NT_STATUS_IS_OK(status)) {
492 printf("Failed to open connection - %s\n", nt_errstr(status));
499 _PUBLIC_ bool torture_get_conn_index(int conn_index,
501 struct torture_context *tctx,
502 char **host, char **share)
504 char **unc_list = NULL;
505 int num_unc_names = 0;
508 (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
509 (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
511 p = torture_setting_string(tctx, "unclist", NULL);
516 unc_list = file_lines_load(p, &num_unc_names, NULL);
517 if (!unc_list || num_unc_names <= 0) {
518 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
522 if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
523 mem_ctx, host, share)) {
524 DEBUG(0, ("Failed to parse UNC name %s\n",
525 unc_list[conn_index % num_unc_names]));
529 talloc_free(unc_list);
535 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
537 struct torture_context *tctx,
538 struct event_context *ev)
543 if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
547 ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
554 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
556 return torture_open_connection_ev(c, conn_index, tctx,
557 cli_credentials_get_event_context(cmdline_credentials));
562 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
566 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
567 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
575 /* check if the server produced the expected error code */
576 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
577 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
581 status = smbcli_nt_error(c->tree);
582 if (NT_STATUS_IS_DOS(status)) {
584 class = NT_STATUS_DOS_CLASS(status);
585 num = NT_STATUS_DOS_CODE(status);
586 if (eclass != class || ecode != num) {
587 printf("unexpected error code %s\n", nt_errstr(status));
588 printf(" expected %s or %s (at %s)\n",
589 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
590 nt_errstr(nterr), location);
594 if (!NT_STATUS_EQUAL(nterr, status)) {
595 printf("unexpected error code %s\n", nt_errstr(status));
596 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
604 static struct smbcli_state *current_cli;
605 static int procnum; /* records process count number when forking */
607 static void sigcont(int sig)
611 double torture_create_procs(struct torture_context *tctx,
612 bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
615 volatile pid_t *child_status;
616 volatile bool *child_status_out;
619 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
620 double start_time_limit = 10 + (torture_nprocs * 1.5);
627 signal(SIGCONT, sigcont);
629 child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
631 printf("Failed to setup shared memory\n");
635 child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
636 if (!child_status_out) {
637 printf("Failed to setup result status shared memory\n");
641 for (i = 0; i < torture_nprocs; i++) {
643 child_status_out[i] = true;
646 tv = timeval_current();
648 for (i=0;i<torture_nprocs;i++) {
653 pid_t mypid = getpid();
654 srandom(((int)mypid) ^ ((int)time(NULL)));
656 asprintf(&myname, "CLIENT%d", i);
657 lp_set_cmdline(tctx->lp_ctx, "netbios name", myname);
662 if (torture_open_connection(¤t_cli, tctx, i)) {
666 printf("pid %d failed to start\n", (int)getpid());
672 child_status[i] = getpid();
676 if (child_status[i]) {
677 printf("Child %d failed to start!\n", i);
678 child_status_out[i] = 1;
682 child_status_out[i] = fn(tctx, current_cli, i);
689 for (i=0;i<torture_nprocs;i++) {
690 if (child_status[i]) synccount++;
692 if (synccount == torture_nprocs) break;
694 } while (timeval_elapsed(&tv) < start_time_limit);
696 if (synccount != torture_nprocs) {
697 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
699 return timeval_elapsed(&tv);
702 printf("Starting %d clients\n", torture_nprocs);
704 /* start the client load */
705 tv = timeval_current();
706 for (i=0;i<torture_nprocs;i++) {
710 printf("%d clients started\n", torture_nprocs);
714 for (i=0;i<torture_nprocs;i++) {
716 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
717 if (ret == -1 || WEXITSTATUS(status) != 0) {
724 for (i=0;i<torture_nprocs;i++) {
725 if (!child_status_out[i]) {
729 return timeval_elapsed(&tv);
732 static bool wrap_smb_multi_test(struct torture_context *torture,
733 struct torture_tcase *tcase,
734 struct torture_test *test)
736 bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
739 torture_create_procs(torture, fn, &result);
744 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
745 struct torture_suite *suite,
747 bool (*run) (struct torture_context *,
748 struct smbcli_state *,
751 struct torture_test *test;
752 struct torture_tcase *tcase;
754 tcase = torture_suite_add_tcase(suite, name);
756 test = talloc(tcase, struct torture_test);
758 test->name = talloc_strdup(test, name);
759 test->description = NULL;
760 test->run = wrap_smb_multi_test;
762 test->dangerous = false;
764 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
770 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
771 struct torture_tcase *tcase,
772 struct torture_test *test)
774 bool (*fn) (struct torture_context *, struct smbcli_state *,
775 struct smbcli_state *);
778 struct smbcli_state *cli1, *cli2;
780 if (!torture_open_connection(&cli1, torture_ctx, 0) ||
781 !torture_open_connection(&cli2, torture_ctx, 1))
786 ret = fn(torture_ctx, cli1, cli2);
796 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
797 struct torture_suite *suite,
799 bool (*run) (struct torture_context *,
800 struct smbcli_state *,
801 struct smbcli_state *))
803 struct torture_test *test;
804 struct torture_tcase *tcase;
806 tcase = torture_suite_add_tcase(suite, name);
808 test = talloc(tcase, struct torture_test);
810 test->name = talloc_strdup(test, name);
811 test->description = NULL;
812 test->run = wrap_simple_2smb_test;
814 test->dangerous = false;
816 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
822 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
823 struct torture_tcase *tcase,
824 struct torture_test *test)
826 bool (*fn) (struct torture_context *, struct smbcli_state *);
829 struct smbcli_state *cli1;
831 if (!torture_open_connection(&cli1, torture_ctx, 0))
836 ret = fn(torture_ctx, cli1);
843 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
844 struct torture_suite *suite,
846 bool (*run) (struct torture_context *, struct smbcli_state *))
848 struct torture_test *test;
849 struct torture_tcase *tcase;
851 tcase = torture_suite_add_tcase(suite, name);
853 test = talloc(tcase, struct torture_test);
855 test->name = talloc_strdup(test, name);
856 test->description = NULL;
857 test->run = wrap_simple_1smb_test;
859 test->dangerous = false;
861 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
867 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
868 struct smbcli_session *session,
869 const char *sharename,
870 struct smbcli_tree **res)
873 struct smbcli_tree *result;
877 if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
878 return NT_STATUS_NO_MEMORY;
881 result = smbcli_tree_init(session, tmp_ctx, false);
882 if (result == NULL) {
883 talloc_free(tmp_ctx);
884 return NT_STATUS_NO_MEMORY;
887 tcon.generic.level = RAW_TCON_TCONX;
888 tcon.tconx.in.flags = 0;
890 /* Ignore share mode security here */
891 tcon.tconx.in.password = data_blob(NULL, 0);
892 tcon.tconx.in.path = sharename;
893 tcon.tconx.in.device = "?????";
895 status = smb_raw_tcon(result, tmp_ctx, &tcon);
896 if (!NT_STATUS_IS_OK(status)) {
897 talloc_free(tmp_ctx);
901 result->tid = tcon.tconx.out.tid;
902 *res = talloc_steal(mem_ctx, result);
903 talloc_free(tmp_ctx);