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/cmdline.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "../libcli/smb/smb_constants.h"
26 #include "libcli/libcli.h"
27 #include "system/filesys.h"
28 #include "system/shmem.h"
29 #include "system/wait.h"
30 #include "system/time.h"
31 #include "torture/torture.h"
32 #include "../lib/util/dlinklist.h"
33 #include "libcli/resolve/resolve.h"
34 #include "param/param.h"
35 #include "libcli/security/security.h"
36 #include "libcli/smb2/smb2.h"
37 #include "libcli/util/clilsa.h"
38 #include "torture/util.h"
39 #include "libcli/smb/smbXcli_base.h"
40 #include "auth/credentials/credentials.h"
41 #include "auth/credentials/credentials_krb5.h"
44 setup a directory ready for a test
46 _PUBLIC_
bool torture_setup_dir(struct smbcli_state
*cli
, const char *dname
)
48 smb_raw_exit(cli
->session
);
49 if (smbcli_deltree(cli
->tree
, dname
) == -1 ||
50 NT_STATUS_IS_ERR(smbcli_mkdir(cli
->tree
, dname
))) {
51 printf("Unable to setup %s - %s\n", dname
, smbcli_errstr(cli
->tree
));
58 create a directory, returning a handle to it
60 NTSTATUS
create_directory_handle(struct smbcli_tree
*tree
, const char *dname
, int *fnum
)
66 mem_ctx
= talloc_named_const(tree
, 0, "create_directory_handle");
68 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
69 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
70 io
.ntcreatex
.in
.flags
= 0;
71 io
.ntcreatex
.in
.access_mask
= SEC_RIGHTS_FILE_ALL
;
72 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
73 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
74 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
| NTCREATEX_SHARE_ACCESS_DELETE
;
75 io
.ntcreatex
.in
.alloc_size
= 0;
76 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
77 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
78 io
.ntcreatex
.in
.security_flags
= 0;
79 io
.ntcreatex
.in
.fname
= dname
;
81 status
= smb_raw_open(tree
, mem_ctx
, &io
);
84 if (NT_STATUS_IS_OK(status
)) {
85 *fnum
= io
.ntcreatex
.out
.file
.fnum
;
93 sometimes we need a fairly complex file to work with, so we can test
94 all possible attributes.
96 _PUBLIC_
int create_complex_file(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
, const char *fname
)
100 union smb_setfileinfo setfile
;
101 union smb_fileinfo fileinfo
;
102 time_t t
= (time(NULL
) & ~1);
105 smbcli_unlink(cli
->tree
, fname
);
106 fnum
= smbcli_nt_create_full(cli
->tree
, fname
, 0,
108 FILE_ATTRIBUTE_NORMAL
,
109 NTCREATEX_SHARE_ACCESS_DELETE
|
110 NTCREATEX_SHARE_ACCESS_READ
|
111 NTCREATEX_SHARE_ACCESS_WRITE
,
112 NTCREATEX_DISP_OVERWRITE_IF
,
114 if (fnum
== -1) return -1;
116 smbcli_write(cli
->tree
, fnum
, 0, buf
, 0, sizeof(buf
));
118 if (strchr(fname
, ':') == NULL
) {
120 setfile
.generic
.level
= RAW_SFILEINFO_EA_SET
;
121 setfile
.generic
.in
.file
.fnum
= fnum
;
122 setfile
.ea_set
.in
.num_eas
= 2;
123 setfile
.ea_set
.in
.eas
= talloc_array(mem_ctx
, struct ea_struct
, 2);
124 setfile
.ea_set
.in
.eas
[0].flags
= 0;
125 setfile
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
126 setfile
.ea_set
.in
.eas
[0].value
= data_blob_talloc(mem_ctx
, "VALUE1", 6);
127 setfile
.ea_set
.in
.eas
[1].flags
= 0;
128 setfile
.ea_set
.in
.eas
[1].name
.s
= "SECONDEA";
129 setfile
.ea_set
.in
.eas
[1].value
= data_blob_talloc(mem_ctx
, "ValueTwo", 8);
130 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
131 if (!NT_STATUS_IS_OK(status
)) {
132 printf("Failed to setup EAs\n");
136 /* make sure all the timestamps aren't the same */
137 ZERO_STRUCT(setfile
);
138 setfile
.generic
.level
= RAW_SFILEINFO_BASIC_INFO
;
139 setfile
.generic
.in
.file
.fnum
= fnum
;
141 unix_to_nt_time(&setfile
.basic_info
.in
.create_time
,
143 unix_to_nt_time(&setfile
.basic_info
.in
.access_time
,
145 unix_to_nt_time(&setfile
.basic_info
.in
.write_time
,
148 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
149 if (!NT_STATUS_IS_OK(status
)) {
150 printf("Failed to setup file times - %s\n", nt_errstr(status
));
153 /* make sure all the timestamps aren't the same */
154 fileinfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
155 fileinfo
.generic
.in
.file
.fnum
= fnum
;
157 status
= smb_raw_fileinfo(cli
->tree
, mem_ctx
, &fileinfo
);
158 if (!NT_STATUS_IS_OK(status
)) {
159 printf("Failed to query file times - %s\n", nt_errstr(status
));
162 if (setfile
.basic_info
.in
.create_time
!= fileinfo
.basic_info
.out
.create_time
) {
163 printf("create_time not setup correctly\n");
165 if (setfile
.basic_info
.in
.access_time
!= fileinfo
.basic_info
.out
.access_time
) {
166 printf("access_time not setup correctly\n");
168 if (setfile
.basic_info
.in
.write_time
!= fileinfo
.basic_info
.out
.write_time
) {
169 printf("write_time not setup correctly\n");
177 sometimes we need a fairly complex directory to work with, so we can test
178 all possible attributes.
180 int create_complex_dir(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
, const char *dname
)
183 union smb_setfileinfo setfile
;
184 union smb_fileinfo fileinfo
;
185 time_t t
= (time(NULL
) & ~1);
188 smbcli_deltree(cli
->tree
, dname
);
189 fnum
= smbcli_nt_create_full(cli
->tree
, dname
, 0,
191 FILE_ATTRIBUTE_DIRECTORY
,
192 NTCREATEX_SHARE_ACCESS_READ
|
193 NTCREATEX_SHARE_ACCESS_WRITE
,
194 NTCREATEX_DISP_OPEN_IF
,
195 NTCREATEX_OPTIONS_DIRECTORY
, 0);
196 if (fnum
== -1) return -1;
198 if (strchr(dname
, ':') == NULL
) {
200 setfile
.generic
.level
= RAW_SFILEINFO_EA_SET
;
201 setfile
.generic
.in
.file
.fnum
= fnum
;
202 setfile
.ea_set
.in
.num_eas
= 2;
203 setfile
.ea_set
.in
.eas
= talloc_array(mem_ctx
, struct ea_struct
, 2);
204 setfile
.ea_set
.in
.eas
[0].flags
= 0;
205 setfile
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
206 setfile
.ea_set
.in
.eas
[0].value
= data_blob_talloc(mem_ctx
, "VALUE1", 6);
207 setfile
.ea_set
.in
.eas
[1].flags
= 0;
208 setfile
.ea_set
.in
.eas
[1].name
.s
= "SECONDEA";
209 setfile
.ea_set
.in
.eas
[1].value
= data_blob_talloc(mem_ctx
, "ValueTwo", 8);
210 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
211 if (!NT_STATUS_IS_OK(status
)) {
212 printf("Failed to setup EAs\n");
216 /* make sure all the timestamps aren't the same */
217 ZERO_STRUCT(setfile
);
218 setfile
.generic
.level
= RAW_SFILEINFO_BASIC_INFO
;
219 setfile
.generic
.in
.file
.fnum
= fnum
;
221 unix_to_nt_time(&setfile
.basic_info
.in
.create_time
,
223 unix_to_nt_time(&setfile
.basic_info
.in
.access_time
,
225 unix_to_nt_time(&setfile
.basic_info
.in
.write_time
,
228 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
229 if (!NT_STATUS_IS_OK(status
)) {
230 printf("Failed to setup file times - %s\n", nt_errstr(status
));
233 /* make sure all the timestamps aren't the same */
234 fileinfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
235 fileinfo
.generic
.in
.file
.fnum
= fnum
;
237 status
= smb_raw_fileinfo(cli
->tree
, mem_ctx
, &fileinfo
);
238 if (!NT_STATUS_IS_OK(status
)) {
239 printf("Failed to query file times - %s\n", nt_errstr(status
));
242 if (setfile
.basic_info
.in
.create_time
!= fileinfo
.basic_info
.out
.create_time
) {
243 printf("create_time not setup correctly\n");
245 if (setfile
.basic_info
.in
.access_time
!= fileinfo
.basic_info
.out
.access_time
) {
246 printf("access_time not setup correctly\n");
248 if (setfile
.basic_info
.in
.write_time
!= fileinfo
.basic_info
.out
.write_time
) {
249 printf("write_time not setup correctly\n");
256 check that a wire string matches the flags specified
257 not 100% accurate, but close enough for testing
259 bool wire_bad_flags(struct smb_wire_string
*str
, int flags
,
260 struct smbcli_transport
*transport
)
264 if (!str
|| !str
->s
) return true;
265 len
= strlen(str
->s
);
266 if (flags
& STR_TERMINATE
) len
++;
268 server_unicode
= (transport
->negotiate
.capabilities
&CAP_UNICODE
)?true:false;
269 if (getenv("CLI_FORCE_ASCII") || !transport
->options
.unicode
) {
270 server_unicode
= false;
273 if ((flags
& STR_UNICODE
) || server_unicode
) {
275 } else if (flags
& STR_TERMINATE_ASCII
) {
278 if (str
->private_length
!= len
) {
279 printf("Expected wire_length %d but got %d for '%s'\n",
280 len
, str
->private_length
, str
->s
);
287 dump a all_info QFILEINFO structure
289 void dump_all_info(TALLOC_CTX
*mem_ctx
, union smb_fileinfo
*finfo
)
291 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.create_time
));
292 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.access_time
));
293 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.write_time
));
294 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.change_time
));
295 d_printf("\tattrib: 0x%x\n", finfo
->all_info
.out
.attrib
);
296 d_printf("\talloc_size: %llu\n", (long long)finfo
->all_info
.out
.alloc_size
);
297 d_printf("\tsize: %llu\n", (long long)finfo
->all_info
.out
.size
);
298 d_printf("\tnlink: %u\n", finfo
->all_info
.out
.nlink
);
299 d_printf("\tdelete_pending: %u\n", finfo
->all_info
.out
.delete_pending
);
300 d_printf("\tdirectory: %u\n", finfo
->all_info
.out
.directory
);
301 d_printf("\tea_size: %u\n", finfo
->all_info
.out
.ea_size
);
302 d_printf("\tfname: '%s'\n", finfo
->all_info
.out
.fname
.s
);
306 dump file infor by name
308 void torture_all_info(struct smbcli_tree
*tree
, const char *fname
)
310 TALLOC_CTX
*mem_ctx
= talloc_named(tree
, 0, "%s", fname
);
311 union smb_fileinfo finfo
;
314 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
315 finfo
.generic
.in
.file
.path
= fname
;
316 status
= smb_raw_pathinfo(tree
, mem_ctx
, &finfo
);
317 if (!NT_STATUS_IS_OK(status
)) {
318 d_printf("%s - %s\n", fname
, nt_errstr(status
));
322 d_printf("%s:\n", fname
);
323 dump_all_info(mem_ctx
, &finfo
);
324 talloc_free(mem_ctx
);
329 set a attribute on a file
331 bool torture_set_file_attribute(struct smbcli_tree
*tree
, const char *fname
, uint16_t attrib
)
333 union smb_setfileinfo sfinfo
;
336 ZERO_STRUCT(sfinfo
.basic_info
.in
);
337 sfinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
338 sfinfo
.basic_info
.in
.file
.path
= fname
;
339 sfinfo
.basic_info
.in
.attrib
= attrib
;
340 status
= smb_raw_setpathinfo(tree
, &sfinfo
);
341 return NT_STATUS_IS_OK(status
);
346 set a file descriptor as sparse
348 NTSTATUS
torture_set_sparse(struct smbcli_tree
*tree
, int fnum
)
354 mem_ctx
= talloc_named_const(tree
, 0, "torture_set_sparse");
356 return NT_STATUS_NO_MEMORY
;
359 nt
.ntioctl
.level
= RAW_IOCTL_NTIOCTL
;
360 nt
.ntioctl
.in
.function
= FSCTL_SET_SPARSE
;
361 nt
.ntioctl
.in
.file
.fnum
= fnum
;
362 nt
.ntioctl
.in
.fsctl
= true;
363 nt
.ntioctl
.in
.filter
= 0;
364 nt
.ntioctl
.in
.max_data
= 0;
365 nt
.ntioctl
.in
.blob
= data_blob(NULL
, 0);
367 status
= smb_raw_ioctl(tree
, mem_ctx
, &nt
);
369 talloc_free(mem_ctx
);
375 check that an EA has the right value
377 NTSTATUS
torture_check_ea(struct smbcli_state
*cli
,
378 const char *fname
, const char *eaname
, const char *value
)
380 union smb_fileinfo info
;
383 TALLOC_CTX
*mem_ctx
= talloc_new(cli
);
385 info
.ea_list
.level
= RAW_FILEINFO_EA_LIST
;
386 info
.ea_list
.in
.file
.path
= fname
;
387 info
.ea_list
.in
.num_names
= 1;
388 info
.ea_list
.in
.ea_names
= &ea
;
392 status
= smb_raw_pathinfo(cli
->tree
, mem_ctx
, &info
);
393 if (!NT_STATUS_IS_OK(status
)) {
394 talloc_free(mem_ctx
);
398 if (info
.ea_list
.out
.num_eas
!= 1) {
399 printf("Expected 1 ea in ea_list\n");
400 talloc_free(mem_ctx
);
401 return NT_STATUS_EA_CORRUPT_ERROR
;
404 if (strcasecmp_m(eaname
, info
.ea_list
.out
.eas
[0].name
.s
) != 0) {
405 printf("Expected ea '%s' not '%s' in ea_list\n",
406 eaname
, info
.ea_list
.out
.eas
[0].name
.s
);
407 talloc_free(mem_ctx
);
408 return NT_STATUS_EA_CORRUPT_ERROR
;
412 if (info
.ea_list
.out
.eas
[0].value
.length
!= 0) {
413 printf("Expected zero length ea for %s\n", eaname
);
414 talloc_free(mem_ctx
);
415 return NT_STATUS_EA_CORRUPT_ERROR
;
417 talloc_free(mem_ctx
);
421 if (strlen(value
) == info
.ea_list
.out
.eas
[0].value
.length
&&
422 memcmp(value
, info
.ea_list
.out
.eas
[0].value
.data
,
423 info
.ea_list
.out
.eas
[0].value
.length
) == 0) {
424 talloc_free(mem_ctx
);
428 printf("Expected value '%s' not '%*.*s' for ea %s\n",
430 (int)info
.ea_list
.out
.eas
[0].value
.length
,
431 (int)info
.ea_list
.out
.eas
[0].value
.length
,
432 info
.ea_list
.out
.eas
[0].value
.data
,
435 talloc_free(mem_ctx
);
437 return NT_STATUS_EA_CORRUPT_ERROR
;
440 _PUBLIC_
bool torture_open_connection_share(TALLOC_CTX
*mem_ctx
,
441 struct smbcli_state
**c
,
442 struct torture_context
*tctx
,
443 const char *hostname
,
444 const char *sharename
,
445 struct tevent_context
*ev
)
449 struct smbcli_options options
;
450 struct smbcli_session_options session_options
;
452 lpcfg_smbcli_options(tctx
->lp_ctx
, &options
);
453 lpcfg_smbcli_session_options(tctx
->lp_ctx
, &session_options
);
455 options
.use_oplocks
= torture_setting_bool(tctx
, "use_oplocks", true);
456 options
.use_level2_oplocks
= torture_setting_bool(tctx
, "use_level2_oplocks", true);
458 status
= smbcli_full_connection(mem_ctx
, c
, hostname
,
459 lpcfg_smb_ports(tctx
->lp_ctx
),
461 lpcfg_socket_options(tctx
->lp_ctx
),
462 samba_cmdline_get_creds(),
463 lpcfg_resolve_context(tctx
->lp_ctx
),
464 ev
, &options
, &session_options
,
465 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
));
466 if (!NT_STATUS_IS_OK(status
)) {
467 printf("Failed to open connection - %s\n", nt_errstr(status
));
474 _PUBLIC_
bool torture_get_conn_index(int conn_index
,
476 struct torture_context
*tctx
,
477 char **host
, char **share
)
479 char **unc_list
= NULL
;
480 int num_unc_names
= 0;
483 (*host
) = talloc_strdup(mem_ctx
, torture_setting_string(tctx
, "host", NULL
));
484 (*share
) = talloc_strdup(mem_ctx
, torture_setting_string(tctx
, "share", NULL
));
486 p
= torture_setting_string(tctx
, "unclist", NULL
);
491 unc_list
= file_lines_load(p
, &num_unc_names
, 0, NULL
);
492 if (!unc_list
|| num_unc_names
<= 0) {
493 DEBUG(0,("Failed to load unc names list from '%s'\n", p
));
497 p
= unc_list
[conn_index
% num_unc_names
];
498 if (p
[0] != '/' && p
[0] != '\\') {
499 /* allow UNC lists of hosts */
500 (*host
) = talloc_strdup(mem_ctx
, p
);
501 } else if (!smbcli_parse_unc(p
, mem_ctx
, host
, share
)) {
502 DEBUG(0, ("Failed to parse UNC name %s\n",
503 unc_list
[conn_index
% num_unc_names
]));
507 talloc_free(unc_list
);
513 _PUBLIC_
bool torture_open_connection_ev(struct smbcli_state
**c
,
515 struct torture_context
*tctx
,
516 struct tevent_context
*ev
)
521 if (!torture_get_conn_index(conn_index
, ev
, tctx
, &host
, &share
)) {
525 ret
= torture_open_connection_share(NULL
, c
, tctx
, host
, share
, ev
);
532 _PUBLIC_
bool torture_open_connection(struct smbcli_state
**c
, struct torture_context
*tctx
, int conn_index
)
534 return torture_open_connection_ev(c
, conn_index
, tctx
, tctx
->ev
);
539 _PUBLIC_
bool torture_close_connection(struct smbcli_state
*c
)
543 if (NT_STATUS_IS_ERR(smbcli_tdis(c
))) {
544 printf("tdis failed (%s)\n", smbcli_errstr(c
->tree
));
552 /* check if the server produced the expected error code */
553 _PUBLIC_
bool check_error(const char *location
, struct smbcli_state
*c
,
554 uint8_t eclass
, uint32_t ecode
, NTSTATUS nterr
)
558 status
= smbcli_nt_error(c
->tree
);
559 if (NT_STATUS_IS_DOS(status
)) {
561 classnum
= NT_STATUS_DOS_CLASS(status
);
562 num
= NT_STATUS_DOS_CODE(status
);
563 if (eclass
!= classnum
|| ecode
!= num
) {
564 printf("unexpected error code %s\n", nt_errstr(status
));
565 printf(" expected %s or %s (at %s)\n",
566 nt_errstr(NT_STATUS_DOS(eclass
, ecode
)),
567 nt_errstr(nterr
), location
);
571 if (!NT_STATUS_EQUAL(nterr
, status
)) {
572 printf("unexpected error code %s\n", nt_errstr(status
));
573 printf(" expected %s (at %s)\n", nt_errstr(nterr
), location
);
581 static struct smbcli_state
*current_cli
;
582 static int procnum
; /* records process count number when forking */
584 static void sigcont(int sig
)
588 struct child_status
{
591 enum torture_result result
;
595 double torture_create_procs(struct torture_context
*tctx
,
596 bool (*fn
)(struct torture_context
*, struct smbcli_state
*, int),
601 struct child_status
*child_status
;
604 size_t torture_nprocs
= torture_setting_int(tctx
, "nprocs", 4);
605 double start_time_limit
= 10 + (torture_nprocs
* 1.5);
612 signal(SIGCONT
, sigcont
);
614 child_status
= (struct child_status
*)anonymous_shared_allocate(
615 sizeof(struct child_status
)*torture_nprocs
);
616 if (child_status
== NULL
) {
617 printf("Failed to setup shared memory\n");
621 for (i
= 0; i
< torture_nprocs
; i
++) {
622 ZERO_STRUCT(child_status
[i
]);
625 tv
= timeval_current();
627 for (i
=0;i
<torture_nprocs
;i
++) {
633 pid_t mypid
= getpid();
634 srandom(((int)mypid
) ^ ((int)time(NULL
)));
636 if (asprintf(&myname
, "CLIENT%zu", i
) == -1) {
637 printf("asprintf failed\n");
640 lpcfg_set_cmdline(tctx
->lp_ctx
, "netbios name", myname
);
645 if (torture_open_connection(¤t_cli
, tctx
, i
)) {
649 printf("pid %d failed to start\n", (int)getpid());
655 child_status
[i
].pid
= getpid();
659 if (!child_status
[i
].start
) {
660 child_status
[i
].result
= TORTURE_ERROR
;
661 printf("Child %zu failed to start!\n", i
);
665 ok
= fn(tctx
, current_cli
, i
);
667 if (tctx
->last_result
== TORTURE_OK
) {
668 torture_result(tctx
, TORTURE_ERROR
,
669 "unknown error: missing "
670 "torture_result call?\n");
673 child_status
[i
].result
= tctx
->last_result
;
675 if (strlen(tctx
->last_reason
) > 1023) {
676 /* note: reason already contains \n */
677 torture_comment(tctx
,
678 "child %zu (pid %u) failed: %s",
680 (unsigned)child_status
[i
].pid
,
684 snprintf(child_status
[i
].reason
,
685 1024, "child %zu (pid %u) failed: %s",
686 i
, (unsigned)child_status
[i
].pid
,
688 /* ensure proper "\n\0" termination: */
689 if (child_status
[i
].reason
[1022] != '\0') {
690 child_status
[i
].reason
[1022] = '\n';
691 child_status
[i
].reason
[1023] = '\0';
700 for (i
=0;i
<torture_nprocs
;i
++) {
701 if (child_status
[i
].pid
!= 0) {
705 if (synccount
== torture_nprocs
) {
709 } while (timeval_elapsed(&tv
) < start_time_limit
);
711 if (synccount
!= torture_nprocs
) {
712 printf("FAILED TO START %zu CLIENTS (started %zu)\n", torture_nprocs
, synccount
);
714 /* cleanup child processes */
715 for (i
= 0; i
< torture_nprocs
; i
++) {
716 if (child_status
[i
].pid
!= 0) {
717 kill(child_status
[i
].pid
, SIGTERM
);
722 return timeval_elapsed(&tv
);
725 printf("Starting %zu clients\n", torture_nprocs
);
727 /* start the client load */
728 tv
= timeval_current();
729 for (i
=0;i
<torture_nprocs
;i
++) {
730 child_status
[i
].start
= true;
733 printf("%zu clients started\n", torture_nprocs
);
737 for (i
=0;i
<torture_nprocs
;i
++) {
739 while ((ret
=waitpid(0, &status
, 0)) == -1 && errno
== EINTR
) /* noop */ ;
740 if (ret
== -1 || WEXITSTATUS(status
) != 0) {
747 for (i
=0;i
<torture_nprocs
;i
++) {
748 if (child_status
[i
].result
!= TORTURE_OK
) {
750 torture_result(tctx
, child_status
[i
].result
,
751 "%s", child_status
[i
].reason
);
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
);
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
= NULL
, *cli2
= NULL
;
806 torture_assert_goto(torture_ctx
, torture_open_connection(&cli1
, torture_ctx
, 0), ret
, fail
, "Failed to open connection");
807 torture_assert_goto(torture_ctx
, torture_open_connection(&cli2
, torture_ctx
, 1), ret
, fail
, "Failed to open connection");
811 ret
= fn(torture_ctx
, cli1
, cli2
);
821 _PUBLIC_
struct torture_test
*torture_suite_add_2smb_test(
822 struct torture_suite
*suite
,
824 bool (*run
) (struct torture_context
*,
825 struct smbcli_state
*,
826 struct smbcli_state
*))
828 struct torture_test
*test
;
829 struct torture_tcase
*tcase
;
831 tcase
= torture_suite_add_tcase(suite
, name
);
833 test
= talloc(tcase
, struct torture_test
);
835 test
->name
= talloc_strdup(test
, name
);
836 test
->description
= NULL
;
837 test
->run
= wrap_simple_2smb_test
;
839 test
->dangerous
= false;
841 DLIST_ADD_END(tcase
->tests
, test
);
847 static bool wrap_simple_1smb_test(struct torture_context
*torture_ctx
,
848 struct torture_tcase
*tcase
,
849 struct torture_test
*test
)
851 bool (*fn
) (struct torture_context
*, struct smbcli_state
*);
854 struct smbcli_state
*cli1
= NULL
;
856 torture_assert_goto(torture_ctx
, torture_open_connection(&cli1
, torture_ctx
, 0), ret
, fail
, "Failed to open connection");
860 ret
= fn(torture_ctx
, cli1
);
867 _PUBLIC_
struct torture_test
*torture_suite_add_1smb_test(
868 struct torture_suite
*suite
,
870 bool (*run
) (struct torture_context
*, struct smbcli_state
*))
872 struct torture_test
*test
;
873 struct torture_tcase
*tcase
;
875 tcase
= torture_suite_add_tcase(suite
, name
);
877 test
= talloc(tcase
, struct torture_test
);
879 test
->name
= talloc_strdup(test
, name
);
880 test
->description
= NULL
;
881 test
->run
= wrap_simple_1smb_test
;
883 test
->dangerous
= false;
885 DLIST_ADD_END(tcase
->tests
, test
);
891 NTSTATUS
torture_second_tcon(TALLOC_CTX
*mem_ctx
,
892 struct smbcli_session
*session
,
893 const char *sharename
,
894 struct smbcli_tree
**res
)
897 struct smbcli_tree
*result
;
901 if ((tmp_ctx
= talloc_new(mem_ctx
)) == NULL
) {
902 return NT_STATUS_NO_MEMORY
;
905 result
= smbcli_tree_init(session
, tmp_ctx
, false);
906 if (result
== NULL
) {
907 talloc_free(tmp_ctx
);
908 return NT_STATUS_NO_MEMORY
;
911 tcon
.generic
.level
= RAW_TCON_TCONX
;
912 tcon
.tconx
.in
.flags
= TCONX_FLAG_EXTENDED_RESPONSE
;
913 tcon
.tconx
.in
.flags
|= TCONX_FLAG_EXTENDED_SIGNATURES
;
915 /* Ignore share mode security here */
916 tcon
.tconx
.in
.password
= data_blob(NULL
, 0);
917 tcon
.tconx
.in
.path
= sharename
;
918 tcon
.tconx
.in
.device
= "?????";
920 status
= smb_raw_tcon(result
, tmp_ctx
, &tcon
);
921 if (!NT_STATUS_IS_OK(status
)) {
922 talloc_free(tmp_ctx
);
926 result
->tid
= tcon
.tconx
.out
.tid
;
928 if (tcon
.tconx
.out
.options
& SMB_EXTENDED_SIGNATURES
) {
929 smb1cli_session_protect_session_key(result
->session
->smbXcli
);
932 *res
= talloc_steal(mem_ctx
, result
);
933 talloc_free(tmp_ctx
);
938 a wrapper around smblsa_sid_check_privilege, that tries to take
939 account of the fact that the lsa privileges calls don't expand
940 group memberships, using an explicit check for administrator. There
941 must be a better way ...
943 NTSTATUS
torture_check_privilege(struct smbcli_state
*cli
,
945 const char *privilege
)
948 TALLOC_CTX
*tmp_ctx
= talloc_new(cli
);
952 sid
= dom_sid_parse_talloc(tmp_ctx
, sid_str
);
954 talloc_free(tmp_ctx
);
955 return NT_STATUS_INVALID_SID
;
958 status
= dom_sid_split_rid(tmp_ctx
, sid
, NULL
, &rid
);
959 if (!NT_STATUS_IS_OK(status
)) {
960 TALLOC_FREE(tmp_ctx
);
964 if (rid
== DOMAIN_RID_ADMINISTRATOR
) {
965 /* assume the administrator has them all */
969 talloc_free(tmp_ctx
);
971 return smblsa_sid_check_privilege(cli
, sid_str
, privilege
);
975 * Use this to pass a 2nd user:
977 * --option='torture:user2name=user2'
978 * --option='torture:user2domain=domain2'
979 * --option='torture:user2password=password2'
981 struct cli_credentials
*torture_user2_credentials(struct torture_context
*tctx
,
984 struct cli_credentials
*credentials1
= samba_cmdline_get_creds();
985 const char *user1domain
= cli_credentials_get_domain(credentials1
);
986 const char *user2name
= torture_setting_string(tctx
, "user2name", NULL
);
987 const char *user2domain
= torture_setting_string(tctx
, "user2domain", user1domain
);
988 const char *user2password
= torture_setting_string(tctx
, "user2password", NULL
);
989 struct cli_credentials
*credentials2
= NULL
;
991 credentials2
= cli_credentials_shallow_copy(mem_ctx
, credentials1
);
992 if (credentials2
== NULL
) {
993 torture_comment(tctx
,
994 "%s: cli_credentials_shallow_copy() failed\n",
998 if (user2name
!= NULL
) {
999 torture_comment(tctx
,
1001 "'torture:user2name'='%s' "
1002 "'torture:user2domain'='%s' "
1003 "'torture:user2password'='REDACTED'",
1006 cli_credentials_set_username(credentials2
, user2name
, CRED_SPECIFIED
);
1007 cli_credentials_set_domain(credentials2
, user2domain
, CRED_SPECIFIED
);
1008 cli_credentials_set_password(credentials2
, user2password
, CRED_SPECIFIED
);
1010 torture_comment(tctx
,
1011 "Fallback to anonymous for "
1012 "'torture:user2name'=NULL "
1013 "'torture:user2domain'='%s' "
1014 "'torture:user2password'='REDACTED'",
1016 cli_credentials_set_anonymous(credentials2
);
1019 return credentials2
;