source: branches/samba-3.5.x/source4/torture/util_smb.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 16 years ago

Samba 3.5.0: Initial import

File size: 24.6 KB
Line 
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)
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*/
55NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
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)
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*/
172int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
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 */
255void *shm_setup(int size)
256{
257 int shmid;
258 void *ret;
259
260#ifdef __QNXNTO__
261 shmid = shm_open("private", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
262 if (shmid == -1) {
263 printf("can't get shared memory\n");
264 exit(1);
265 }
266 shm_unlink("private");
267 if (ftruncate(shmid, size) == -1) {
268 printf("can't set shared memory size\n");
269 exit(1);
270 }
271 ret = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0);
272 if (ret == MAP_FAILED) {
273 printf("can't map shared memory\n");
274 exit(1);
275 }
276#else
277 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
278 if (shmid == -1) {
279 printf("can't get shared memory\n");
280 exit(1);
281 }
282 ret = (void *)shmat(shmid, 0, 0);
283 if (!ret || ret == (void *)-1) {
284 printf("can't attach to shared memory\n");
285 return NULL;
286 }
287 /* the following releases the ipc, but note that this process
288 and all its children will still have access to the memory, its
289 just that the shmid is no longer valid for other shm calls. This
290 means we don't leave behind lots of shm segments after we exit
291
292 See Stevens "advanced programming in unix env" for details
293 */
294 shmctl(shmid, IPC_RMID, 0);
295#endif
296
297 return ret;
298}
299
300
301/**
302 check that a wire string matches the flags specified
303 not 100% accurate, but close enough for testing
304*/
305bool wire_bad_flags(struct smb_wire_string *str, int flags,
306 struct smbcli_transport *transport)
307{
308 bool server_unicode;
309 int len;
310 if (!str || !str->s) return true;
311 len = strlen(str->s);
312 if (flags & STR_TERMINATE) len++;
313
314 server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
315 if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
316 server_unicode = false;
317 }
318
319 if ((flags & STR_UNICODE) || server_unicode) {
320 len *= 2;
321 } else if (flags & STR_TERMINATE_ASCII) {
322 len++;
323 }
324 if (str->private_length != len) {
325 printf("Expected wire_length %d but got %d for '%s'\n",
326 len, str->private_length, str->s);
327 return true;
328 }
329 return false;
330}
331
332/*
333 dump a all_info QFILEINFO structure
334*/
335void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
336{
337 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
338 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
339 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
340 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
341 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
342 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
343 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
344 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
345 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
346 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
347 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
348 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
349}
350
351/*
352 dump file infor by name
353*/
354void torture_all_info(struct smbcli_tree *tree, const char *fname)
355{
356 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
357 union smb_fileinfo finfo;
358 NTSTATUS status;
359
360 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
361 finfo.generic.in.file.path = fname;
362 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
363 if (!NT_STATUS_IS_OK(status)) {
364 d_printf("%s - %s\n", fname, nt_errstr(status));
365 return;
366 }
367
368 d_printf("%s:\n", fname);
369 dump_all_info(mem_ctx, &finfo);
370 talloc_free(mem_ctx);
371}
372
373
374/*
375 set a attribute on a file
376*/
377bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
378{
379 union smb_setfileinfo sfinfo;
380 NTSTATUS status;
381
382 ZERO_STRUCT(sfinfo.basic_info.in);
383 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
384 sfinfo.basic_info.in.file.path = fname;
385 sfinfo.basic_info.in.attrib = attrib;
386 status = smb_raw_setpathinfo(tree, &sfinfo);
387 return NT_STATUS_IS_OK(status);
388}
389
390
391/*
392 set a file descriptor as sparse
393*/
394NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
395{
396 union smb_ioctl nt;
397 NTSTATUS status;
398 TALLOC_CTX *mem_ctx;
399
400 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
401 if (!mem_ctx) {
402 return NT_STATUS_NO_MEMORY;
403 }
404
405 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
406 nt.ntioctl.in.function = FSCTL_SET_SPARSE;
407 nt.ntioctl.in.file.fnum = fnum;
408 nt.ntioctl.in.fsctl = true;
409 nt.ntioctl.in.filter = 0;
410 nt.ntioctl.in.max_data = 0;
411 nt.ntioctl.in.blob = data_blob(NULL, 0);
412
413 status = smb_raw_ioctl(tree, mem_ctx, &nt);
414
415 talloc_free(mem_ctx);
416
417 return status;
418}
419
420/*
421 check that an EA has the right value
422*/
423NTSTATUS torture_check_ea(struct smbcli_state *cli,
424 const char *fname, const char *eaname, const char *value)
425{
426 union smb_fileinfo info;
427 NTSTATUS status;
428 struct ea_name ea;
429 TALLOC_CTX *mem_ctx = talloc_new(cli);
430
431 info.ea_list.level = RAW_FILEINFO_EA_LIST;
432 info.ea_list.in.file.path = fname;
433 info.ea_list.in.num_names = 1;
434 info.ea_list.in.ea_names = &ea;
435
436 ea.name.s = eaname;
437
438 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
439 if (!NT_STATUS_IS_OK(status)) {
440 talloc_free(mem_ctx);
441 return status;
442 }
443
444 if (info.ea_list.out.num_eas != 1) {
445 printf("Expected 1 ea in ea_list\n");
446 talloc_free(mem_ctx);
447 return NT_STATUS_EA_CORRUPT_ERROR;
448 }
449
450 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
451 printf("Expected ea '%s' not '%s' in ea_list\n",
452 eaname, info.ea_list.out.eas[0].name.s);
453 talloc_free(mem_ctx);
454 return NT_STATUS_EA_CORRUPT_ERROR;
455 }
456
457 if (value == NULL) {
458 if (info.ea_list.out.eas[0].value.length != 0) {
459 printf("Expected zero length ea for %s\n", eaname);
460 talloc_free(mem_ctx);
461 return NT_STATUS_EA_CORRUPT_ERROR;
462 }
463 talloc_free(mem_ctx);
464 return NT_STATUS_OK;
465 }
466
467 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
468 memcmp(value, info.ea_list.out.eas[0].value.data,
469 info.ea_list.out.eas[0].value.length) == 0) {
470 talloc_free(mem_ctx);
471 return NT_STATUS_OK;
472 }
473
474 printf("Expected value '%s' not '%*.*s' for ea %s\n",
475 value,
476 (int)info.ea_list.out.eas[0].value.length,
477 (int)info.ea_list.out.eas[0].value.length,
478 info.ea_list.out.eas[0].value.data,
479 eaname);
480
481 talloc_free(mem_ctx);
482
483 return NT_STATUS_EA_CORRUPT_ERROR;
484}
485
486_PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
487 struct smbcli_state **c,
488 struct torture_context *tctx,
489 const char *hostname,
490 const char *sharename,
491 struct tevent_context *ev)
492{
493 NTSTATUS status;
494
495 struct smbcli_options options;
496 struct smbcli_session_options session_options;
497
498 lp_smbcli_options(tctx->lp_ctx, &options);
499 lp_smbcli_session_options(tctx->lp_ctx, &session_options);
500
501 options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
502 options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
503
504 status = smbcli_full_connection(mem_ctx, c, hostname,
505 lp_smb_ports(tctx->lp_ctx),
506 sharename, NULL,
507 lp_socket_options(tctx->lp_ctx),
508 cmdline_credentials,
509 lp_resolve_context(tctx->lp_ctx),
510 ev, &options, &session_options,
511 lp_iconv_convenience(tctx->lp_ctx),
512 lp_gensec_settings(tctx, tctx->lp_ctx));
513 if (!NT_STATUS_IS_OK(status)) {
514 printf("Failed to open connection - %s\n", nt_errstr(status));
515 return false;
516 }
517
518 return true;
519}
520
521_PUBLIC_ bool torture_get_conn_index(int conn_index,
522 TALLOC_CTX *mem_ctx,
523 struct torture_context *tctx,
524 char **host, char **share)
525{
526 char **unc_list = NULL;
527 int num_unc_names = 0;
528 const char *p;
529
530 (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
531 (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
532
533 p = torture_setting_string(tctx, "unclist", NULL);
534 if (!p) {
535 return true;
536 }
537
538 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
539 if (!unc_list || num_unc_names <= 0) {
540 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
541 return false;
542 }
543
544 if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
545 mem_ctx, host, share)) {
546 DEBUG(0, ("Failed to parse UNC name %s\n",
547 unc_list[conn_index % num_unc_names]));
548 return false;
549 }
550
551 talloc_free(unc_list);
552 return true;
553}
554
555
556
557_PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
558 int conn_index,
559 struct torture_context *tctx,
560 struct tevent_context *ev)
561{
562 char *host, *share;
563 bool ret;
564
565 if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
566 return false;
567 }
568
569 ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
570 talloc_free(host);
571 talloc_free(share);
572
573 return ret;
574}
575
576_PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
577{
578 return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
579}
580
581
582
583_PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
584{
585 bool ret = true;
586 if (!c) return true;
587 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
588 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
589 ret = false;
590 }
591 talloc_free(c);
592 return ret;
593}
594
595
596/* check if the server produced the expected error code */
597_PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
598 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
599{
600 NTSTATUS status;
601
602 status = smbcli_nt_error(c->tree);
603 if (NT_STATUS_IS_DOS(status)) {
604 int classnum, num;
605 classnum = NT_STATUS_DOS_CLASS(status);
606 num = NT_STATUS_DOS_CODE(status);
607 if (eclass != classnum || ecode != num) {
608 printf("unexpected error code %s\n", nt_errstr(status));
609 printf(" expected %s or %s (at %s)\n",
610 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
611 nt_errstr(nterr), location);
612 return false;
613 }
614 } else {
615 if (!NT_STATUS_EQUAL(nterr, status)) {
616 printf("unexpected error code %s\n", nt_errstr(status));
617 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
618 return false;
619 }
620 }
621
622 return true;
623}
624
625static struct smbcli_state *current_cli;
626static int procnum; /* records process count number when forking */
627
628static void sigcont(int sig)
629{
630}
631
632double torture_create_procs(struct torture_context *tctx,
633 bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
634{
635 int i, status;
636 volatile pid_t *child_status;
637 volatile bool *child_status_out;
638 int synccount;
639 int tries = 8;
640 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
641 double start_time_limit = 10 + (torture_nprocs * 1.5);
642 struct timeval tv;
643
644 *result = true;
645
646 synccount = 0;
647
648 signal(SIGCONT, sigcont);
649
650 child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
651 if (!child_status) {
652 printf("Failed to setup shared memory\n");
653 return -1;
654 }
655
656 child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
657 if (!child_status_out) {
658 printf("Failed to setup result status shared memory\n");
659 return -1;
660 }
661
662 for (i = 0; i < torture_nprocs; i++) {
663 child_status[i] = 0;
664 child_status_out[i] = true;
665 }
666
667 tv = timeval_current();
668
669 for (i=0;i<torture_nprocs;i++) {
670 procnum = i;
671 if (fork() == 0) {
672 char *myname;
673
674 pid_t mypid = getpid();
675 srandom(((int)mypid) ^ ((int)time(NULL)));
676
677 if (asprintf(&myname, "CLIENT%d", i) == -1) {
678 printf("asprintf failed\n");
679 return -1;
680 }
681 lp_set_cmdline(tctx->lp_ctx, "netbios name", myname);
682 free(myname);
683
684
685 while (1) {
686 if (torture_open_connection(&current_cli, tctx, i)) {
687 break;
688 }
689 if (tries-- == 0) {
690 printf("pid %d failed to start\n", (int)getpid());
691 _exit(1);
692 }
693 msleep(100);
694 }
695
696 child_status[i] = getpid();
697
698 pause();
699
700 if (child_status[i]) {
701 printf("Child %d failed to start!\n", i);
702 child_status_out[i] = 1;
703 _exit(1);
704 }
705
706 child_status_out[i] = fn(tctx, current_cli, i);
707 _exit(0);
708 }
709 }
710
711 do {
712 synccount = 0;
713 for (i=0;i<torture_nprocs;i++) {
714 if (child_status[i]) synccount++;
715 }
716 if (synccount == torture_nprocs) break;
717 msleep(100);
718 } while (timeval_elapsed(&tv) < start_time_limit);
719
720 if (synccount != torture_nprocs) {
721 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
722 *result = false;
723 return timeval_elapsed(&tv);
724 }
725
726 printf("Starting %d clients\n", torture_nprocs);
727
728 /* start the client load */
729 tv = timeval_current();
730 for (i=0;i<torture_nprocs;i++) {
731 child_status[i] = 0;
732 }
733
734 printf("%d clients started\n", torture_nprocs);
735
736 kill(0, SIGCONT);
737
738 for (i=0;i<torture_nprocs;i++) {
739 int ret;
740 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
741 if (ret == -1 || WEXITSTATUS(status) != 0) {
742 *result = false;
743 }
744 }
745
746 printf("\n");
747
748 for (i=0;i<torture_nprocs;i++) {
749 if (!child_status_out[i]) {
750 *result = false;
751 }
752 }
753 return timeval_elapsed(&tv);
754}
755
756static bool wrap_smb_multi_test(struct torture_context *torture,
757 struct torture_tcase *tcase,
758 struct torture_test *test)
759{
760 bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
761 bool result;
762
763 torture_create_procs(torture, fn, &result);
764
765 return result;
766}
767
768_PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
769 struct torture_suite *suite,
770 const char *name,
771 bool (*run) (struct torture_context *,
772 struct smbcli_state *,
773 int i))
774{
775 struct torture_test *test;
776 struct torture_tcase *tcase;
777
778 tcase = torture_suite_add_tcase(suite, name);
779
780 test = talloc(tcase, struct torture_test);
781
782 test->name = talloc_strdup(test, name);
783 test->description = NULL;
784 test->run = wrap_smb_multi_test;
785 test->fn = run;
786 test->dangerous = false;
787
788 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
789
790 return test;
791
792}
793
794static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
795 struct torture_tcase *tcase,
796 struct torture_test *test)
797{
798 bool (*fn) (struct torture_context *, struct smbcli_state *,
799 struct smbcli_state *);
800 bool ret;
801
802 struct smbcli_state *cli1, *cli2;
803
804 if (!torture_open_connection(&cli1, torture_ctx, 0) ||
805 !torture_open_connection(&cli2, torture_ctx, 1))
806 return false;
807
808 fn = test->fn;
809
810 ret = fn(torture_ctx, cli1, cli2);
811
812 talloc_free(cli1);
813 talloc_free(cli2);
814
815 return ret;
816}
817
818
819
820_PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
821 struct torture_suite *suite,
822 const char *name,
823 bool (*run) (struct torture_context *,
824 struct smbcli_state *,
825 struct smbcli_state *))
826{
827 struct torture_test *test;
828 struct torture_tcase *tcase;
829
830 tcase = torture_suite_add_tcase(suite, name);
831
832 test = talloc(tcase, struct torture_test);
833
834 test->name = talloc_strdup(test, name);
835 test->description = NULL;
836 test->run = wrap_simple_2smb_test;
837 test->fn = run;
838 test->dangerous = false;
839
840 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
841
842 return test;
843
844}
845
846static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
847 struct torture_tcase *tcase,
848 struct torture_test *test)
849{
850 bool (*fn) (struct torture_context *, struct smbcli_state *);
851 bool ret;
852
853 struct smbcli_state *cli1;
854
855 if (!torture_open_connection(&cli1, torture_ctx, 0))
856 return false;
857
858 fn = test->fn;
859
860 ret = fn(torture_ctx, cli1);
861
862 talloc_free(cli1);
863
864 return ret;
865}
866
867_PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
868 struct torture_suite *suite,
869 const char *name,
870 bool (*run) (struct torture_context *, struct smbcli_state *))
871{
872 struct torture_test *test;
873 struct torture_tcase *tcase;
874
875 tcase = torture_suite_add_tcase(suite, name);
876
877 test = talloc(tcase, struct torture_test);
878
879 test->name = talloc_strdup(test, name);
880 test->description = NULL;
881 test->run = wrap_simple_1smb_test;
882 test->fn = run;
883 test->dangerous = false;
884
885 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
886
887 return test;
888}
889
890
891NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
892 struct smbcli_session *session,
893 const char *sharename,
894 struct smbcli_tree **res)
895{
896 union smb_tcon tcon;
897 struct smbcli_tree *result;
898 TALLOC_CTX *tmp_ctx;
899 NTSTATUS status;
900
901 if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
902 return NT_STATUS_NO_MEMORY;
903 }
904
905 result = smbcli_tree_init(session, tmp_ctx, false);
906 if (result == NULL) {
907 talloc_free(tmp_ctx);
908 return NT_STATUS_NO_MEMORY;
909 }
910
911 tcon.generic.level = RAW_TCON_TCONX;
912 tcon.tconx.in.flags = 0;
913
914 /* Ignore share mode security here */
915 tcon.tconx.in.password = data_blob(NULL, 0);
916 tcon.tconx.in.path = sharename;
917 tcon.tconx.in.device = "?????";
918
919 status = smb_raw_tcon(result, tmp_ctx, &tcon);
920 if (!NT_STATUS_IS_OK(status)) {
921 talloc_free(tmp_ctx);
922 return status;
923 }
924
925 result->tid = tcon.tconx.out.tid;
926 *res = talloc_steal(mem_ctx, result);
927 talloc_free(tmp_ctx);
928 return NT_STATUS_OK;
929}
Note: See TracBrowser for help on using the repository browser.