/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- torture_setup_dir
- create_directory_handle
- create_complex_file
- create_complex_dir
- shm_setup
- wire_bad_flags
- dump_all_info
- torture_all_info
- torture_set_file_attribute
- torture_set_sparse
- torture_check_ea
- torture_open_connection_share
- torture_get_conn_index
- torture_open_connection_ev
- torture_open_connection
- torture_close_connection
- check_error
- sigcont
- torture_create_procs
- wrap_smb_multi_test
- torture_suite_add_smb_multi_test
- wrap_simple_2smb_test
- torture_suite_add_2smb_test
- wrap_simple_1smb_test
- torture_suite_add_1smb_test
- torture_second_tcon
1 /*
2 Unix SMB/CIFS implementation.
3 SMB torture tester utility functions
4 Copyright (C) Andrew Tridgell 2003
5 Copyright (C) Jelmer Vernooij 2006
6
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.
11
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.
16
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/>.
19 */
20
21 #include "includes.h"
22 #include "lib/cmdline/popt_common.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "libcli/raw/ioctl.h"
26 #include "libcli/libcli.h"
27 #include "system/filesys.h"
28 #include "system/shmem.h"
29 #include "system/wait.h"
30 #include "system/time.h"
31 #include "torture/torture.h"
32 #include "../lib/util/dlinklist.h"
33 #include "auth/credentials/credentials.h"
34 #include "libcli/resolve/resolve.h"
35 #include "param/param.h"
36
37
38 /**
39 setup a directory ready for a test
40 */
41 _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
/* [<][>][^][v][top][bottom][index][help] */
42 {
43 smb_raw_exit(cli->session);
44 if (smbcli_deltree(cli->tree, dname) == -1 ||
45 NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
46 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
47 return false;
48 }
49 return true;
50 }
51
52 /*
53 create a directory, returning a handle to it
54 */
55 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
/* [<][>][^][v][top][bottom][index][help] */
56 {
57 NTSTATUS status;
58 union smb_open io;
59 TALLOC_CTX *mem_ctx;
60
61 mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
62
63 io.generic.level = RAW_OPEN_NTCREATEX;
64 io.ntcreatex.in.root_fid = 0;
65 io.ntcreatex.in.flags = 0;
66 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
67 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
68 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
69 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
70 io.ntcreatex.in.alloc_size = 0;
71 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
72 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
73 io.ntcreatex.in.security_flags = 0;
74 io.ntcreatex.in.fname = dname;
75
76 status = smb_raw_open(tree, mem_ctx, &io);
77 talloc_free(mem_ctx);
78
79 if (NT_STATUS_IS_OK(status)) {
80 *fnum = io.ntcreatex.out.file.fnum;
81 }
82
83 return status;
84 }
85
86
87 /**
88 sometimes we need a fairly complex file to work with, so we can test
89 all possible attributes.
90 */
91 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
/* [<][>][^][v][top][bottom][index][help] */
92 {
93 int fnum;
94 char buf[7] = "abc";
95 union smb_setfileinfo setfile;
96 union smb_fileinfo fileinfo;
97 time_t t = (time(NULL) & ~1);
98 NTSTATUS status;
99
100 smbcli_unlink(cli->tree, fname);
101 fnum = smbcli_nt_create_full(cli->tree, fname, 0,
102 SEC_RIGHTS_FILE_ALL,
103 FILE_ATTRIBUTE_NORMAL,
104 NTCREATEX_SHARE_ACCESS_DELETE|
105 NTCREATEX_SHARE_ACCESS_READ|
106 NTCREATEX_SHARE_ACCESS_WRITE,
107 NTCREATEX_DISP_OVERWRITE_IF,
108 0, 0);
109 if (fnum == -1) return -1;
110
111 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
112
113 if (strchr(fname, ':') == NULL) {
114 /* setup some EAs */
115 setfile.generic.level = RAW_SFILEINFO_EA_SET;
116 setfile.generic.in.file.fnum = fnum;
117 setfile.ea_set.in.num_eas = 2;
118 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
119 setfile.ea_set.in.eas[0].flags = 0;
120 setfile.ea_set.in.eas[0].name.s = "EAONE";
121 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
122 setfile.ea_set.in.eas[1].flags = 0;
123 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
124 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
125 status = smb_raw_setfileinfo(cli->tree, &setfile);
126 if (!NT_STATUS_IS_OK(status)) {
127 printf("Failed to setup EAs\n");
128 }
129 }
130
131 /* make sure all the timestamps aren't the same, and are also
132 in different DST zones*/
133 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
134 setfile.generic.in.file.fnum = fnum;
135
136 setfile.setattre.in.create_time = t + 9*30*24*60*60;
137 setfile.setattre.in.access_time = t + 6*30*24*60*60;
138 setfile.setattre.in.write_time = t + 3*30*24*60*60;
139
140 status = smb_raw_setfileinfo(cli->tree, &setfile);
141 if (!NT_STATUS_IS_OK(status)) {
142 printf("Failed to setup file times - %s\n", nt_errstr(status));
143 }
144
145 /* make sure all the timestamps aren't the same */
146 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
147 fileinfo.generic.in.file.fnum = fnum;
148
149 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
150 if (!NT_STATUS_IS_OK(status)) {
151 printf("Failed to query file times - %s\n", nt_errstr(status));
152 }
153
154 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
155 printf("create_time not setup correctly\n");
156 }
157 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
158 printf("access_time not setup correctly\n");
159 }
160 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
161 printf("write_time not setup correctly\n");
162 }
163
164 return fnum;
165 }
166
167
168 /*
169 sometimes we need a fairly complex directory to work with, so we can test
170 all possible attributes.
171 */
172 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
/* [<][>][^][v][top][bottom][index][help] */
173 {
174 int fnum;
175 union smb_setfileinfo setfile;
176 union smb_fileinfo fileinfo;
177 time_t t = (time(NULL) & ~1);
178 NTSTATUS status;
179
180 smbcli_deltree(cli->tree, dname);
181 fnum = smbcli_nt_create_full(cli->tree, dname, 0,
182 SEC_RIGHTS_DIR_ALL,
183 FILE_ATTRIBUTE_DIRECTORY,
184 NTCREATEX_SHARE_ACCESS_READ|
185 NTCREATEX_SHARE_ACCESS_WRITE,
186 NTCREATEX_DISP_OPEN_IF,
187 NTCREATEX_OPTIONS_DIRECTORY, 0);
188 if (fnum == -1) return -1;
189
190 if (strchr(dname, ':') == NULL) {
191 /* setup some EAs */
192 setfile.generic.level = RAW_SFILEINFO_EA_SET;
193 setfile.generic.in.file.fnum = fnum;
194 setfile.ea_set.in.num_eas = 2;
195 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
196 setfile.ea_set.in.eas[0].flags = 0;
197 setfile.ea_set.in.eas[0].name.s = "EAONE";
198 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
199 setfile.ea_set.in.eas[1].flags = 0;
200 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
201 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
202 status = smb_raw_setfileinfo(cli->tree, &setfile);
203 if (!NT_STATUS_IS_OK(status)) {
204 printf("Failed to setup EAs\n");
205 }
206 }
207
208 /* make sure all the timestamps aren't the same, and are also
209 in different DST zones*/
210 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
211 setfile.generic.in.file.fnum = fnum;
212
213 setfile.setattre.in.create_time = t + 9*30*24*60*60;
214 setfile.setattre.in.access_time = t + 6*30*24*60*60;
215 setfile.setattre.in.write_time = t + 3*30*24*60*60;
216
217 status = smb_raw_setfileinfo(cli->tree, &setfile);
218 if (!NT_STATUS_IS_OK(status)) {
219 printf("Failed to setup file times - %s\n", nt_errstr(status));
220 }
221
222 /* make sure all the timestamps aren't the same */
223 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
224 fileinfo.generic.in.file.fnum = fnum;
225
226 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
227 if (!NT_STATUS_IS_OK(status)) {
228 printf("Failed to query file times - %s\n", nt_errstr(status));
229 }
230
231 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
232 printf("create_time not setup correctly\n");
233 }
234 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
235 printf("access_time not setup correctly\n");
236 }
237 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
238 printf("write_time not setup correctly\n");
239 }
240
241 return fnum;
242 }
243
244
245
246 /* return a pointer to a anonymous shared memory segment of size "size"
247 which will persist across fork() but will disappear when all processes
248 exit
249
250 The memory is not zeroed
251
252 This function uses system5 shared memory. It takes advantage of a property
253 that the memory is not destroyed if it is attached when the id is removed
254 */
255 void *shm_setup(int size)
/* [<][>][^][v][top][bottom][index][help] */
256 {
257 int shmid;
258 void *ret;
259
260 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
261 if (shmid == -1) {
262 printf("can't get shared memory\n");
263 exit(1);
264 }
265 ret = (void *)shmat(shmid, 0, 0);
266 if (!ret || ret == (void *)-1) {
267 printf("can't attach to shared memory\n");
268 return NULL;
269 }
270 /* the following releases the ipc, but note that this process
271 and all its children will still have access to the memory, its
272 just that the shmid is no longer valid for other shm calls. This
273 means we don't leave behind lots of shm segments after we exit
274
275 See Stevens "advanced programming in unix env" for details
276 */
277 shmctl(shmid, IPC_RMID, 0);
278
279 return ret;
280 }
281
282
283 /**
284 check that a wire string matches the flags specified
285 not 100% accurate, but close enough for testing
286 */
287 bool wire_bad_flags(struct smb_wire_string *str, int flags,
/* [<][>][^][v][top][bottom][index][help] */
288 struct smbcli_transport *transport)
289 {
290 bool server_unicode;
291 int len;
292 if (!str || !str->s) return true;
293 len = strlen(str->s);
294 if (flags & STR_TERMINATE) len++;
295
296 server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
297 if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
298 server_unicode = false;
299 }
300
301 if ((flags & STR_UNICODE) || server_unicode) {
302 len *= 2;
303 } else if (flags & STR_TERMINATE_ASCII) {
304 len++;
305 }
306 if (str->private_length != len) {
307 printf("Expected wire_length %d but got %d for '%s'\n",
308 len, str->private_length, str->s);
309 return true;
310 }
311 return false;
312 }
313
314 /*
315 dump a all_info QFILEINFO structure
316 */
317 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
/* [<][>][^][v][top][bottom][index][help] */
318 {
319 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
320 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
321 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
322 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
323 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
324 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
325 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
326 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
327 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
328 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
329 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
330 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
331 }
332
333 /*
334 dump file infor by name
335 */
336 void torture_all_info(struct smbcli_tree *tree, const char *fname)
/* [<][>][^][v][top][bottom][index][help] */
337 {
338 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
339 union smb_fileinfo finfo;
340 NTSTATUS status;
341
342 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
343 finfo.generic.in.file.path = fname;
344 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
345 if (!NT_STATUS_IS_OK(status)) {
346 d_printf("%s - %s\n", fname, nt_errstr(status));
347 return;
348 }
349
350 d_printf("%s:\n", fname);
351 dump_all_info(mem_ctx, &finfo);
352 talloc_free(mem_ctx);
353 }
354
355
356 /*
357 set a attribute on a file
358 */
359 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
/* [<][>][^][v][top][bottom][index][help] */
360 {
361 union smb_setfileinfo sfinfo;
362 NTSTATUS status;
363
364 ZERO_STRUCT(sfinfo.basic_info.in);
365 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
366 sfinfo.basic_info.in.file.path = fname;
367 sfinfo.basic_info.in.attrib = attrib;
368 status = smb_raw_setpathinfo(tree, &sfinfo);
369 return NT_STATUS_IS_OK(status);
370 }
371
372
373 /*
374 set a file descriptor as sparse
375 */
376 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
/* [<][>][^][v][top][bottom][index][help] */
377 {
378 union smb_ioctl nt;
379 NTSTATUS status;
380 TALLOC_CTX *mem_ctx;
381
382 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
383 if (!mem_ctx) {
384 return NT_STATUS_NO_MEMORY;
385 }
386
387 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
388 nt.ntioctl.in.function = FSCTL_SET_SPARSE;
389 nt.ntioctl.in.file.fnum = fnum;
390 nt.ntioctl.in.fsctl = true;
391 nt.ntioctl.in.filter = 0;
392 nt.ntioctl.in.max_data = 0;
393 nt.ntioctl.in.blob = data_blob(NULL, 0);
394
395 status = smb_raw_ioctl(tree, mem_ctx, &nt);
396
397 talloc_free(mem_ctx);
398
399 return status;
400 }
401
402 /*
403 check that an EA has the right value
404 */
405 NTSTATUS torture_check_ea(struct smbcli_state *cli,
/* [<][>][^][v][top][bottom][index][help] */
406 const char *fname, const char *eaname, const char *value)
407 {
408 union smb_fileinfo info;
409 NTSTATUS status;
410 struct ea_name ea;
411 TALLOC_CTX *mem_ctx = talloc_new(cli);
412
413 info.ea_list.level = RAW_FILEINFO_EA_LIST;
414 info.ea_list.in.file.path = fname;
415 info.ea_list.in.num_names = 1;
416 info.ea_list.in.ea_names = &ea;
417
418 ea.name.s = eaname;
419
420 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
421 if (!NT_STATUS_IS_OK(status)) {
422 talloc_free(mem_ctx);
423 return status;
424 }
425
426 if (info.ea_list.out.num_eas != 1) {
427 printf("Expected 1 ea in ea_list\n");
428 talloc_free(mem_ctx);
429 return NT_STATUS_EA_CORRUPT_ERROR;
430 }
431
432 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
433 printf("Expected ea '%s' not '%s' in ea_list\n",
434 eaname, info.ea_list.out.eas[0].name.s);
435 talloc_free(mem_ctx);
436 return NT_STATUS_EA_CORRUPT_ERROR;
437 }
438
439 if (value == NULL) {
440 if (info.ea_list.out.eas[0].value.length != 0) {
441 printf("Expected zero length ea for %s\n", eaname);
442 talloc_free(mem_ctx);
443 return NT_STATUS_EA_CORRUPT_ERROR;
444 }
445 talloc_free(mem_ctx);
446 return NT_STATUS_OK;
447 }
448
449 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
450 memcmp(value, info.ea_list.out.eas[0].value.data,
451 info.ea_list.out.eas[0].value.length) == 0) {
452 talloc_free(mem_ctx);
453 return NT_STATUS_OK;
454 }
455
456 printf("Expected value '%s' not '%*.*s' for ea %s\n",
457 value,
458 (int)info.ea_list.out.eas[0].value.length,
459 (int)info.ea_list.out.eas[0].value.length,
460 info.ea_list.out.eas[0].value.data,
461 eaname);
462
463 talloc_free(mem_ctx);
464
465 return NT_STATUS_EA_CORRUPT_ERROR;
466 }
467
468 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
469 struct smbcli_state **c,
470 struct torture_context *tctx,
471 const char *hostname,
472 const char *sharename,
473 struct tevent_context *ev)
474 {
475 NTSTATUS status;
476
477 struct smbcli_options options;
478 struct smbcli_session_options session_options;
479
480 lp_smbcli_options(tctx->lp_ctx, &options);
481 lp_smbcli_session_options(tctx->lp_ctx, &session_options);
482
483 options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
484 options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
485
486 status = smbcli_full_connection(mem_ctx, c, hostname,
487 lp_smb_ports(tctx->lp_ctx),
488 sharename, NULL,
489 lp_socket_options(tctx->lp_ctx),
490 cmdline_credentials,
491 lp_resolve_context(tctx->lp_ctx),
492 ev, &options, &session_options,
493 lp_iconv_convenience(tctx->lp_ctx),
494 lp_gensec_settings(tctx, tctx->lp_ctx));
495 if (!NT_STATUS_IS_OK(status)) {
496 printf("Failed to open connection - %s\n", nt_errstr(status));
497 return false;
498 }
499
500 return true;
501 }
502
503 _PUBLIC_ bool torture_get_conn_index(int conn_index,
/* [<][>][^][v][top][bottom][index][help] */
504 TALLOC_CTX *mem_ctx,
505 struct torture_context *tctx,
506 char **host, char **share)
507 {
508 char **unc_list = NULL;
509 int num_unc_names = 0;
510 const char *p;
511
512 (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
513 (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
514
515 p = torture_setting_string(tctx, "unclist", NULL);
516 if (!p) {
517 return true;
518 }
519
520 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
521 if (!unc_list || num_unc_names <= 0) {
522 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
523 return false;
524 }
525
526 if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
527 mem_ctx, host, share)) {
528 DEBUG(0, ("Failed to parse UNC name %s\n",
529 unc_list[conn_index % num_unc_names]));
530 return false;
531 }
532
533 talloc_free(unc_list);
534 return true;
535 }
536
537
538
539 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
/* [<][>][^][v][top][bottom][index][help] */
540 int conn_index,
541 struct torture_context *tctx,
542 struct tevent_context *ev)
543 {
544 char *host, *share;
545 bool ret;
546
547 if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
548 return false;
549 }
550
551 ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
552 talloc_free(host);
553 talloc_free(share);
554
555 return ret;
556 }
557
558 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
/* [<][>][^][v][top][bottom][index][help] */
559 {
560 return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
561 }
562
563
564
565 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
/* [<][>][^][v][top][bottom][index][help] */
566 {
567 bool ret = true;
568 if (!c) return true;
569 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
570 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
571 ret = false;
572 }
573 talloc_free(c);
574 return ret;
575 }
576
577
578 /* check if the server produced the expected error code */
579 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
/* [<][>][^][v][top][bottom][index][help] */
580 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
581 {
582 NTSTATUS status;
583
584 status = smbcli_nt_error(c->tree);
585 if (NT_STATUS_IS_DOS(status)) {
586 int classnum, num;
587 classnum = NT_STATUS_DOS_CLASS(status);
588 num = NT_STATUS_DOS_CODE(status);
589 if (eclass != classnum || ecode != num) {
590 printf("unexpected error code %s\n", nt_errstr(status));
591 printf(" expected %s or %s (at %s)\n",
592 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
593 nt_errstr(nterr), location);
594 return false;
595 }
596 } else {
597 if (!NT_STATUS_EQUAL(nterr, status)) {
598 printf("unexpected error code %s\n", nt_errstr(status));
599 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
600 return false;
601 }
602 }
603
604 return true;
605 }
606
607 static struct smbcli_state *current_cli;
608 static int procnum; /* records process count number when forking */
609
610 static void sigcont(int sig)
/* [<][>][^][v][top][bottom][index][help] */
611 {
612 }
613
614 double torture_create_procs(struct torture_context *tctx,
/* [<][>][^][v][top][bottom][index][help] */
615 bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
616 {
617 int i, status;
618 volatile pid_t *child_status;
619 volatile bool *child_status_out;
620 int synccount;
621 int tries = 8;
622 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
623 double start_time_limit = 10 + (torture_nprocs * 1.5);
624 struct timeval tv;
625
626 *result = true;
627
628 synccount = 0;
629
630 signal(SIGCONT, sigcont);
631
632 child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
633 if (!child_status) {
634 printf("Failed to setup shared memory\n");
635 return -1;
636 }
637
638 child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
639 if (!child_status_out) {
640 printf("Failed to setup result status shared memory\n");
641 return -1;
642 }
643
644 for (i = 0; i < torture_nprocs; i++) {
645 child_status[i] = 0;
646 child_status_out[i] = true;
647 }
648
649 tv = timeval_current();
650
651 for (i=0;i<torture_nprocs;i++) {
652 procnum = i;
653 if (fork() == 0) {
654 char *myname;
655
656 pid_t mypid = getpid();
657 srandom(((int)mypid) ^ ((int)time(NULL)));
658
659 if (asprintf(&myname, "CLIENT%d", i) == -1) {
660 printf("asprintf failed\n");
661 return -1;
662 }
663 lp_set_cmdline(tctx->lp_ctx, "netbios name", myname);
664 free(myname);
665
666
667 while (1) {
668 if (torture_open_connection(¤t_cli, tctx, i)) {
669 break;
670 }
671 if (tries-- == 0) {
672 printf("pid %d failed to start\n", (int)getpid());
673 _exit(1);
674 }
675 msleep(100);
676 }
677
678 child_status[i] = getpid();
679
680 pause();
681
682 if (child_status[i]) {
683 printf("Child %d failed to start!\n", i);
684 child_status_out[i] = 1;
685 _exit(1);
686 }
687
688 child_status_out[i] = fn(tctx, current_cli, i);
689 _exit(0);
690 }
691 }
692
693 do {
694 synccount = 0;
695 for (i=0;i<torture_nprocs;i++) {
696 if (child_status[i]) synccount++;
697 }
698 if (synccount == torture_nprocs) break;
699 msleep(100);
700 } while (timeval_elapsed(&tv) < start_time_limit);
701
702 if (synccount != torture_nprocs) {
703 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
704 *result = false;
705 return timeval_elapsed(&tv);
706 }
707
708 printf("Starting %d clients\n", torture_nprocs);
709
710 /* start the client load */
711 tv = timeval_current();
712 for (i=0;i<torture_nprocs;i++) {
713 child_status[i] = 0;
714 }
715
716 printf("%d clients started\n", torture_nprocs);
717
718 kill(0, SIGCONT);
719
720 for (i=0;i<torture_nprocs;i++) {
721 int ret;
722 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
723 if (ret == -1 || WEXITSTATUS(status) != 0) {
724 *result = false;
725 }
726 }
727
728 printf("\n");
729
730 for (i=0;i<torture_nprocs;i++) {
731 if (!child_status_out[i]) {
732 *result = false;
733 }
734 }
735 return timeval_elapsed(&tv);
736 }
737
738 static bool wrap_smb_multi_test(struct torture_context *torture,
/* [<][>][^][v][top][bottom][index][help] */
739 struct torture_tcase *tcase,
740 struct torture_test *test)
741 {
742 bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
743 bool result;
744
745 torture_create_procs(torture, fn, &result);
746
747 return result;
748 }
749
750 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
/* [<][>][^][v][top][bottom][index][help] */
751 struct torture_suite *suite,
752 const char *name,
753 bool (*run) (struct torture_context *,
754 struct smbcli_state *,
755 int i))
756 {
757 struct torture_test *test;
758 struct torture_tcase *tcase;
759
760 tcase = torture_suite_add_tcase(suite, name);
761
762 test = talloc(tcase, struct torture_test);
763
764 test->name = talloc_strdup(test, name);
765 test->description = NULL;
766 test->run = wrap_smb_multi_test;
767 test->fn = run;
768 test->dangerous = false;
769
770 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
771
772 return test;
773
774 }
775
776 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
/* [<][>][^][v][top][bottom][index][help] */
777 struct torture_tcase *tcase,
778 struct torture_test *test)
779 {
780 bool (*fn) (struct torture_context *, struct smbcli_state *,
781 struct smbcli_state *);
782 bool ret;
783
784 struct smbcli_state *cli1, *cli2;
785
786 if (!torture_open_connection(&cli1, torture_ctx, 0) ||
787 !torture_open_connection(&cli2, torture_ctx, 1))
788 return false;
789
790 fn = test->fn;
791
792 ret = fn(torture_ctx, cli1, cli2);
793
794 talloc_free(cli1);
795 talloc_free(cli2);
796
797 return ret;
798 }
799
800
801
802 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
/* [<][>][^][v][top][bottom][index][help] */
803 struct torture_suite *suite,
804 const char *name,
805 bool (*run) (struct torture_context *,
806 struct smbcli_state *,
807 struct smbcli_state *))
808 {
809 struct torture_test *test;
810 struct torture_tcase *tcase;
811
812 tcase = torture_suite_add_tcase(suite, name);
813
814 test = talloc(tcase, struct torture_test);
815
816 test->name = talloc_strdup(test, name);
817 test->description = NULL;
818 test->run = wrap_simple_2smb_test;
819 test->fn = run;
820 test->dangerous = false;
821
822 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
823
824 return test;
825
826 }
827
828 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
/* [<][>][^][v][top][bottom][index][help] */
829 struct torture_tcase *tcase,
830 struct torture_test *test)
831 {
832 bool (*fn) (struct torture_context *, struct smbcli_state *);
833 bool ret;
834
835 struct smbcli_state *cli1;
836
837 if (!torture_open_connection(&cli1, torture_ctx, 0))
838 return false;
839
840 fn = test->fn;
841
842 ret = fn(torture_ctx, cli1);
843
844 talloc_free(cli1);
845
846 return ret;
847 }
848
849 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
/* [<][>][^][v][top][bottom][index][help] */
850 struct torture_suite *suite,
851 const char *name,
852 bool (*run) (struct torture_context *, struct smbcli_state *))
853 {
854 struct torture_test *test;
855 struct torture_tcase *tcase;
856
857 tcase = torture_suite_add_tcase(suite, name);
858
859 test = talloc(tcase, struct torture_test);
860
861 test->name = talloc_strdup(test, name);
862 test->description = NULL;
863 test->run = wrap_simple_1smb_test;
864 test->fn = run;
865 test->dangerous = false;
866
867 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
868
869 return test;
870 }
871
872
873 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
874 struct smbcli_session *session,
875 const char *sharename,
876 struct smbcli_tree **res)
877 {
878 union smb_tcon tcon;
879 struct smbcli_tree *result;
880 TALLOC_CTX *tmp_ctx;
881 NTSTATUS status;
882
883 if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
884 return NT_STATUS_NO_MEMORY;
885 }
886
887 result = smbcli_tree_init(session, tmp_ctx, false);
888 if (result == NULL) {
889 talloc_free(tmp_ctx);
890 return NT_STATUS_NO_MEMORY;
891 }
892
893 tcon.generic.level = RAW_TCON_TCONX;
894 tcon.tconx.in.flags = 0;
895
896 /* Ignore share mode security here */
897 tcon.tconx.in.password = data_blob(NULL, 0);
898 tcon.tconx.in.path = sharename;
899 tcon.tconx.in.device = "?????";
900
901 status = smb_raw_tcon(result, tmp_ctx, &tcon);
902 if (!NT_STATUS_IS_OK(status)) {
903 talloc_free(tmp_ctx);
904 return status;
905 }
906
907 result->tid = tcon.tconx.out.tid;
908 *res = talloc_steal(mem_ctx, result);
909 talloc_free(tmp_ctx);
910 return NT_STATUS_OK;
911 }