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/smb/smb_constants.h"
26 #include "libcli/libcli.h"
27 #include "system/filesys.h"
28 #include "system/shmem.h"
29 #include "system/wait.h"
30 #include "system/time.h"
31 #include "torture/torture.h"
32 #include "../lib/util/dlinklist.h"
33 #include "libcli/resolve/resolve.h"
34 #include "param/param.h"
35 #include "libcli/security/security.h"
36 #include "libcli/util/clilsa.h"
37 #include "torture/util.h"
38 #include "libcli/smb/smbXcli_base.h"
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
| NTCREATEX_SHARE_ACCESS_DELETE
;
72 io
.ntcreatex
.in
.alloc_size
= 0;
73 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
74 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
75 io
.ntcreatex
.in
.security_flags
= 0;
76 io
.ntcreatex
.in
.fname
= dname
;
78 status
= smb_raw_open(tree
, mem_ctx
, &io
);
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 */
134 ZERO_STRUCT(setfile
);
135 setfile
.generic
.level
= RAW_SFILEINFO_BASIC_INFO
;
136 setfile
.generic
.in
.file
.fnum
= fnum
;
138 unix_to_nt_time(&setfile
.basic_info
.in
.create_time
,
140 unix_to_nt_time(&setfile
.basic_info
.in
.access_time
,
142 unix_to_nt_time(&setfile
.basic_info
.in
.write_time
,
145 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
146 if (!NT_STATUS_IS_OK(status
)) {
147 printf("Failed to setup file times - %s\n", nt_errstr(status
));
150 /* make sure all the timestamps aren't the same */
151 fileinfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
152 fileinfo
.generic
.in
.file
.fnum
= fnum
;
154 status
= smb_raw_fileinfo(cli
->tree
, mem_ctx
, &fileinfo
);
155 if (!NT_STATUS_IS_OK(status
)) {
156 printf("Failed to query file times - %s\n", nt_errstr(status
));
159 if (setfile
.basic_info
.in
.create_time
!= fileinfo
.basic_info
.out
.create_time
) {
160 printf("create_time not setup correctly\n");
162 if (setfile
.basic_info
.in
.access_time
!= fileinfo
.basic_info
.out
.access_time
) {
163 printf("access_time not setup correctly\n");
165 if (setfile
.basic_info
.in
.write_time
!= fileinfo
.basic_info
.out
.write_time
) {
166 printf("write_time not setup correctly\n");
174 sometimes we need a fairly complex directory to work with, so we can test
175 all possible attributes.
177 int create_complex_dir(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
, const char *dname
)
180 union smb_setfileinfo setfile
;
181 union smb_fileinfo fileinfo
;
182 time_t t
= (time(NULL
) & ~1);
185 smbcli_deltree(cli
->tree
, dname
);
186 fnum
= smbcli_nt_create_full(cli
->tree
, dname
, 0,
188 FILE_ATTRIBUTE_DIRECTORY
,
189 NTCREATEX_SHARE_ACCESS_READ
|
190 NTCREATEX_SHARE_ACCESS_WRITE
,
191 NTCREATEX_DISP_OPEN_IF
,
192 NTCREATEX_OPTIONS_DIRECTORY
, 0);
193 if (fnum
== -1) return -1;
195 if (strchr(dname
, ':') == NULL
) {
197 setfile
.generic
.level
= RAW_SFILEINFO_EA_SET
;
198 setfile
.generic
.in
.file
.fnum
= fnum
;
199 setfile
.ea_set
.in
.num_eas
= 2;
200 setfile
.ea_set
.in
.eas
= talloc_array(mem_ctx
, struct ea_struct
, 2);
201 setfile
.ea_set
.in
.eas
[0].flags
= 0;
202 setfile
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
203 setfile
.ea_set
.in
.eas
[0].value
= data_blob_talloc(mem_ctx
, "VALUE1", 6);
204 setfile
.ea_set
.in
.eas
[1].flags
= 0;
205 setfile
.ea_set
.in
.eas
[1].name
.s
= "SECONDEA";
206 setfile
.ea_set
.in
.eas
[1].value
= data_blob_talloc(mem_ctx
, "ValueTwo", 8);
207 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
208 if (!NT_STATUS_IS_OK(status
)) {
209 printf("Failed to setup EAs\n");
213 /* make sure all the timestamps aren't the same */
214 ZERO_STRUCT(setfile
);
215 setfile
.generic
.level
= RAW_SFILEINFO_BASIC_INFO
;
216 setfile
.generic
.in
.file
.fnum
= fnum
;
218 unix_to_nt_time(&setfile
.basic_info
.in
.create_time
,
220 unix_to_nt_time(&setfile
.basic_info
.in
.access_time
,
222 unix_to_nt_time(&setfile
.basic_info
.in
.write_time
,
225 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
226 if (!NT_STATUS_IS_OK(status
)) {
227 printf("Failed to setup file times - %s\n", nt_errstr(status
));
230 /* make sure all the timestamps aren't the same */
231 fileinfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
232 fileinfo
.generic
.in
.file
.fnum
= fnum
;
234 status
= smb_raw_fileinfo(cli
->tree
, mem_ctx
, &fileinfo
);
235 if (!NT_STATUS_IS_OK(status
)) {
236 printf("Failed to query file times - %s\n", nt_errstr(status
));
239 if (setfile
.basic_info
.in
.create_time
!= fileinfo
.basic_info
.out
.create_time
) {
240 printf("create_time not setup correctly\n");
242 if (setfile
.basic_info
.in
.access_time
!= fileinfo
.basic_info
.out
.access_time
) {
243 printf("access_time not setup correctly\n");
245 if (setfile
.basic_info
.in
.write_time
!= fileinfo
.basic_info
.out
.write_time
) {
246 printf("write_time not setup correctly\n");
253 check that a wire string matches the flags specified
254 not 100% accurate, but close enough for testing
256 bool wire_bad_flags(struct smb_wire_string
*str
, int flags
,
257 struct smbcli_transport
*transport
)
261 if (!str
|| !str
->s
) return true;
262 len
= strlen(str
->s
);
263 if (flags
& STR_TERMINATE
) len
++;
265 server_unicode
= (transport
->negotiate
.capabilities
&CAP_UNICODE
)?true:false;
266 if (getenv("CLI_FORCE_ASCII") || !transport
->options
.unicode
) {
267 server_unicode
= false;
270 if ((flags
& STR_UNICODE
) || server_unicode
) {
272 } else if (flags
& STR_TERMINATE_ASCII
) {
275 if (str
->private_length
!= len
) {
276 printf("Expected wire_length %d but got %d for '%s'\n",
277 len
, str
->private_length
, str
->s
);
284 dump a all_info QFILEINFO structure
286 void dump_all_info(TALLOC_CTX
*mem_ctx
, union smb_fileinfo
*finfo
)
288 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.create_time
));
289 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.access_time
));
290 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.write_time
));
291 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.change_time
));
292 d_printf("\tattrib: 0x%x\n", finfo
->all_info
.out
.attrib
);
293 d_printf("\talloc_size: %llu\n", (long long)finfo
->all_info
.out
.alloc_size
);
294 d_printf("\tsize: %llu\n", (long long)finfo
->all_info
.out
.size
);
295 d_printf("\tnlink: %u\n", finfo
->all_info
.out
.nlink
);
296 d_printf("\tdelete_pending: %u\n", finfo
->all_info
.out
.delete_pending
);
297 d_printf("\tdirectory: %u\n", finfo
->all_info
.out
.directory
);
298 d_printf("\tea_size: %u\n", finfo
->all_info
.out
.ea_size
);
299 d_printf("\tfname: '%s'\n", finfo
->all_info
.out
.fname
.s
);
303 dump file infor by name
305 void torture_all_info(struct smbcli_tree
*tree
, const char *fname
)
307 TALLOC_CTX
*mem_ctx
= talloc_named(tree
, 0, "%s", fname
);
308 union smb_fileinfo finfo
;
311 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
312 finfo
.generic
.in
.file
.path
= fname
;
313 status
= smb_raw_pathinfo(tree
, mem_ctx
, &finfo
);
314 if (!NT_STATUS_IS_OK(status
)) {
315 d_printf("%s - %s\n", fname
, nt_errstr(status
));
319 d_printf("%s:\n", fname
);
320 dump_all_info(mem_ctx
, &finfo
);
321 talloc_free(mem_ctx
);
326 set a attribute on a file
328 bool torture_set_file_attribute(struct smbcli_tree
*tree
, const char *fname
, uint16_t attrib
)
330 union smb_setfileinfo sfinfo
;
333 ZERO_STRUCT(sfinfo
.basic_info
.in
);
334 sfinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
335 sfinfo
.basic_info
.in
.file
.path
= fname
;
336 sfinfo
.basic_info
.in
.attrib
= attrib
;
337 status
= smb_raw_setpathinfo(tree
, &sfinfo
);
338 return NT_STATUS_IS_OK(status
);
343 set a file descriptor as sparse
345 NTSTATUS
torture_set_sparse(struct smbcli_tree
*tree
, int fnum
)
351 mem_ctx
= talloc_named_const(tree
, 0, "torture_set_sparse");
353 return NT_STATUS_NO_MEMORY
;
356 nt
.ntioctl
.level
= RAW_IOCTL_NTIOCTL
;
357 nt
.ntioctl
.in
.function
= FSCTL_SET_SPARSE
;
358 nt
.ntioctl
.in
.file
.fnum
= fnum
;
359 nt
.ntioctl
.in
.fsctl
= true;
360 nt
.ntioctl
.in
.filter
= 0;
361 nt
.ntioctl
.in
.max_data
= 0;
362 nt
.ntioctl
.in
.blob
= data_blob(NULL
, 0);
364 status
= smb_raw_ioctl(tree
, mem_ctx
, &nt
);
366 talloc_free(mem_ctx
);
372 check that an EA has the right value
374 NTSTATUS
torture_check_ea(struct smbcli_state
*cli
,
375 const char *fname
, const char *eaname
, const char *value
)
377 union smb_fileinfo info
;
380 TALLOC_CTX
*mem_ctx
= talloc_new(cli
);
382 info
.ea_list
.level
= RAW_FILEINFO_EA_LIST
;
383 info
.ea_list
.in
.file
.path
= fname
;
384 info
.ea_list
.in
.num_names
= 1;
385 info
.ea_list
.in
.ea_names
= &ea
;
389 status
= smb_raw_pathinfo(cli
->tree
, mem_ctx
, &info
);
390 if (!NT_STATUS_IS_OK(status
)) {
391 talloc_free(mem_ctx
);
395 if (info
.ea_list
.out
.num_eas
!= 1) {
396 printf("Expected 1 ea in ea_list\n");
397 talloc_free(mem_ctx
);
398 return NT_STATUS_EA_CORRUPT_ERROR
;
401 if (strcasecmp_m(eaname
, info
.ea_list
.out
.eas
[0].name
.s
) != 0) {
402 printf("Expected ea '%s' not '%s' in ea_list\n",
403 eaname
, info
.ea_list
.out
.eas
[0].name
.s
);
404 talloc_free(mem_ctx
);
405 return NT_STATUS_EA_CORRUPT_ERROR
;
409 if (info
.ea_list
.out
.eas
[0].value
.length
!= 0) {
410 printf("Expected zero length ea for %s\n", eaname
);
411 talloc_free(mem_ctx
);
412 return NT_STATUS_EA_CORRUPT_ERROR
;
414 talloc_free(mem_ctx
);
418 if (strlen(value
) == info
.ea_list
.out
.eas
[0].value
.length
&&
419 memcmp(value
, info
.ea_list
.out
.eas
[0].value
.data
,
420 info
.ea_list
.out
.eas
[0].value
.length
) == 0) {
421 talloc_free(mem_ctx
);
425 printf("Expected value '%s' not '%*.*s' for ea %s\n",
427 (int)info
.ea_list
.out
.eas
[0].value
.length
,
428 (int)info
.ea_list
.out
.eas
[0].value
.length
,
429 info
.ea_list
.out
.eas
[0].value
.data
,
432 talloc_free(mem_ctx
);
434 return NT_STATUS_EA_CORRUPT_ERROR
;
437 _PUBLIC_
bool torture_open_connection_share(TALLOC_CTX
*mem_ctx
,
438 struct smbcli_state
**c
,
439 struct torture_context
*tctx
,
440 const char *hostname
,
441 const char *sharename
,
442 struct tevent_context
*ev
)
446 struct smbcli_options options
;
447 struct smbcli_session_options session_options
;
449 lpcfg_smbcli_options(tctx
->lp_ctx
, &options
);
450 lpcfg_smbcli_session_options(tctx
->lp_ctx
, &session_options
);
452 options
.use_oplocks
= torture_setting_bool(tctx
, "use_oplocks", true);
453 options
.use_level2_oplocks
= torture_setting_bool(tctx
, "use_level2_oplocks", true);
455 status
= smbcli_full_connection(mem_ctx
, c
, hostname
,
456 lpcfg_smb_ports(tctx
->lp_ctx
),
458 lpcfg_socket_options(tctx
->lp_ctx
),
460 lpcfg_resolve_context(tctx
->lp_ctx
),
461 ev
, &options
, &session_options
,
462 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
));
463 if (!NT_STATUS_IS_OK(status
)) {
464 printf("Failed to open connection - %s\n", nt_errstr(status
));
471 _PUBLIC_
bool torture_get_conn_index(int conn_index
,
473 struct torture_context
*tctx
,
474 char **host
, char **share
)
476 char **unc_list
= NULL
;
477 int num_unc_names
= 0;
480 (*host
) = talloc_strdup(mem_ctx
, torture_setting_string(tctx
, "host", NULL
));
481 (*share
) = talloc_strdup(mem_ctx
, torture_setting_string(tctx
, "share", NULL
));
483 p
= torture_setting_string(tctx
, "unclist", NULL
);
488 unc_list
= file_lines_load(p
, &num_unc_names
, 0, NULL
);
489 if (!unc_list
|| num_unc_names
<= 0) {
490 DEBUG(0,("Failed to load unc names list from '%s'\n", p
));
494 p
= unc_list
[conn_index
% num_unc_names
];
495 if (p
[0] != '/' && p
[0] != '\\') {
496 /* allow UNC lists of hosts */
497 (*host
) = talloc_strdup(mem_ctx
, p
);
498 } else if (!smbcli_parse_unc(p
, mem_ctx
, host
, share
)) {
499 DEBUG(0, ("Failed to parse UNC name %s\n",
500 unc_list
[conn_index
% num_unc_names
]));
504 talloc_free(unc_list
);
510 _PUBLIC_
bool torture_open_connection_ev(struct smbcli_state
**c
,
512 struct torture_context
*tctx
,
513 struct tevent_context
*ev
)
518 if (!torture_get_conn_index(conn_index
, ev
, tctx
, &host
, &share
)) {
522 ret
= torture_open_connection_share(NULL
, c
, tctx
, host
, share
, ev
);
529 _PUBLIC_
bool torture_open_connection(struct smbcli_state
**c
, struct torture_context
*tctx
, int conn_index
)
531 return torture_open_connection_ev(c
, conn_index
, tctx
, tctx
->ev
);
536 _PUBLIC_
bool torture_close_connection(struct smbcli_state
*c
)
540 if (NT_STATUS_IS_ERR(smbcli_tdis(c
))) {
541 printf("tdis failed (%s)\n", smbcli_errstr(c
->tree
));
549 /* check if the server produced the expected error code */
550 _PUBLIC_
bool check_error(const char *location
, struct smbcli_state
*c
,
551 uint8_t eclass
, uint32_t ecode
, NTSTATUS nterr
)
555 status
= smbcli_nt_error(c
->tree
);
556 if (NT_STATUS_IS_DOS(status
)) {
558 classnum
= NT_STATUS_DOS_CLASS(status
);
559 num
= NT_STATUS_DOS_CODE(status
);
560 if (eclass
!= classnum
|| ecode
!= num
) {
561 printf("unexpected error code %s\n", nt_errstr(status
));
562 printf(" expected %s or %s (at %s)\n",
563 nt_errstr(NT_STATUS_DOS(eclass
, ecode
)),
564 nt_errstr(nterr
), location
);
568 if (!NT_STATUS_EQUAL(nterr
, status
)) {
569 printf("unexpected error code %s\n", nt_errstr(status
));
570 printf(" expected %s (at %s)\n", nt_errstr(nterr
), location
);
578 static struct smbcli_state
*current_cli
;
579 static int procnum
; /* records process count number when forking */
581 static void sigcont(int sig
)
585 double torture_create_procs(struct torture_context
*tctx
,
586 bool (*fn
)(struct torture_context
*, struct smbcli_state
*, int), bool *result
)
589 volatile pid_t
*child_status
;
590 volatile bool *child_status_out
;
593 int torture_nprocs
= torture_setting_int(tctx
, "nprocs", 4);
594 double start_time_limit
= 10 + (torture_nprocs
* 1.5);
601 signal(SIGCONT
, sigcont
);
603 child_status
= (volatile pid_t
*)anonymous_shared_allocate(sizeof(pid_t
)*torture_nprocs
);
605 printf("Failed to setup shared memory\n");
609 child_status_out
= (volatile bool *)anonymous_shared_allocate(sizeof(bool)*torture_nprocs
);
610 if (!child_status_out
) {
611 printf("Failed to setup result status shared memory\n");
615 for (i
= 0; i
< torture_nprocs
; i
++) {
617 child_status_out
[i
] = true;
620 tv
= timeval_current();
622 for (i
=0;i
<torture_nprocs
;i
++) {
627 pid_t mypid
= getpid();
628 srandom(((int)mypid
) ^ ((int)time(NULL
)));
630 if (asprintf(&myname
, "CLIENT%d", i
) == -1) {
631 printf("asprintf failed\n");
634 lpcfg_set_cmdline(tctx
->lp_ctx
, "netbios name", myname
);
639 if (torture_open_connection(¤t_cli
, tctx
, i
)) {
643 printf("pid %d failed to start\n", (int)getpid());
649 child_status
[i
] = getpid();
653 if (child_status
[i
]) {
654 printf("Child %d failed to start!\n", i
);
655 child_status_out
[i
] = 1;
659 child_status_out
[i
] = fn(tctx
, current_cli
, i
);
666 for (i
=0;i
<torture_nprocs
;i
++) {
667 if (child_status
[i
]) synccount
++;
669 if (synccount
== torture_nprocs
) break;
671 } while (timeval_elapsed(&tv
) < start_time_limit
);
673 if (synccount
!= torture_nprocs
) {
674 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs
, synccount
);
676 /* cleanup child processes */
677 for (i
= 0; i
< torture_nprocs
; i
++) {
678 if (child_status
[i
]) {
679 kill(child_status
[i
], SIGTERM
);
684 return timeval_elapsed(&tv
);
687 printf("Starting %d clients\n", torture_nprocs
);
689 /* start the client load */
690 tv
= timeval_current();
691 for (i
=0;i
<torture_nprocs
;i
++) {
695 printf("%d clients started\n", torture_nprocs
);
699 for (i
=0;i
<torture_nprocs
;i
++) {
701 while ((ret
=waitpid(0, &status
, 0)) == -1 && errno
== EINTR
) /* noop */ ;
702 if (ret
== -1 || WEXITSTATUS(status
) != 0) {
709 for (i
=0;i
<torture_nprocs
;i
++) {
710 if (!child_status_out
[i
]) {
714 return timeval_elapsed(&tv
);
717 static bool wrap_smb_multi_test(struct torture_context
*torture
,
718 struct torture_tcase
*tcase
,
719 struct torture_test
*test
)
721 bool (*fn
)(struct torture_context
*, struct smbcli_state
*, int ) = test
->fn
;
724 torture_create_procs(torture
, fn
, &result
);
729 _PUBLIC_
struct torture_test
*torture_suite_add_smb_multi_test(
730 struct torture_suite
*suite
,
732 bool (*run
) (struct torture_context
*,
733 struct smbcli_state
*,
736 struct torture_test
*test
;
737 struct torture_tcase
*tcase
;
739 tcase
= torture_suite_add_tcase(suite
, name
);
741 test
= talloc(tcase
, struct torture_test
);
743 test
->name
= talloc_strdup(test
, name
);
744 test
->description
= NULL
;
745 test
->run
= wrap_smb_multi_test
;
747 test
->dangerous
= false;
749 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
755 static bool wrap_simple_2smb_test(struct torture_context
*torture_ctx
,
756 struct torture_tcase
*tcase
,
757 struct torture_test
*test
)
759 bool (*fn
) (struct torture_context
*, struct smbcli_state
*,
760 struct smbcli_state
*);
763 struct smbcli_state
*cli1
= NULL
, *cli2
= NULL
;
765 torture_assert_goto(torture_ctx
, torture_open_connection(&cli1
, torture_ctx
, 0), ret
, fail
, "Failed to open connection");
766 torture_assert_goto(torture_ctx
, torture_open_connection(&cli2
, torture_ctx
, 1), ret
, fail
, "Failed to open connection");
770 ret
= fn(torture_ctx
, cli1
, cli2
);
780 _PUBLIC_
struct torture_test
*torture_suite_add_2smb_test(
781 struct torture_suite
*suite
,
783 bool (*run
) (struct torture_context
*,
784 struct smbcli_state
*,
785 struct smbcli_state
*))
787 struct torture_test
*test
;
788 struct torture_tcase
*tcase
;
790 tcase
= torture_suite_add_tcase(suite
, name
);
792 test
= talloc(tcase
, struct torture_test
);
794 test
->name
= talloc_strdup(test
, name
);
795 test
->description
= NULL
;
796 test
->run
= wrap_simple_2smb_test
;
798 test
->dangerous
= false;
800 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
806 static bool wrap_simple_1smb_test(struct torture_context
*torture_ctx
,
807 struct torture_tcase
*tcase
,
808 struct torture_test
*test
)
810 bool (*fn
) (struct torture_context
*, struct smbcli_state
*);
813 struct smbcli_state
*cli1
= NULL
;
815 torture_assert_goto(torture_ctx
, torture_open_connection(&cli1
, torture_ctx
, 0), ret
, fail
, "Failed to open connection");
819 ret
= fn(torture_ctx
, cli1
);
826 _PUBLIC_
struct torture_test
*torture_suite_add_1smb_test(
827 struct torture_suite
*suite
,
829 bool (*run
) (struct torture_context
*, struct smbcli_state
*))
831 struct torture_test
*test
;
832 struct torture_tcase
*tcase
;
834 tcase
= torture_suite_add_tcase(suite
, name
);
836 test
= talloc(tcase
, struct torture_test
);
838 test
->name
= talloc_strdup(test
, name
);
839 test
->description
= NULL
;
840 test
->run
= wrap_simple_1smb_test
;
842 test
->dangerous
= false;
844 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
850 NTSTATUS
torture_second_tcon(TALLOC_CTX
*mem_ctx
,
851 struct smbcli_session
*session
,
852 const char *sharename
,
853 struct smbcli_tree
**res
)
856 struct smbcli_tree
*result
;
860 if ((tmp_ctx
= talloc_new(mem_ctx
)) == NULL
) {
861 return NT_STATUS_NO_MEMORY
;
864 result
= smbcli_tree_init(session
, tmp_ctx
, false);
865 if (result
== NULL
) {
866 talloc_free(tmp_ctx
);
867 return NT_STATUS_NO_MEMORY
;
870 tcon
.generic
.level
= RAW_TCON_TCONX
;
871 tcon
.tconx
.in
.flags
= TCONX_FLAG_EXTENDED_RESPONSE
;
872 tcon
.tconx
.in
.flags
|= TCONX_FLAG_EXTENDED_SIGNATURES
;
874 /* Ignore share mode security here */
875 tcon
.tconx
.in
.password
= data_blob(NULL
, 0);
876 tcon
.tconx
.in
.path
= sharename
;
877 tcon
.tconx
.in
.device
= "?????";
879 status
= smb_raw_tcon(result
, tmp_ctx
, &tcon
);
880 if (!NT_STATUS_IS_OK(status
)) {
881 talloc_free(tmp_ctx
);
885 result
->tid
= tcon
.tconx
.out
.tid
;
887 if (tcon
.tconx
.out
.options
& SMB_EXTENDED_SIGNATURES
) {
888 smb1cli_session_protect_session_key(result
->session
->smbXcli
);
891 *res
= talloc_steal(mem_ctx
, result
);
892 talloc_free(tmp_ctx
);
897 a wrapper around smblsa_sid_check_privilege, that tries to take
898 account of the fact that the lsa privileges calls don't expand
899 group memberships, using an explicit check for administrator. There
900 must be a better way ...
902 NTSTATUS
torture_check_privilege(struct smbcli_state
*cli
,
904 const char *privilege
)
907 TALLOC_CTX
*tmp_ctx
= talloc_new(cli
);
911 sid
= dom_sid_parse_talloc(tmp_ctx
, sid_str
);
913 talloc_free(tmp_ctx
);
914 return NT_STATUS_INVALID_SID
;
917 status
= dom_sid_split_rid(tmp_ctx
, sid
, NULL
, &rid
);
918 if (!NT_STATUS_IS_OK(status
)) {
919 TALLOC_FREE(tmp_ctx
);
923 if (rid
== DOMAIN_RID_ADMINISTRATOR
) {
924 /* assume the administrator has them all */
928 talloc_free(tmp_ctx
);
930 return smblsa_sid_check_privilege(cli
, sid_str
, privilege
);