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 "libcli/libcli.h"
24 #include "system/shmem.h"
25 #include "system/time.h"
29 setup a directory ready for a test
31 BOOL torture_setup_dir(struct smbcli_state *cli, const char *dname)
33 smb_raw_exit(cli->session);
34 if (smbcli_deltree(cli->tree, dname) == -1 ||
35 NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
36 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
43 create a directory, returning a handle to it
45 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
51 mem_ctx = talloc_init("create_directory_handle");
53 io.generic.level = RAW_OPEN_NTCREATEX;
54 io.ntcreatex.in.root_fid = 0;
55 io.ntcreatex.in.flags = 0;
56 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
57 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
58 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
59 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
60 io.ntcreatex.in.alloc_size = 0;
61 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
62 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
63 io.ntcreatex.in.security_flags = 0;
64 io.ntcreatex.in.fname = dname;
66 status = smb_raw_open(tree, mem_ctx, &io);
69 if (NT_STATUS_IS_OK(status)) {
70 *fnum = io.ntcreatex.out.fnum;
78 sometimes we need a fairly complex file to work with, so we can test
79 all possible attributes.
81 int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
85 union smb_setfileinfo setfile;
86 union smb_fileinfo fileinfo;
87 time_t t = (time(NULL) & ~1);
90 smbcli_unlink(cli->tree, fname);
91 fnum = smbcli_nt_create_full(cli->tree, fname, 0,
93 FILE_ATTRIBUTE_NORMAL,
94 NTCREATEX_SHARE_ACCESS_DELETE|
95 NTCREATEX_SHARE_ACCESS_READ|
96 NTCREATEX_SHARE_ACCESS_WRITE,
97 NTCREATEX_DISP_OVERWRITE_IF,
99 if (fnum == -1) return -1;
101 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
103 if (strchr(fname, ':') == NULL) {
105 setfile.generic.level = RAW_SFILEINFO_EA_SET;
106 setfile.generic.file.fnum = fnum;
107 setfile.ea_set.in.num_eas = 2;
108 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
109 setfile.ea_set.in.eas[0].flags = 0;
110 setfile.ea_set.in.eas[0].name.s = "EAONE";
111 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
112 setfile.ea_set.in.eas[1].flags = 0;
113 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
114 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
115 status = smb_raw_setfileinfo(cli->tree, &setfile);
116 if (!NT_STATUS_IS_OK(status)) {
117 printf("Failed to setup EAs\n");
121 /* make sure all the timestamps aren't the same, and are also
122 in different DST zones*/
123 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
124 setfile.generic.file.fnum = fnum;
126 setfile.setattre.in.create_time = t + 9*30*24*60*60;
127 setfile.setattre.in.access_time = t + 6*30*24*60*60;
128 setfile.setattre.in.write_time = t + 3*30*24*60*60;
130 status = smb_raw_setfileinfo(cli->tree, &setfile);
131 if (!NT_STATUS_IS_OK(status)) {
132 printf("Failed to setup file times - %s\n", nt_errstr(status));
135 /* make sure all the timestamps aren't the same */
136 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
137 fileinfo.generic.in.fnum = fnum;
139 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
140 if (!NT_STATUS_IS_OK(status)) {
141 printf("Failed to query file times - %s\n", nt_errstr(status));
144 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
145 printf("create_time not setup correctly\n");
147 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
148 printf("access_time not setup correctly\n");
150 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
151 printf("write_time not setup correctly\n");
159 sometimes we need a fairly complex directory to work with, so we can test
160 all possible attributes.
162 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
165 union smb_setfileinfo setfile;
166 union smb_fileinfo fileinfo;
167 time_t t = (time(NULL) & ~1);
170 smbcli_deltree(cli->tree, dname);
171 fnum = smbcli_nt_create_full(cli->tree, dname, 0,
173 FILE_ATTRIBUTE_DIRECTORY,
174 NTCREATEX_SHARE_ACCESS_READ|
175 NTCREATEX_SHARE_ACCESS_WRITE,
176 NTCREATEX_DISP_OPEN_IF,
177 NTCREATEX_OPTIONS_DIRECTORY, 0);
178 if (fnum == -1) return -1;
180 if (strchr(dname, ':') == NULL) {
182 setfile.generic.level = RAW_SFILEINFO_EA_SET;
183 setfile.generic.file.fnum = fnum;
184 setfile.ea_set.in.num_eas = 2;
185 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
186 setfile.ea_set.in.eas[0].flags = 0;
187 setfile.ea_set.in.eas[0].name.s = "EAONE";
188 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
189 setfile.ea_set.in.eas[1].flags = 0;
190 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
191 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
192 status = smb_raw_setfileinfo(cli->tree, &setfile);
193 if (!NT_STATUS_IS_OK(status)) {
194 printf("Failed to setup EAs\n");
198 /* make sure all the timestamps aren't the same, and are also
199 in different DST zones*/
200 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
201 setfile.generic.file.fnum = fnum;
203 setfile.setattre.in.create_time = t + 9*30*24*60*60;
204 setfile.setattre.in.access_time = t + 6*30*24*60*60;
205 setfile.setattre.in.write_time = t + 3*30*24*60*60;
207 status = smb_raw_setfileinfo(cli->tree, &setfile);
208 if (!NT_STATUS_IS_OK(status)) {
209 printf("Failed to setup file times - %s\n", nt_errstr(status));
212 /* make sure all the timestamps aren't the same */
213 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
214 fileinfo.generic.in.fnum = fnum;
216 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
217 if (!NT_STATUS_IS_OK(status)) {
218 printf("Failed to query file times - %s\n", nt_errstr(status));
221 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
222 printf("create_time not setup correctly\n");
224 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
225 printf("access_time not setup correctly\n");
227 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
228 printf("write_time not setup correctly\n");
236 /* return a pointer to a anonymous shared memory segment of size "size"
237 which will persist across fork() but will disappear when all processes
240 The memory is not zeroed
242 This function uses system5 shared memory. It takes advantage of a property
243 that the memory is not destroyed if it is attached when the id is removed
245 void *shm_setup(int size)
250 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
252 printf("can't get shared memory\n");
255 ret = (void *)shmat(shmid, 0, 0);
256 if (!ret || ret == (void *)-1) {
257 printf("can't attach to shared memory\n");
260 /* the following releases the ipc, but note that this process
261 and all its children will still have access to the memory, its
262 just that the shmid is no longer valid for other shm calls. This
263 means we don't leave behind lots of shm segments after we exit
265 See Stevens "advanced programming in unix env" for details
267 shmctl(shmid, IPC_RMID, 0);
274 check that a wire string matches the flags specified
275 not 100% accurate, but close enough for testing
277 BOOL wire_bad_flags(WIRE_STRING *str, int flags, struct smbcli_state *cli)
281 if (!str || !str->s) return True;
282 len = strlen(str->s);
283 if (flags & STR_TERMINATE) len++;
285 server_unicode = (cli->transport->negotiate.capabilities&CAP_UNICODE)?True:False;
286 if (getenv("CLI_FORCE_ASCII") || !lp_unicode()) {
287 server_unicode = False;
290 if ((flags & STR_UNICODE) || server_unicode) {
292 } else if (flags & STR_TERMINATE_ASCII) {
295 if (str->private_length != len) {
296 printf("Expected wire_length %d but got %d for '%s'\n",
297 len, str->private_length, str->s);
304 check if 2 NTTIMEs are equal
306 BOOL nt_time_equal(NTTIME *t1, NTTIME *t2)
312 dump a all_info QFILEINFO structure
314 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
316 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
317 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
318 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
319 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
320 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
321 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
322 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
323 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
324 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
325 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
326 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
327 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
331 dump file infor by name
333 void torture_all_info(struct smbcli_tree *tree, const char *fname)
335 TALLOC_CTX *mem_ctx = talloc_init("%s", fname);
336 union smb_fileinfo finfo;
339 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
340 finfo.generic.in.fname = fname;
341 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
342 if (!NT_STATUS_IS_OK(status)) {
343 d_printf("%s - %s\n", fname, nt_errstr(status));
347 d_printf("%s:\n", fname);
348 dump_all_info(mem_ctx, &finfo);
349 talloc_free(mem_ctx);
354 split a UNC name into server and share names
356 BOOL split_unc_name(const char *unc, char **server, char **share)
358 char *p = strdup(unc);
359 if (!p) return False;
360 all_string_sub(p, "\\", "/", 0);
361 if (strncmp(p, "//", 2) != 0) return False;
364 p = strchr(*server, '/');
365 if (!p) return False;
374 set a attribute on a file
376 BOOL torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
378 union smb_setfileinfo sfinfo;
381 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
382 sfinfo.generic.file.fname = fname;
384 ZERO_STRUCT(sfinfo.basic_info.in);
385 sfinfo.basic_info.in.attrib = attrib;
386 status = smb_raw_setpathinfo(tree, &sfinfo);
387 return NT_STATUS_IS_OK(status);
392 set a file descriptor as sparse
394 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
400 mem_ctx = talloc_init("torture_set_sparse");
402 return NT_STATUS_NO_MEMORY;
405 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
406 nt.ntioctl.in.function = 0x900c4;
407 nt.ntioctl.in.fnum = fnum;
408 nt.ntioctl.in.fsctl = True;
409 nt.ntioctl.in.filter = 0;
411 status = smb_raw_ioctl(tree, mem_ctx, &nt);
413 talloc_free(mem_ctx);
419 check that an EA has the right value
421 NTSTATUS torture_check_ea(struct smbcli_state *cli,
422 const char *fname, const char *eaname, const char *value)
424 union smb_fileinfo info;
427 TALLOC_CTX *mem_ctx = talloc_new(cli);
429 info.ea_list.level = RAW_FILEINFO_EA_LIST;
430 info.ea_list.file.fname = fname;
431 info.ea_list.in.num_names = 1;
432 info.ea_list.in.ea_names = &ea;
436 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
437 if (!NT_STATUS_IS_OK(status)) {
438 talloc_free(mem_ctx);
442 if (info.ea_list.out.num_eas != 1) {
443 printf("Expected 1 ea in ea_list\n");
444 talloc_free(mem_ctx);
445 return NT_STATUS_EA_CORRUPT_ERROR;
448 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
449 printf("Expected ea '%s' not '%s' in ea_list\n",
450 eaname, info.ea_list.out.eas[0].name.s);
451 talloc_free(mem_ctx);
452 return NT_STATUS_EA_CORRUPT_ERROR;
456 if (info.ea_list.out.eas[0].value.length != 0) {
457 printf("Expected zero length ea for %s\n", eaname);
458 talloc_free(mem_ctx);
459 return NT_STATUS_EA_CORRUPT_ERROR;
461 talloc_free(mem_ctx);
465 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
466 memcmp(value, info.ea_list.out.eas[0].value.data,
467 info.ea_list.out.eas[0].value.length) == 0) {
468 talloc_free(mem_ctx);
472 printf("Expected value '%s' not '%*.*s' for ea %s\n",
474 (int)info.ea_list.out.eas[0].value.length,
475 (int)info.ea_list.out.eas[0].value.length,
476 info.ea_list.out.eas[0].value.data,
479 talloc_free(mem_ctx);
481 return NT_STATUS_EA_CORRUPT_ERROR;