source: trunk/server/source4/torture/util_smb.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

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