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
),
459 popt_get_cmdline_credentials(),
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 struct child_status
{
588 enum torture_result result
;
592 double torture_create_procs(struct torture_context
*tctx
,
593 bool (*fn
)(struct torture_context
*, struct smbcli_state
*, int),
598 struct child_status
*child_status
;
601 size_t torture_nprocs
= torture_setting_int(tctx
, "nprocs", 4);
602 double start_time_limit
= 10 + (torture_nprocs
* 1.5);
609 signal(SIGCONT
, sigcont
);
611 child_status
= (struct child_status
*)anonymous_shared_allocate(
612 sizeof(struct child_status
)*torture_nprocs
);
613 if (child_status
== NULL
) {
614 printf("Failed to setup shared memory\n");
618 for (i
= 0; i
< torture_nprocs
; i
++) {
619 ZERO_STRUCT(child_status
[i
]);
622 tv
= timeval_current();
624 for (i
=0;i
<torture_nprocs
;i
++) {
630 pid_t mypid
= getpid();
631 srandom(((int)mypid
) ^ ((int)time(NULL
)));
633 if (asprintf(&myname
, "CLIENT%zu", i
) == -1) {
634 printf("asprintf failed\n");
637 lpcfg_set_cmdline(tctx
->lp_ctx
, "netbios name", myname
);
642 if (torture_open_connection(¤t_cli
, tctx
, i
)) {
646 printf("pid %d failed to start\n", (int)getpid());
652 child_status
[i
].pid
= getpid();
656 if (!child_status
[i
].start
) {
657 child_status
[i
].result
= TORTURE_ERROR
;
658 printf("Child %zu failed to start!\n", i
);
662 ok
= fn(tctx
, current_cli
, i
);
664 if (tctx
->last_result
== TORTURE_OK
) {
665 torture_result(tctx
, TORTURE_ERROR
,
666 "unknown error: missing "
667 "torture_result call?\n");
670 child_status
[i
].result
= tctx
->last_result
;
672 if (strlen(tctx
->last_reason
) > 1023) {
673 /* note: reason already contains \n */
674 torture_comment(tctx
,
675 "child %zu (pid %u) failed: %s",
677 (unsigned)child_status
[i
].pid
,
681 snprintf(child_status
[i
].reason
,
682 1024, "child %zu (pid %u) failed: %s",
683 i
, (unsigned)child_status
[i
].pid
,
685 /* ensure proper "\n\0" termination: */
686 if (child_status
[i
].reason
[1022] != '\0') {
687 child_status
[i
].reason
[1022] = '\n';
688 child_status
[i
].reason
[1023] = '\0';
697 for (i
=0;i
<torture_nprocs
;i
++) {
698 if (child_status
[i
].pid
!= 0) {
702 if (synccount
== torture_nprocs
) {
706 } while (timeval_elapsed(&tv
) < start_time_limit
);
708 if (synccount
!= torture_nprocs
) {
709 printf("FAILED TO START %zu CLIENTS (started %zu)\n", torture_nprocs
, synccount
);
711 /* cleanup child processes */
712 for (i
= 0; i
< torture_nprocs
; i
++) {
713 if (child_status
[i
].pid
!= 0) {
714 kill(child_status
[i
].pid
, SIGTERM
);
719 return timeval_elapsed(&tv
);
722 printf("Starting %zu clients\n", torture_nprocs
);
724 /* start the client load */
725 tv
= timeval_current();
726 for (i
=0;i
<torture_nprocs
;i
++) {
727 child_status
[i
].start
= true;
730 printf("%zu clients started\n", torture_nprocs
);
734 for (i
=0;i
<torture_nprocs
;i
++) {
736 while ((ret
=waitpid(0, &status
, 0)) == -1 && errno
== EINTR
) /* noop */ ;
737 if (ret
== -1 || WEXITSTATUS(status
) != 0) {
744 for (i
=0;i
<torture_nprocs
;i
++) {
745 if (child_status
[i
].result
!= TORTURE_OK
) {
747 torture_result(tctx
, child_status
[i
].result
,
748 "%s", child_status
[i
].reason
);
752 return timeval_elapsed(&tv
);
755 static bool wrap_smb_multi_test(struct torture_context
*torture
,
756 struct torture_tcase
*tcase
,
757 struct torture_test
*test
)
759 bool (*fn
)(struct torture_context
*, struct smbcli_state
*, int ) = test
->fn
;
762 torture_create_procs(torture
, fn
, &result
);
767 _PUBLIC_
struct torture_test
*torture_suite_add_smb_multi_test(
768 struct torture_suite
*suite
,
770 bool (*run
) (struct torture_context
*,
771 struct smbcli_state
*,
774 struct torture_test
*test
;
775 struct torture_tcase
*tcase
;
777 tcase
= torture_suite_add_tcase(suite
, name
);
779 test
= talloc(tcase
, struct torture_test
);
781 test
->name
= talloc_strdup(test
, name
);
782 test
->description
= NULL
;
783 test
->run
= wrap_smb_multi_test
;
785 test
->dangerous
= false;
787 DLIST_ADD_END(tcase
->tests
, test
);
793 static bool wrap_simple_2smb_test(struct torture_context
*torture_ctx
,
794 struct torture_tcase
*tcase
,
795 struct torture_test
*test
)
797 bool (*fn
) (struct torture_context
*, struct smbcli_state
*,
798 struct smbcli_state
*);
801 struct smbcli_state
*cli1
= NULL
, *cli2
= NULL
;
803 torture_assert_goto(torture_ctx
, torture_open_connection(&cli1
, torture_ctx
, 0), ret
, fail
, "Failed to open connection");
804 torture_assert_goto(torture_ctx
, torture_open_connection(&cli2
, torture_ctx
, 1), ret
, fail
, "Failed to open connection");
808 ret
= fn(torture_ctx
, cli1
, cli2
);
818 _PUBLIC_
struct torture_test
*torture_suite_add_2smb_test(
819 struct torture_suite
*suite
,
821 bool (*run
) (struct torture_context
*,
822 struct smbcli_state
*,
823 struct smbcli_state
*))
825 struct torture_test
*test
;
826 struct torture_tcase
*tcase
;
828 tcase
= torture_suite_add_tcase(suite
, name
);
830 test
= talloc(tcase
, struct torture_test
);
832 test
->name
= talloc_strdup(test
, name
);
833 test
->description
= NULL
;
834 test
->run
= wrap_simple_2smb_test
;
836 test
->dangerous
= false;
838 DLIST_ADD_END(tcase
->tests
, test
);
844 static bool wrap_simple_1smb_test(struct torture_context
*torture_ctx
,
845 struct torture_tcase
*tcase
,
846 struct torture_test
*test
)
848 bool (*fn
) (struct torture_context
*, struct smbcli_state
*);
851 struct smbcli_state
*cli1
= NULL
;
853 torture_assert_goto(torture_ctx
, torture_open_connection(&cli1
, torture_ctx
, 0), ret
, fail
, "Failed to open connection");
857 ret
= fn(torture_ctx
, cli1
);
864 _PUBLIC_
struct torture_test
*torture_suite_add_1smb_test(
865 struct torture_suite
*suite
,
867 bool (*run
) (struct torture_context
*, struct smbcli_state
*))
869 struct torture_test
*test
;
870 struct torture_tcase
*tcase
;
872 tcase
= torture_suite_add_tcase(suite
, name
);
874 test
= talloc(tcase
, struct torture_test
);
876 test
->name
= talloc_strdup(test
, name
);
877 test
->description
= NULL
;
878 test
->run
= wrap_simple_1smb_test
;
880 test
->dangerous
= false;
882 DLIST_ADD_END(tcase
->tests
, test
);
888 NTSTATUS
torture_second_tcon(TALLOC_CTX
*mem_ctx
,
889 struct smbcli_session
*session
,
890 const char *sharename
,
891 struct smbcli_tree
**res
)
894 struct smbcli_tree
*result
;
898 if ((tmp_ctx
= talloc_new(mem_ctx
)) == NULL
) {
899 return NT_STATUS_NO_MEMORY
;
902 result
= smbcli_tree_init(session
, tmp_ctx
, false);
903 if (result
== NULL
) {
904 talloc_free(tmp_ctx
);
905 return NT_STATUS_NO_MEMORY
;
908 tcon
.generic
.level
= RAW_TCON_TCONX
;
909 tcon
.tconx
.in
.flags
= TCONX_FLAG_EXTENDED_RESPONSE
;
910 tcon
.tconx
.in
.flags
|= TCONX_FLAG_EXTENDED_SIGNATURES
;
912 /* Ignore share mode security here */
913 tcon
.tconx
.in
.password
= data_blob(NULL
, 0);
914 tcon
.tconx
.in
.path
= sharename
;
915 tcon
.tconx
.in
.device
= "?????";
917 status
= smb_raw_tcon(result
, tmp_ctx
, &tcon
);
918 if (!NT_STATUS_IS_OK(status
)) {
919 talloc_free(tmp_ctx
);
923 result
->tid
= tcon
.tconx
.out
.tid
;
925 if (tcon
.tconx
.out
.options
& SMB_EXTENDED_SIGNATURES
) {
926 smb1cli_session_protect_session_key(result
->session
->smbXcli
);
929 *res
= talloc_steal(mem_ctx
, result
);
930 talloc_free(tmp_ctx
);
935 a wrapper around smblsa_sid_check_privilege, that tries to take
936 account of the fact that the lsa privileges calls don't expand
937 group memberships, using an explicit check for administrator. There
938 must be a better way ...
940 NTSTATUS
torture_check_privilege(struct smbcli_state
*cli
,
942 const char *privilege
)
945 TALLOC_CTX
*tmp_ctx
= talloc_new(cli
);
949 sid
= dom_sid_parse_talloc(tmp_ctx
, sid_str
);
951 talloc_free(tmp_ctx
);
952 return NT_STATUS_INVALID_SID
;
955 status
= dom_sid_split_rid(tmp_ctx
, sid
, NULL
, &rid
);
956 if (!NT_STATUS_IS_OK(status
)) {
957 TALLOC_FREE(tmp_ctx
);
961 if (rid
== DOMAIN_RID_ADMINISTRATOR
) {
962 /* assume the administrator has them all */
966 talloc_free(tmp_ctx
);
968 return smblsa_sid_check_privilege(cli
, sid_str
, privilege
);