2 Unix SMB/CIFS implementation.
3 SMB torture tester utility functions
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libcli/raw/libcliraw.h"
23 #include "system/shmem.h"
24 #include "system/time.h"
28 setup a directory ready for a test
30 BOOL torture_setup_dir(struct smbcli_state *cli, const char *dname)
32 smb_raw_exit(cli->session);
33 if (smbcli_deltree(cli->tree, dname) == -1 ||
34 NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
35 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
42 create a directory, returning a handle to it
44 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
50 mem_ctx = talloc_init("create_directory_handle");
52 io.generic.level = RAW_OPEN_NTCREATEX;
53 io.ntcreatex.in.root_fid = 0;
54 io.ntcreatex.in.flags = 0;
55 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
56 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
57 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
58 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
59 io.ntcreatex.in.alloc_size = 0;
60 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
61 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
62 io.ntcreatex.in.security_flags = 0;
63 io.ntcreatex.in.fname = dname;
65 status = smb_raw_open(tree, mem_ctx, &io);
68 if (NT_STATUS_IS_OK(status)) {
69 *fnum = io.ntcreatex.out.fnum;
77 sometimes we need a fairly complex file to work with, so we can test
78 all possible attributes.
80 int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
84 union smb_setfileinfo setfile;
85 union smb_fileinfo fileinfo;
86 time_t t = (time(NULL) & ~1);
89 smbcli_unlink(cli->tree, fname);
90 fnum = smbcli_nt_create_full(cli->tree, fname, 0,
92 FILE_ATTRIBUTE_NORMAL,
93 NTCREATEX_SHARE_ACCESS_DELETE|
94 NTCREATEX_SHARE_ACCESS_READ|
95 NTCREATEX_SHARE_ACCESS_WRITE,
96 NTCREATEX_DISP_OVERWRITE_IF,
98 if (fnum == -1) return -1;
100 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
102 if (strchr(fname, ':') == NULL) {
104 setfile.generic.level = RAW_SFILEINFO_EA_SET;
105 setfile.generic.file.fnum = fnum;
106 setfile.ea_set.in.num_eas = 2;
107 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
108 setfile.ea_set.in.eas[0].flags = 0;
109 setfile.ea_set.in.eas[0].name.s = "EAONE";
110 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
111 setfile.ea_set.in.eas[1].flags = 0;
112 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
113 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
114 status = smb_raw_setfileinfo(cli->tree, &setfile);
115 if (!NT_STATUS_IS_OK(status)) {
116 printf("Failed to setup EAs\n");
120 /* make sure all the timestamps aren't the same, and are also
121 in different DST zones*/
122 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
123 setfile.generic.file.fnum = fnum;
125 setfile.setattre.in.create_time = t + 9*30*24*60*60;
126 setfile.setattre.in.access_time = t + 6*30*24*60*60;
127 setfile.setattre.in.write_time = t + 3*30*24*60*60;
129 status = smb_raw_setfileinfo(cli->tree, &setfile);
130 if (!NT_STATUS_IS_OK(status)) {
131 printf("Failed to setup file times - %s\n", nt_errstr(status));
134 /* make sure all the timestamps aren't the same */
135 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
136 fileinfo.generic.in.fnum = fnum;
138 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
139 if (!NT_STATUS_IS_OK(status)) {
140 printf("Failed to query file times - %s\n", nt_errstr(status));
143 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
144 printf("create_time not setup correctly\n");
146 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
147 printf("access_time not setup correctly\n");
149 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
150 printf("write_time not setup correctly\n");
158 sometimes we need a fairly complex directory to work with, so we can test
159 all possible attributes.
161 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
164 union smb_setfileinfo setfile;
165 union smb_fileinfo fileinfo;
166 time_t t = (time(NULL) & ~1);
169 smbcli_deltree(cli->tree, dname);
170 fnum = smbcli_nt_create_full(cli->tree, dname, 0,
172 FILE_ATTRIBUTE_DIRECTORY,
173 NTCREATEX_SHARE_ACCESS_READ|
174 NTCREATEX_SHARE_ACCESS_WRITE,
175 NTCREATEX_DISP_OPEN_IF,
176 NTCREATEX_OPTIONS_DIRECTORY, 0);
177 if (fnum == -1) return -1;
179 if (strchr(dname, ':') == NULL) {
181 setfile.generic.level = RAW_SFILEINFO_EA_SET;
182 setfile.generic.file.fnum = fnum;
183 setfile.ea_set.in.num_eas = 2;
184 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
185 setfile.ea_set.in.eas[0].flags = 0;
186 setfile.ea_set.in.eas[0].name.s = "EAONE";
187 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
188 setfile.ea_set.in.eas[1].flags = 0;
189 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
190 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
191 status = smb_raw_setfileinfo(cli->tree, &setfile);
192 if (!NT_STATUS_IS_OK(status)) {
193 printf("Failed to setup EAs\n");
197 /* make sure all the timestamps aren't the same, and are also
198 in different DST zones*/
199 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
200 setfile.generic.file.fnum = fnum;
202 setfile.setattre.in.create_time = t + 9*30*24*60*60;
203 setfile.setattre.in.access_time = t + 6*30*24*60*60;
204 setfile.setattre.in.write_time = t + 3*30*24*60*60;
206 status = smb_raw_setfileinfo(cli->tree, &setfile);
207 if (!NT_STATUS_IS_OK(status)) {
208 printf("Failed to setup file times - %s\n", nt_errstr(status));
211 /* make sure all the timestamps aren't the same */
212 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
213 fileinfo.generic.in.fnum = fnum;
215 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
216 if (!NT_STATUS_IS_OK(status)) {
217 printf("Failed to query file times - %s\n", nt_errstr(status));
220 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
221 printf("create_time not setup correctly\n");
223 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
224 printf("access_time not setup correctly\n");
226 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
227 printf("write_time not setup correctly\n");
235 /* return a pointer to a anonymous shared memory segment of size "size"
236 which will persist across fork() but will disappear when all processes
239 The memory is not zeroed
241 This function uses system5 shared memory. It takes advantage of a property
242 that the memory is not destroyed if it is attached when the id is removed
244 void *shm_setup(int size)
249 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
251 printf("can't get shared memory\n");
254 ret = (void *)shmat(shmid, 0, 0);
255 if (!ret || ret == (void *)-1) {
256 printf("can't attach to shared memory\n");
259 /* the following releases the ipc, but note that this process
260 and all its children will still have access to the memory, its
261 just that the shmid is no longer valid for other shm calls. This
262 means we don't leave behind lots of shm segments after we exit
264 See Stevens "advanced programming in unix env" for details
266 shmctl(shmid, IPC_RMID, 0);
273 check that a wire string matches the flags specified
274 not 100% accurate, but close enough for testing
276 BOOL wire_bad_flags(WIRE_STRING *str, int flags, struct smbcli_state *cli)
280 if (!str || !str->s) return True;
281 len = strlen(str->s);
282 if (flags & STR_TERMINATE) len++;
284 server_unicode = (cli->transport->negotiate.capabilities&CAP_UNICODE)?True:False;
285 if (getenv("CLI_FORCE_ASCII") || !lp_unicode()) {
286 server_unicode = False;
289 if ((flags & STR_UNICODE) || server_unicode) {
291 } else if (flags & STR_TERMINATE_ASCII) {
294 if (str->private_length != len) {
295 printf("Expected wire_length %d but got %d for '%s'\n",
296 len, str->private_length, str->s);
303 check if 2 NTTIMEs are equal
305 BOOL nt_time_equal(NTTIME *t1, NTTIME *t2)
311 dump a all_info QFILEINFO structure
313 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
315 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
316 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
317 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
318 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
319 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
320 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
321 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
322 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
323 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
324 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
325 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
326 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
330 dump file infor by name
332 void torture_all_info(struct smbcli_tree *tree, const char *fname)
334 TALLOC_CTX *mem_ctx = talloc_init("%s", fname);
335 union smb_fileinfo finfo;
338 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
339 finfo.generic.in.fname = fname;
340 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
341 if (!NT_STATUS_IS_OK(status)) {
342 d_printf("%s - %s\n", fname, nt_errstr(status));
346 d_printf("%s:\n", fname);
347 dump_all_info(mem_ctx, &finfo);
348 talloc_free(mem_ctx);
353 split a UNC name into server and share names
355 BOOL split_unc_name(const char *unc, char **server, char **share)
357 char *p = strdup(unc);
358 if (!p) return False;
359 all_string_sub(p, "\\", "/", 0);
360 if (strncmp(p, "//", 2) != 0) return False;
363 p = strchr(*server, '/');
364 if (!p) return False;
373 set a attribute on a file
375 BOOL torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
377 union smb_setfileinfo sfinfo;
380 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
381 sfinfo.generic.file.fname = fname;
383 ZERO_STRUCT(sfinfo.basic_info.in);
384 sfinfo.basic_info.in.attrib = attrib;
385 status = smb_raw_setpathinfo(tree, &sfinfo);
386 return NT_STATUS_IS_OK(status);
391 set a file descriptor as sparse
393 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
399 mem_ctx = talloc_init("torture_set_sparse");
401 return NT_STATUS_NO_MEMORY;
404 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
405 nt.ntioctl.in.function = 0x900c4;
406 nt.ntioctl.in.fnum = fnum;
407 nt.ntioctl.in.fsctl = True;
408 nt.ntioctl.in.filter = 0;
410 status = smb_raw_ioctl(tree, mem_ctx, &nt);
412 talloc_free(mem_ctx);
418 check that an EA has the right value
420 NTSTATUS torture_check_ea(struct smbcli_state *cli,
421 const char *fname, const char *eaname, const char *value)
423 union smb_fileinfo info;
426 TALLOC_CTX *mem_ctx = talloc_new(cli);
428 info.ea_list.level = RAW_FILEINFO_EA_LIST;
429 info.ea_list.file.fname = fname;
430 info.ea_list.in.num_names = 1;
431 info.ea_list.in.ea_names = &ea;
435 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
436 if (!NT_STATUS_IS_OK(status)) {
437 talloc_free(mem_ctx);
441 if (info.ea_list.out.num_eas != 1) {
442 printf("Expected 1 ea in ea_list\n");
443 talloc_free(mem_ctx);
444 return NT_STATUS_EA_CORRUPT_ERROR;
447 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
448 printf("Expected ea '%s' not '%s' in ea_list\n",
449 eaname, info.ea_list.out.eas[0].name.s);
450 talloc_free(mem_ctx);
451 return NT_STATUS_EA_CORRUPT_ERROR;
455 if (info.ea_list.out.eas[0].value.length != 0) {
456 printf("Expected zero length ea for %s\n", eaname);
457 talloc_free(mem_ctx);
458 return NT_STATUS_EA_CORRUPT_ERROR;
460 talloc_free(mem_ctx);
464 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
465 memcmp(value, info.ea_list.out.eas[0].value.data,
466 info.ea_list.out.eas[0].value.length) == 0) {
467 talloc_free(mem_ctx);
471 printf("Expected value '%s' not '%*.*s' for ea %s\n",
473 (int)info.ea_list.out.eas[0].value.length,
474 (int)info.ea_list.out.eas[0].value.length,
475 info.ea_list.out.eas[0].value.data,
478 talloc_free(mem_ctx);
480 return NT_STATUS_EA_CORRUPT_ERROR;