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 "libcli/resolve/resolve.h"
34 #include "param/param.h"
35 #include "libcli/security/security.h"
36 #include "libcli/util/clilsa.h"
40 setup a directory ready for a test
42 _PUBLIC_
bool torture_setup_dir(struct smbcli_state
*cli
, const char *dname
)
44 smb_raw_exit(cli
->session
);
45 if (smbcli_deltree(cli
->tree
, dname
) == -1 ||
46 NT_STATUS_IS_ERR(smbcli_mkdir(cli
->tree
, dname
))) {
47 printf("Unable to setup %s - %s\n", dname
, smbcli_errstr(cli
->tree
));
54 create a directory, returning a handle to it
56 NTSTATUS
create_directory_handle(struct smbcli_tree
*tree
, const char *dname
, int *fnum
)
62 mem_ctx
= talloc_named_const(tree
, 0, "create_directory_handle");
64 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
65 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
66 io
.ntcreatex
.in
.flags
= 0;
67 io
.ntcreatex
.in
.access_mask
= SEC_RIGHTS_FILE_ALL
;
68 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
69 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
70 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
71 io
.ntcreatex
.in
.alloc_size
= 0;
72 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
73 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
74 io
.ntcreatex
.in
.security_flags
= 0;
75 io
.ntcreatex
.in
.fname
= dname
;
77 status
= smb_raw_open(tree
, mem_ctx
, &io
);
80 if (NT_STATUS_IS_OK(status
)) {
81 *fnum
= io
.ntcreatex
.out
.file
.fnum
;
89 sometimes we need a fairly complex file to work with, so we can test
90 all possible attributes.
92 _PUBLIC_
int create_complex_file(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
, const char *fname
)
96 union smb_setfileinfo setfile
;
97 union smb_fileinfo fileinfo
;
98 time_t t
= (time(NULL
) & ~1);
101 smbcli_unlink(cli
->tree
, fname
);
102 fnum
= smbcli_nt_create_full(cli
->tree
, fname
, 0,
104 FILE_ATTRIBUTE_NORMAL
,
105 NTCREATEX_SHARE_ACCESS_DELETE
|
106 NTCREATEX_SHARE_ACCESS_READ
|
107 NTCREATEX_SHARE_ACCESS_WRITE
,
108 NTCREATEX_DISP_OVERWRITE_IF
,
110 if (fnum
== -1) return -1;
112 smbcli_write(cli
->tree
, fnum
, 0, buf
, 0, sizeof(buf
));
114 if (strchr(fname
, ':') == NULL
) {
116 setfile
.generic
.level
= RAW_SFILEINFO_EA_SET
;
117 setfile
.generic
.in
.file
.fnum
= fnum
;
118 setfile
.ea_set
.in
.num_eas
= 2;
119 setfile
.ea_set
.in
.eas
= talloc_array(mem_ctx
, struct ea_struct
, 2);
120 setfile
.ea_set
.in
.eas
[0].flags
= 0;
121 setfile
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
122 setfile
.ea_set
.in
.eas
[0].value
= data_blob_talloc(mem_ctx
, "VALUE1", 6);
123 setfile
.ea_set
.in
.eas
[1].flags
= 0;
124 setfile
.ea_set
.in
.eas
[1].name
.s
= "SECONDEA";
125 setfile
.ea_set
.in
.eas
[1].value
= data_blob_talloc(mem_ctx
, "ValueTwo", 8);
126 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
127 if (!NT_STATUS_IS_OK(status
)) {
128 printf("Failed to setup EAs\n");
132 /* make sure all the timestamps aren't the same, and are also
133 in different DST zones*/
134 setfile
.generic
.level
= RAW_SFILEINFO_SETATTRE
;
135 setfile
.generic
.in
.file
.fnum
= fnum
;
137 setfile
.setattre
.in
.create_time
= t
+ 9*30*24*60*60;
138 setfile
.setattre
.in
.access_time
= t
+ 6*30*24*60*60;
139 setfile
.setattre
.in
.write_time
= t
+ 3*30*24*60*60;
141 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
142 if (!NT_STATUS_IS_OK(status
)) {
143 printf("Failed to setup file times - %s\n", nt_errstr(status
));
146 /* make sure all the timestamps aren't the same */
147 fileinfo
.generic
.level
= RAW_FILEINFO_GETATTRE
;
148 fileinfo
.generic
.in
.file
.fnum
= fnum
;
150 status
= smb_raw_fileinfo(cli
->tree
, mem_ctx
, &fileinfo
);
151 if (!NT_STATUS_IS_OK(status
)) {
152 printf("Failed to query file times - %s\n", nt_errstr(status
));
155 if (setfile
.setattre
.in
.create_time
!= fileinfo
.getattre
.out
.create_time
) {
156 printf("create_time not setup correctly\n");
158 if (setfile
.setattre
.in
.access_time
!= fileinfo
.getattre
.out
.access_time
) {
159 printf("access_time not setup correctly\n");
161 if (setfile
.setattre
.in
.write_time
!= fileinfo
.getattre
.out
.write_time
) {
162 printf("write_time not setup correctly\n");
170 sometimes we need a fairly complex directory to work with, so we can test
171 all possible attributes.
173 int create_complex_dir(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
, const char *dname
)
176 union smb_setfileinfo setfile
;
177 union smb_fileinfo fileinfo
;
178 time_t t
= (time(NULL
) & ~1);
181 smbcli_deltree(cli
->tree
, dname
);
182 fnum
= smbcli_nt_create_full(cli
->tree
, dname
, 0,
184 FILE_ATTRIBUTE_DIRECTORY
,
185 NTCREATEX_SHARE_ACCESS_READ
|
186 NTCREATEX_SHARE_ACCESS_WRITE
,
187 NTCREATEX_DISP_OPEN_IF
,
188 NTCREATEX_OPTIONS_DIRECTORY
, 0);
189 if (fnum
== -1) return -1;
191 if (strchr(dname
, ':') == NULL
) {
193 setfile
.generic
.level
= RAW_SFILEINFO_EA_SET
;
194 setfile
.generic
.in
.file
.fnum
= fnum
;
195 setfile
.ea_set
.in
.num_eas
= 2;
196 setfile
.ea_set
.in
.eas
= talloc_array(mem_ctx
, struct ea_struct
, 2);
197 setfile
.ea_set
.in
.eas
[0].flags
= 0;
198 setfile
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
199 setfile
.ea_set
.in
.eas
[0].value
= data_blob_talloc(mem_ctx
, "VALUE1", 6);
200 setfile
.ea_set
.in
.eas
[1].flags
= 0;
201 setfile
.ea_set
.in
.eas
[1].name
.s
= "SECONDEA";
202 setfile
.ea_set
.in
.eas
[1].value
= data_blob_talloc(mem_ctx
, "ValueTwo", 8);
203 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
204 if (!NT_STATUS_IS_OK(status
)) {
205 printf("Failed to setup EAs\n");
209 /* make sure all the timestamps aren't the same, and are also
210 in different DST zones*/
211 setfile
.generic
.level
= RAW_SFILEINFO_SETATTRE
;
212 setfile
.generic
.in
.file
.fnum
= fnum
;
214 setfile
.setattre
.in
.create_time
= t
+ 9*30*24*60*60;
215 setfile
.setattre
.in
.access_time
= t
+ 6*30*24*60*60;
216 setfile
.setattre
.in
.write_time
= t
+ 3*30*24*60*60;
218 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
219 if (!NT_STATUS_IS_OK(status
)) {
220 printf("Failed to setup file times - %s\n", nt_errstr(status
));
223 /* make sure all the timestamps aren't the same */
224 fileinfo
.generic
.level
= RAW_FILEINFO_GETATTRE
;
225 fileinfo
.generic
.in
.file
.fnum
= fnum
;
227 status
= smb_raw_fileinfo(cli
->tree
, mem_ctx
, &fileinfo
);
228 if (!NT_STATUS_IS_OK(status
)) {
229 printf("Failed to query file times - %s\n", nt_errstr(status
));
232 if (setfile
.setattre
.in
.create_time
!= fileinfo
.getattre
.out
.create_time
) {
233 printf("create_time not setup correctly\n");
235 if (setfile
.setattre
.in
.access_time
!= fileinfo
.getattre
.out
.access_time
) {
236 printf("access_time not setup correctly\n");
238 if (setfile
.setattre
.in
.write_time
!= fileinfo
.getattre
.out
.write_time
) {
239 printf("write_time not setup correctly\n");
247 /* return a pointer to a anonymous shared memory segment of size "size"
248 which will persist across fork() but will disappear when all processes
251 The memory is not zeroed
253 This function uses system5 shared memory. It takes advantage of a property
254 that the memory is not destroyed if it is attached when the id is removed
256 void *shm_setup(int size
)
262 shmid
= shm_open("private", O_RDWR
| O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
);
264 printf("can't get shared memory\n");
267 shm_unlink("private");
268 if (ftruncate(shmid
, size
) == -1) {
269 printf("can't set shared memory size\n");
272 ret
= mmap(0, size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, shmid
, 0);
273 if (ret
== MAP_FAILED
) {
274 printf("can't map shared memory\n");
278 shmid
= shmget(IPC_PRIVATE
, size
, SHM_R
| SHM_W
);
280 printf("can't get shared memory\n");
283 ret
= (void *)shmat(shmid
, 0, 0);
284 if (!ret
|| ret
== (void *)-1) {
285 printf("can't attach to shared memory\n");
288 /* the following releases the ipc, but note that this process
289 and all its children will still have access to the memory, its
290 just that the shmid is no longer valid for other shm calls. This
291 means we don't leave behind lots of shm segments after we exit
293 See Stevens "advanced programming in unix env" for details
295 shmctl(shmid
, IPC_RMID
, 0);
303 check that a wire string matches the flags specified
304 not 100% accurate, but close enough for testing
306 bool wire_bad_flags(struct smb_wire_string
*str
, int flags
,
307 struct smbcli_transport
*transport
)
311 if (!str
|| !str
->s
) return true;
312 len
= strlen(str
->s
);
313 if (flags
& STR_TERMINATE
) len
++;
315 server_unicode
= (transport
->negotiate
.capabilities
&CAP_UNICODE
)?true:false;
316 if (getenv("CLI_FORCE_ASCII") || !transport
->options
.unicode
) {
317 server_unicode
= false;
320 if ((flags
& STR_UNICODE
) || server_unicode
) {
322 } else if (flags
& STR_TERMINATE_ASCII
) {
325 if (str
->private_length
!= len
) {
326 printf("Expected wire_length %d but got %d for '%s'\n",
327 len
, str
->private_length
, str
->s
);
334 dump a all_info QFILEINFO structure
336 void dump_all_info(TALLOC_CTX
*mem_ctx
, union smb_fileinfo
*finfo
)
338 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.create_time
));
339 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.access_time
));
340 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.write_time
));
341 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx
, finfo
->all_info
.out
.change_time
));
342 d_printf("\tattrib: 0x%x\n", finfo
->all_info
.out
.attrib
);
343 d_printf("\talloc_size: %llu\n", (long long)finfo
->all_info
.out
.alloc_size
);
344 d_printf("\tsize: %llu\n", (long long)finfo
->all_info
.out
.size
);
345 d_printf("\tnlink: %u\n", finfo
->all_info
.out
.nlink
);
346 d_printf("\tdelete_pending: %u\n", finfo
->all_info
.out
.delete_pending
);
347 d_printf("\tdirectory: %u\n", finfo
->all_info
.out
.directory
);
348 d_printf("\tea_size: %u\n", finfo
->all_info
.out
.ea_size
);
349 d_printf("\tfname: '%s'\n", finfo
->all_info
.out
.fname
.s
);
353 dump file infor by name
355 void torture_all_info(struct smbcli_tree
*tree
, const char *fname
)
357 TALLOC_CTX
*mem_ctx
= talloc_named(tree
, 0, "%s", fname
);
358 union smb_fileinfo finfo
;
361 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
362 finfo
.generic
.in
.file
.path
= fname
;
363 status
= smb_raw_pathinfo(tree
, mem_ctx
, &finfo
);
364 if (!NT_STATUS_IS_OK(status
)) {
365 d_printf("%s - %s\n", fname
, nt_errstr(status
));
369 d_printf("%s:\n", fname
);
370 dump_all_info(mem_ctx
, &finfo
);
371 talloc_free(mem_ctx
);
376 set a attribute on a file
378 bool torture_set_file_attribute(struct smbcli_tree
*tree
, const char *fname
, uint16_t attrib
)
380 union smb_setfileinfo sfinfo
;
383 ZERO_STRUCT(sfinfo
.basic_info
.in
);
384 sfinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
385 sfinfo
.basic_info
.in
.file
.path
= fname
;
386 sfinfo
.basic_info
.in
.attrib
= attrib
;
387 status
= smb_raw_setpathinfo(tree
, &sfinfo
);
388 return NT_STATUS_IS_OK(status
);
393 set a file descriptor as sparse
395 NTSTATUS
torture_set_sparse(struct smbcli_tree
*tree
, int fnum
)
401 mem_ctx
= talloc_named_const(tree
, 0, "torture_set_sparse");
403 return NT_STATUS_NO_MEMORY
;
406 nt
.ntioctl
.level
= RAW_IOCTL_NTIOCTL
;
407 nt
.ntioctl
.in
.function
= FSCTL_SET_SPARSE
;
408 nt
.ntioctl
.in
.file
.fnum
= fnum
;
409 nt
.ntioctl
.in
.fsctl
= true;
410 nt
.ntioctl
.in
.filter
= 0;
411 nt
.ntioctl
.in
.max_data
= 0;
412 nt
.ntioctl
.in
.blob
= data_blob(NULL
, 0);
414 status
= smb_raw_ioctl(tree
, mem_ctx
, &nt
);
416 talloc_free(mem_ctx
);
422 check that an EA has the right value
424 NTSTATUS
torture_check_ea(struct smbcli_state
*cli
,
425 const char *fname
, const char *eaname
, const char *value
)
427 union smb_fileinfo info
;
430 TALLOC_CTX
*mem_ctx
= talloc_new(cli
);
432 info
.ea_list
.level
= RAW_FILEINFO_EA_LIST
;
433 info
.ea_list
.in
.file
.path
= fname
;
434 info
.ea_list
.in
.num_names
= 1;
435 info
.ea_list
.in
.ea_names
= &ea
;
439 status
= smb_raw_pathinfo(cli
->tree
, mem_ctx
, &info
);
440 if (!NT_STATUS_IS_OK(status
)) {
441 talloc_free(mem_ctx
);
445 if (info
.ea_list
.out
.num_eas
!= 1) {
446 printf("Expected 1 ea in ea_list\n");
447 talloc_free(mem_ctx
);
448 return NT_STATUS_EA_CORRUPT_ERROR
;
451 if (strcasecmp_m(eaname
, info
.ea_list
.out
.eas
[0].name
.s
) != 0) {
452 printf("Expected ea '%s' not '%s' in ea_list\n",
453 eaname
, info
.ea_list
.out
.eas
[0].name
.s
);
454 talloc_free(mem_ctx
);
455 return NT_STATUS_EA_CORRUPT_ERROR
;
459 if (info
.ea_list
.out
.eas
[0].value
.length
!= 0) {
460 printf("Expected zero length ea for %s\n", eaname
);
461 talloc_free(mem_ctx
);
462 return NT_STATUS_EA_CORRUPT_ERROR
;
464 talloc_free(mem_ctx
);
468 if (strlen(value
) == info
.ea_list
.out
.eas
[0].value
.length
&&
469 memcmp(value
, info
.ea_list
.out
.eas
[0].value
.data
,
470 info
.ea_list
.out
.eas
[0].value
.length
) == 0) {
471 talloc_free(mem_ctx
);
475 printf("Expected value '%s' not '%*.*s' for ea %s\n",
477 (int)info
.ea_list
.out
.eas
[0].value
.length
,
478 (int)info
.ea_list
.out
.eas
[0].value
.length
,
479 info
.ea_list
.out
.eas
[0].value
.data
,
482 talloc_free(mem_ctx
);
484 return NT_STATUS_EA_CORRUPT_ERROR
;
487 _PUBLIC_
bool torture_open_connection_share(TALLOC_CTX
*mem_ctx
,
488 struct smbcli_state
**c
,
489 struct torture_context
*tctx
,
490 const char *hostname
,
491 const char *sharename
,
492 struct tevent_context
*ev
)
496 struct smbcli_options options
;
497 struct smbcli_session_options session_options
;
499 lp_smbcli_options(tctx
->lp_ctx
, &options
);
500 lp_smbcli_session_options(tctx
->lp_ctx
, &session_options
);
502 options
.use_oplocks
= torture_setting_bool(tctx
, "use_oplocks", true);
503 options
.use_level2_oplocks
= torture_setting_bool(tctx
, "use_level2_oplocks", true);
505 status
= smbcli_full_connection(mem_ctx
, c
, hostname
,
506 lp_smb_ports(tctx
->lp_ctx
),
508 lp_socket_options(tctx
->lp_ctx
),
510 lp_resolve_context(tctx
->lp_ctx
),
511 ev
, &options
, &session_options
,
512 lp_iconv_convenience(tctx
->lp_ctx
),
513 lp_gensec_settings(tctx
, tctx
->lp_ctx
));
514 if (!NT_STATUS_IS_OK(status
)) {
515 printf("Failed to open connection - %s\n", nt_errstr(status
));
522 _PUBLIC_
bool torture_get_conn_index(int conn_index
,
524 struct torture_context
*tctx
,
525 char **host
, char **share
)
527 char **unc_list
= NULL
;
528 int num_unc_names
= 0;
531 (*host
) = talloc_strdup(mem_ctx
, torture_setting_string(tctx
, "host", NULL
));
532 (*share
) = talloc_strdup(mem_ctx
, torture_setting_string(tctx
, "share", NULL
));
534 p
= torture_setting_string(tctx
, "unclist", NULL
);
539 unc_list
= file_lines_load(p
, &num_unc_names
, 0, NULL
);
540 if (!unc_list
|| num_unc_names
<= 0) {
541 DEBUG(0,("Failed to load unc names list from '%s'\n", p
));
545 if (!smbcli_parse_unc(unc_list
[conn_index
% num_unc_names
],
546 mem_ctx
, host
, share
)) {
547 DEBUG(0, ("Failed to parse UNC name %s\n",
548 unc_list
[conn_index
% num_unc_names
]));
552 talloc_free(unc_list
);
558 _PUBLIC_
bool torture_open_connection_ev(struct smbcli_state
**c
,
560 struct torture_context
*tctx
,
561 struct tevent_context
*ev
)
566 if (!torture_get_conn_index(conn_index
, ev
, tctx
, &host
, &share
)) {
570 ret
= torture_open_connection_share(NULL
, c
, tctx
, host
, share
, ev
);
577 _PUBLIC_
bool torture_open_connection(struct smbcli_state
**c
, struct torture_context
*tctx
, int conn_index
)
579 return torture_open_connection_ev(c
, conn_index
, tctx
, tctx
->ev
);
584 _PUBLIC_
bool torture_close_connection(struct smbcli_state
*c
)
588 if (NT_STATUS_IS_ERR(smbcli_tdis(c
))) {
589 printf("tdis failed (%s)\n", smbcli_errstr(c
->tree
));
597 /* check if the server produced the expected error code */
598 _PUBLIC_
bool check_error(const char *location
, struct smbcli_state
*c
,
599 uint8_t eclass
, uint32_t ecode
, NTSTATUS nterr
)
603 status
= smbcli_nt_error(c
->tree
);
604 if (NT_STATUS_IS_DOS(status
)) {
606 classnum
= NT_STATUS_DOS_CLASS(status
);
607 num
= NT_STATUS_DOS_CODE(status
);
608 if (eclass
!= classnum
|| ecode
!= num
) {
609 printf("unexpected error code %s\n", nt_errstr(status
));
610 printf(" expected %s or %s (at %s)\n",
611 nt_errstr(NT_STATUS_DOS(eclass
, ecode
)),
612 nt_errstr(nterr
), location
);
616 if (!NT_STATUS_EQUAL(nterr
, status
)) {
617 printf("unexpected error code %s\n", nt_errstr(status
));
618 printf(" expected %s (at %s)\n", nt_errstr(nterr
), location
);
626 static struct smbcli_state
*current_cli
;
627 static int procnum
; /* records process count number when forking */
629 static void sigcont(int sig
)
633 double torture_create_procs(struct torture_context
*tctx
,
634 bool (*fn
)(struct torture_context
*, struct smbcli_state
*, int), bool *result
)
637 volatile pid_t
*child_status
;
638 volatile bool *child_status_out
;
641 int torture_nprocs
= torture_setting_int(tctx
, "nprocs", 4);
642 double start_time_limit
= 10 + (torture_nprocs
* 1.5);
649 signal(SIGCONT
, sigcont
);
651 child_status
= (volatile pid_t
*)shm_setup(sizeof(pid_t
)*torture_nprocs
);
653 printf("Failed to setup shared memory\n");
657 child_status_out
= (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs
);
658 if (!child_status_out
) {
659 printf("Failed to setup result status shared memory\n");
663 for (i
= 0; i
< torture_nprocs
; i
++) {
665 child_status_out
[i
] = true;
668 tv
= timeval_current();
670 for (i
=0;i
<torture_nprocs
;i
++) {
675 pid_t mypid
= getpid();
676 srandom(((int)mypid
) ^ ((int)time(NULL
)));
678 if (asprintf(&myname
, "CLIENT%d", i
) == -1) {
679 printf("asprintf failed\n");
682 lp_set_cmdline(tctx
->lp_ctx
, "netbios name", myname
);
687 if (torture_open_connection(¤t_cli
, tctx
, i
)) {
691 printf("pid %d failed to start\n", (int)getpid());
697 child_status
[i
] = getpid();
701 if (child_status
[i
]) {
702 printf("Child %d failed to start!\n", i
);
703 child_status_out
[i
] = 1;
707 child_status_out
[i
] = fn(tctx
, current_cli
, i
);
714 for (i
=0;i
<torture_nprocs
;i
++) {
715 if (child_status
[i
]) synccount
++;
717 if (synccount
== torture_nprocs
) break;
719 } while (timeval_elapsed(&tv
) < start_time_limit
);
721 if (synccount
!= torture_nprocs
) {
722 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs
, synccount
);
724 return timeval_elapsed(&tv
);
727 printf("Starting %d clients\n", torture_nprocs
);
729 /* start the client load */
730 tv
= timeval_current();
731 for (i
=0;i
<torture_nprocs
;i
++) {
735 printf("%d clients started\n", torture_nprocs
);
739 for (i
=0;i
<torture_nprocs
;i
++) {
741 while ((ret
=waitpid(0, &status
, 0)) == -1 && errno
== EINTR
) /* noop */ ;
742 if (ret
== -1 || WEXITSTATUS(status
) != 0) {
749 for (i
=0;i
<torture_nprocs
;i
++) {
750 if (!child_status_out
[i
]) {
754 return timeval_elapsed(&tv
);
757 static bool wrap_smb_multi_test(struct torture_context
*torture
,
758 struct torture_tcase
*tcase
,
759 struct torture_test
*test
)
761 bool (*fn
)(struct torture_context
*, struct smbcli_state
*, int ) = test
->fn
;
764 torture_create_procs(torture
, fn
, &result
);
769 _PUBLIC_
struct torture_test
*torture_suite_add_smb_multi_test(
770 struct torture_suite
*suite
,
772 bool (*run
) (struct torture_context
*,
773 struct smbcli_state
*,
776 struct torture_test
*test
;
777 struct torture_tcase
*tcase
;
779 tcase
= torture_suite_add_tcase(suite
, name
);
781 test
= talloc(tcase
, struct torture_test
);
783 test
->name
= talloc_strdup(test
, name
);
784 test
->description
= NULL
;
785 test
->run
= wrap_smb_multi_test
;
787 test
->dangerous
= false;
789 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
795 static bool wrap_simple_2smb_test(struct torture_context
*torture_ctx
,
796 struct torture_tcase
*tcase
,
797 struct torture_test
*test
)
799 bool (*fn
) (struct torture_context
*, struct smbcli_state
*,
800 struct smbcli_state
*);
803 struct smbcli_state
*cli1
, *cli2
;
805 if (!torture_open_connection(&cli1
, torture_ctx
, 0) ||
806 !torture_open_connection(&cli2
, torture_ctx
, 1))
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
, struct torture_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
;
856 if (!torture_open_connection(&cli1
, torture_ctx
, 0))
861 ret
= fn(torture_ctx
, cli1
);
868 _PUBLIC_
struct torture_test
*torture_suite_add_1smb_test(
869 struct torture_suite
*suite
,
871 bool (*run
) (struct torture_context
*, struct smbcli_state
*))
873 struct torture_test
*test
;
874 struct torture_tcase
*tcase
;
876 tcase
= torture_suite_add_tcase(suite
, name
);
878 test
= talloc(tcase
, struct torture_test
);
880 test
->name
= talloc_strdup(test
, name
);
881 test
->description
= NULL
;
882 test
->run
= wrap_simple_1smb_test
;
884 test
->dangerous
= false;
886 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
892 NTSTATUS
torture_second_tcon(TALLOC_CTX
*mem_ctx
,
893 struct smbcli_session
*session
,
894 const char *sharename
,
895 struct smbcli_tree
**res
)
898 struct smbcli_tree
*result
;
902 if ((tmp_ctx
= talloc_new(mem_ctx
)) == NULL
) {
903 return NT_STATUS_NO_MEMORY
;
906 result
= smbcli_tree_init(session
, tmp_ctx
, false);
907 if (result
== NULL
) {
908 talloc_free(tmp_ctx
);
909 return NT_STATUS_NO_MEMORY
;
912 tcon
.generic
.level
= RAW_TCON_TCONX
;
913 tcon
.tconx
.in
.flags
= 0;
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
;
927 *res
= talloc_steal(mem_ctx
, result
);
928 talloc_free(tmp_ctx
);
933 a wrapper around smblsa_sid_check_privilege, that tries to take
934 account of the fact that the lsa privileges calls don't expand
935 group memberships, using an explicit check for administrator. There
936 must be a better way ...
938 NTSTATUS
torture_check_privilege(struct smbcli_state
*cli
,
940 const char *privilege
)
943 TALLOC_CTX
*tmp_ctx
= talloc_new(cli
);
947 sid
= dom_sid_parse_talloc(tmp_ctx
, sid_str
);
949 talloc_free(tmp_ctx
);
950 return NT_STATUS_INVALID_SID
;
953 status
= dom_sid_split_rid(tmp_ctx
, sid
, NULL
, &rid
);
954 NT_STATUS_NOT_OK_RETURN_AND_FREE(status
, tmp_ctx
);
956 if (rid
== DOMAIN_RID_ADMINISTRATOR
) {
957 /* assume the administrator has them all */
961 talloc_free(tmp_ctx
);
963 return smblsa_sid_check_privilege(cli
, sid_str
, privilege
);