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/torture.h"
32 #include "../lib/util/dlinklist.h"
33 #include "auth/credentials/credentials.h"
34 #include "libcli/resolve/resolve.h"
35 #include "param/param.h"
36 #include "libcli/security/security.h"
37 #include "libcli/util/clilsa.h"
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));
55 create a directory, returning a handle to it
57 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
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;
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);
81 if (NT_STATUS_IS_OK(status)) {
82 *fnum = io.ntcreatex.out.file.fnum;
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)
97 union smb_setfileinfo setfile;
98 union smb_fileinfo fileinfo;
99 time_t t = (time(NULL) & ~1);
102 smbcli_unlink(cli->tree, fname);
103 fnum = smbcli_nt_create_full(cli->tree, fname, 0,
105 FILE_ATTRIBUTE_NORMAL,
106 NTCREATEX_SHARE_ACCESS_DELETE|
107 NTCREATEX_SHARE_ACCESS_READ|
108 NTCREATEX_SHARE_ACCESS_WRITE,
109 NTCREATEX_DISP_OVERWRITE_IF,
111 if (fnum == -1) return -1;
113 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
115 if (strchr(fname, ':') == NULL) {
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, and are also
134 in different DST zones*/
135 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
136 setfile.generic.in.file.fnum = fnum;
138 setfile.setattre.in.create_time = t + 9*30*24*60*60;
139 setfile.setattre.in.access_time = t + 6*30*24*60*60;
140 setfile.setattre.in.write_time = t + 3*30*24*60*60;
142 status = smb_raw_setfileinfo(cli->tree, &setfile);
143 if (!NT_STATUS_IS_OK(status)) {
144 printf("Failed to setup file times - %s\n", nt_errstr(status));
147 /* make sure all the timestamps aren't the same */
148 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
149 fileinfo.generic.in.file.fnum = fnum;
151 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
152 if (!NT_STATUS_IS_OK(status)) {
153 printf("Failed to query file times - %s\n", nt_errstr(status));
156 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
157 printf("create_time not setup correctly\n");
159 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
160 printf("access_time not setup correctly\n");
162 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
163 printf("write_time not setup correctly\n");
171 sometimes we need a fairly complex directory to work with, so we can test
172 all possible attributes.
174 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
177 union smb_setfileinfo setfile;
178 union smb_fileinfo fileinfo;
179 time_t t = (time(NULL) & ~1);
182 smbcli_deltree(cli->tree, dname);
183 fnum = smbcli_nt_create_full(cli->tree, dname, 0,
185 FILE_ATTRIBUTE_DIRECTORY,
186 NTCREATEX_SHARE_ACCESS_READ|
187 NTCREATEX_SHARE_ACCESS_WRITE,
188 NTCREATEX_DISP_OPEN_IF,
189 NTCREATEX_OPTIONS_DIRECTORY, 0);
190 if (fnum == -1) return -1;
192 if (strchr(dname, ':') == NULL) {
194 setfile.generic.level = RAW_SFILEINFO_EA_SET;
195 setfile.generic.in.file.fnum = fnum;
196 setfile.ea_set.in.num_eas = 2;
197 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
198 setfile.ea_set.in.eas[0].flags = 0;
199 setfile.ea_set.in.eas[0].name.s = "EAONE";
200 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
201 setfile.ea_set.in.eas[1].flags = 0;
202 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
203 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
204 status = smb_raw_setfileinfo(cli->tree, &setfile);
205 if (!NT_STATUS_IS_OK(status)) {
206 printf("Failed to setup EAs\n");
210 /* make sure all the timestamps aren't the same, and are also
211 in different DST zones*/
212 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
213 setfile.generic.in.file.fnum = fnum;
215 setfile.setattre.in.create_time = t + 9*30*24*60*60;
216 setfile.setattre.in.access_time = t + 6*30*24*60*60;
217 setfile.setattre.in.write_time = t + 3*30*24*60*60;
219 status = smb_raw_setfileinfo(cli->tree, &setfile);
220 if (!NT_STATUS_IS_OK(status)) {
221 printf("Failed to setup file times - %s\n", nt_errstr(status));
224 /* make sure all the timestamps aren't the same */
225 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
226 fileinfo.generic.in.file.fnum = fnum;
228 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
229 if (!NT_STATUS_IS_OK(status)) {
230 printf("Failed to query file times - %s\n", nt_errstr(status));
233 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
234 printf("create_time not setup correctly\n");
236 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
237 printf("access_time not setup correctly\n");
239 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
240 printf("write_time not setup correctly\n");
248 /* return a pointer to a anonymous shared memory segment of size "size"
249 which will persist across fork() but will disappear when all processes
252 The memory is not zeroed
254 This function uses system5 shared memory. It takes advantage of a property
255 that the memory is not destroyed if it is attached when the id is removed
257 void *shm_setup(int size)
263 shmid = shm_open("private", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
265 printf("can't get shared memory\n");
268 shm_unlink("private");
269 if (ftruncate(shmid, size) == -1) {
270 printf("can't set shared memory size\n");
273 ret = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0);
274 if (ret == MAP_FAILED) {
275 printf("can't map shared memory\n");
279 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
281 printf("can't get shared memory\n");
284 ret = (void *)shmat(shmid, 0, 0);
285 if (!ret || ret == (void *)-1) {
286 printf("can't attach to shared memory\n");
289 /* the following releases the ipc, but note that this process
290 and all its children will still have access to the memory, its
291 just that the shmid is no longer valid for other shm calls. This
292 means we don't leave behind lots of shm segments after we exit
294 See Stevens "advanced programming in unix env" for details
296 shmctl(shmid, IPC_RMID, 0);
304 check that a wire string matches the flags specified
305 not 100% accurate, but close enough for testing
307 bool wire_bad_flags(struct smb_wire_string *str, int flags,
308 struct smbcli_transport *transport)
312 if (!str || !str->s) return true;
313 len = strlen(str->s);
314 if (flags & STR_TERMINATE) len++;
316 server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
317 if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
318 server_unicode = false;
321 if ((flags & STR_UNICODE) || server_unicode) {
323 } else if (flags & STR_TERMINATE_ASCII) {
326 if (str->private_length != len) {
327 printf("Expected wire_length %d but got %d for '%s'\n",
328 len, str->private_length, str->s);
335 dump a all_info QFILEINFO structure
337 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
339 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
340 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
341 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
342 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
343 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
344 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
345 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
346 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
347 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
348 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
349 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
350 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
354 dump file infor by name
356 void torture_all_info(struct smbcli_tree *tree, const char *fname)
358 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
359 union smb_fileinfo finfo;
362 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
363 finfo.generic.in.file.path = fname;
364 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
365 if (!NT_STATUS_IS_OK(status)) {
366 d_printf("%s - %s\n", fname, nt_errstr(status));
370 d_printf("%s:\n", fname);
371 dump_all_info(mem_ctx, &finfo);
372 talloc_free(mem_ctx);
377 set a attribute on a file
379 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
381 union smb_setfileinfo sfinfo;
384 ZERO_STRUCT(sfinfo.basic_info.in);
385 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
386 sfinfo.basic_info.in.file.path = fname;
387 sfinfo.basic_info.in.attrib = attrib;
388 status = smb_raw_setpathinfo(tree, &sfinfo);
389 return NT_STATUS_IS_OK(status);
394 set a file descriptor as sparse
396 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
402 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
404 return NT_STATUS_NO_MEMORY;
407 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
408 nt.ntioctl.in.function = FSCTL_SET_SPARSE;
409 nt.ntioctl.in.file.fnum = fnum;
410 nt.ntioctl.in.fsctl = true;
411 nt.ntioctl.in.filter = 0;
412 nt.ntioctl.in.max_data = 0;
413 nt.ntioctl.in.blob = data_blob(NULL, 0);
415 status = smb_raw_ioctl(tree, mem_ctx, &nt);
417 talloc_free(mem_ctx);
423 check that an EA has the right value
425 NTSTATUS torture_check_ea(struct smbcli_state *cli,
426 const char *fname, const char *eaname, const char *value)
428 union smb_fileinfo info;
431 TALLOC_CTX *mem_ctx = talloc_new(cli);
433 info.ea_list.level = RAW_FILEINFO_EA_LIST;
434 info.ea_list.in.file.path = fname;
435 info.ea_list.in.num_names = 1;
436 info.ea_list.in.ea_names = &ea;
440 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
441 if (!NT_STATUS_IS_OK(status)) {
442 talloc_free(mem_ctx);
446 if (info.ea_list.out.num_eas != 1) {
447 printf("Expected 1 ea in ea_list\n");
448 talloc_free(mem_ctx);
449 return NT_STATUS_EA_CORRUPT_ERROR;
452 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
453 printf("Expected ea '%s' not '%s' in ea_list\n",
454 eaname, info.ea_list.out.eas[0].name.s);
455 talloc_free(mem_ctx);
456 return NT_STATUS_EA_CORRUPT_ERROR;
460 if (info.ea_list.out.eas[0].value.length != 0) {
461 printf("Expected zero length ea for %s\n", eaname);
462 talloc_free(mem_ctx);
463 return NT_STATUS_EA_CORRUPT_ERROR;
465 talloc_free(mem_ctx);
469 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
470 memcmp(value, info.ea_list.out.eas[0].value.data,
471 info.ea_list.out.eas[0].value.length) == 0) {
472 talloc_free(mem_ctx);
476 printf("Expected value '%s' not '%*.*s' for ea %s\n",
478 (int)info.ea_list.out.eas[0].value.length,
479 (int)info.ea_list.out.eas[0].value.length,
480 info.ea_list.out.eas[0].value.data,
483 talloc_free(mem_ctx);
485 return NT_STATUS_EA_CORRUPT_ERROR;
488 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
489 struct smbcli_state **c,
490 struct torture_context *tctx,
491 const char *hostname,
492 const char *sharename,
493 struct tevent_context *ev)
497 struct smbcli_options options;
498 struct smbcli_session_options session_options;
500 lp_smbcli_options(tctx->lp_ctx, &options);
501 lp_smbcli_session_options(tctx->lp_ctx, &session_options);
503 options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
504 options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
506 status = smbcli_full_connection(mem_ctx, c, hostname,
507 lp_smb_ports(tctx->lp_ctx),
509 lp_socket_options(tctx->lp_ctx),
511 lp_resolve_context(tctx->lp_ctx),
512 ev, &options, &session_options,
513 lp_iconv_convenience(tctx->lp_ctx),
514 lp_gensec_settings(tctx, tctx->lp_ctx));
515 if (!NT_STATUS_IS_OK(status)) {
516 printf("Failed to open connection - %s\n", nt_errstr(status));
523 _PUBLIC_ bool torture_get_conn_index(int conn_index,
525 struct torture_context *tctx,
526 char **host, char **share)
528 char **unc_list = NULL;
529 int num_unc_names = 0;
532 (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
533 (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
535 p = torture_setting_string(tctx, "unclist", NULL);
540 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
541 if (!unc_list || num_unc_names <= 0) {
542 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
546 if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
547 mem_ctx, host, share)) {
548 DEBUG(0, ("Failed to parse UNC name %s\n",
549 unc_list[conn_index % num_unc_names]));
553 talloc_free(unc_list);
559 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
561 struct torture_context *tctx,
562 struct tevent_context *ev)
567 if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
571 ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
578 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
580 return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
585 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
589 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
590 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
598 /* check if the server produced the expected error code */
599 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
600 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
604 status = smbcli_nt_error(c->tree);
605 if (NT_STATUS_IS_DOS(status)) {
607 classnum = NT_STATUS_DOS_CLASS(status);
608 num = NT_STATUS_DOS_CODE(status);
609 if (eclass != classnum || ecode != num) {
610 printf("unexpected error code %s\n", nt_errstr(status));
611 printf(" expected %s or %s (at %s)\n",
612 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
613 nt_errstr(nterr), location);
617 if (!NT_STATUS_EQUAL(nterr, status)) {
618 printf("unexpected error code %s\n", nt_errstr(status));
619 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
627 static struct smbcli_state *current_cli;
628 static int procnum; /* records process count number when forking */
630 static void sigcont(int sig)
634 double torture_create_procs(struct torture_context *tctx,
635 bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
638 volatile pid_t *child_status;
639 volatile bool *child_status_out;
642 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
643 double start_time_limit = 10 + (torture_nprocs * 1.5);
650 signal(SIGCONT, sigcont);
652 child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
654 printf("Failed to setup shared memory\n");
658 child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
659 if (!child_status_out) {
660 printf("Failed to setup result status shared memory\n");
664 for (i = 0; i < torture_nprocs; i++) {
666 child_status_out[i] = true;
669 tv = timeval_current();
671 for (i=0;i<torture_nprocs;i++) {
676 pid_t mypid = getpid();
677 srandom(((int)mypid) ^ ((int)time(NULL)));
679 if (asprintf(&myname, "CLIENT%d", i) == -1) {
680 printf("asprintf failed\n");
683 lp_set_cmdline(tctx->lp_ctx, "netbios name", myname);
688 if (torture_open_connection(¤t_cli, tctx, i)) {
692 printf("pid %d failed to start\n", (int)getpid());
698 child_status[i] = getpid();
702 if (child_status[i]) {
703 printf("Child %d failed to start!\n", i);
704 child_status_out[i] = 1;
708 child_status_out[i] = fn(tctx, current_cli, i);
715 for (i=0;i<torture_nprocs;i++) {
716 if (child_status[i]) synccount++;
718 if (synccount == torture_nprocs) break;
720 } while (timeval_elapsed(&tv) < start_time_limit);
722 if (synccount != torture_nprocs) {
723 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
725 return timeval_elapsed(&tv);
728 printf("Starting %d clients\n", torture_nprocs);
730 /* start the client load */
731 tv = timeval_current();
732 for (i=0;i<torture_nprocs;i++) {
736 printf("%d clients started\n", torture_nprocs);
740 for (i=0;i<torture_nprocs;i++) {
742 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
743 if (ret == -1 || WEXITSTATUS(status) != 0) {
750 for (i=0;i<torture_nprocs;i++) {
751 if (!child_status_out[i]) {
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;
765 torture_create_procs(torture, fn, &result);
770 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
771 struct torture_suite *suite,
773 bool (*run) (struct torture_context *,
774 struct smbcli_state *,
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;
788 test->dangerous = false;
790 DLIST_ADD_END(tcase->tests, test, struct torture_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 *);
804 struct smbcli_state *cli1, *cli2;
806 if (!torture_open_connection(&cli1, torture_ctx, 0) ||
807 !torture_open_connection(&cli2, torture_ctx, 1))
812 ret = fn(torture_ctx, cli1, cli2);
822 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
823 struct torture_suite *suite,
825 bool (*run) (struct torture_context *,
826 struct smbcli_state *,
827 struct smbcli_state *))
829 struct torture_test *test;
830 struct torture_tcase *tcase;
832 tcase = torture_suite_add_tcase(suite, name);
834 test = talloc(tcase, struct torture_test);
836 test->name = talloc_strdup(test, name);
837 test->description = NULL;
838 test->run = wrap_simple_2smb_test;
840 test->dangerous = false;
842 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
848 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
849 struct torture_tcase *tcase,
850 struct torture_test *test)
852 bool (*fn) (struct torture_context *, struct smbcli_state *);
855 struct smbcli_state *cli1;
857 if (!torture_open_connection(&cli1, torture_ctx, 0))
862 ret = fn(torture_ctx, cli1);
869 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
870 struct torture_suite *suite,
872 bool (*run) (struct torture_context *, struct smbcli_state *))
874 struct torture_test *test;
875 struct torture_tcase *tcase;
877 tcase = torture_suite_add_tcase(suite, name);
879 test = talloc(tcase, struct torture_test);
881 test->name = talloc_strdup(test, name);
882 test->description = NULL;
883 test->run = wrap_simple_1smb_test;
885 test->dangerous = false;
887 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
893 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
894 struct smbcli_session *session,
895 const char *sharename,
896 struct smbcli_tree **res)
899 struct smbcli_tree *result;
903 if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
904 return NT_STATUS_NO_MEMORY;
907 result = smbcli_tree_init(session, tmp_ctx, false);
908 if (result == NULL) {
909 talloc_free(tmp_ctx);
910 return NT_STATUS_NO_MEMORY;
913 tcon.generic.level = RAW_TCON_TCONX;
914 tcon.tconx.in.flags = 0;
916 /* Ignore share mode security here */
917 tcon.tconx.in.password = data_blob(NULL, 0);
918 tcon.tconx.in.path = sharename;
919 tcon.tconx.in.device = "?????";
921 status = smb_raw_tcon(result, tmp_ctx, &tcon);
922 if (!NT_STATUS_IS_OK(status)) {
923 talloc_free(tmp_ctx);
927 result->tid = tcon.tconx.out.tid;
928 *res = talloc_steal(mem_ctx, result);
929 talloc_free(tmp_ctx);
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,
941 const char *privilege)
944 TALLOC_CTX *tmp_ctx = talloc_new(cli);
948 sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
950 talloc_free(tmp_ctx);
951 return NT_STATUS_INVALID_SID;
954 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
955 NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
957 if (rid == DOMAIN_RID_ADMINISTRATOR) {
958 /* assume the administrator has them all */
962 talloc_free(tmp_ctx);
964 return smblsa_sid_check_privilege(cli, sid_str, privilege);