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"
25 #include "librpc/gen_ndr/ndr_security.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));
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");
119 /* make sure all the timestamps aren't the same, and are also
120 in different DST zones*/
121 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
122 setfile.generic.file.fnum = fnum;
124 setfile.setattre.in.create_time = t + 9*30*24*60*60;
125 setfile.setattre.in.access_time = t + 6*30*24*60*60;
126 setfile.setattre.in.write_time = t + 3*30*24*60*60;
128 status = smb_raw_setfileinfo(cli->tree, &setfile);
129 if (!NT_STATUS_IS_OK(status)) {
130 printf("Failed to setup file times - %s\n", nt_errstr(status));
133 /* make sure all the timestamps aren't the same */
134 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
135 fileinfo.generic.in.fnum = fnum;
137 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
138 if (!NT_STATUS_IS_OK(status)) {
139 printf("Failed to query file times - %s\n", nt_errstr(status));
142 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
143 printf("create_time not setup correctly\n");
145 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
146 printf("access_time not setup correctly\n");
148 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
149 printf("write_time not setup correctly\n");
157 /* return a pointer to a anonymous shared memory segment of size "size"
158 which will persist across fork() but will disappear when all processes
161 The memory is not zeroed
163 This function uses system5 shared memory. It takes advantage of a property
164 that the memory is not destroyed if it is attached when the id is removed
166 void *shm_setup(int size)
171 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
173 printf("can't get shared memory\n");
176 ret = (void *)shmat(shmid, 0, 0);
177 if (!ret || ret == (void *)-1) {
178 printf("can't attach to shared memory\n");
181 /* the following releases the ipc, but note that this process
182 and all its children will still have access to the memory, its
183 just that the shmid is no longer valid for other shm calls. This
184 means we don't leave behind lots of shm segments after we exit
186 See Stevens "advanced programming in unix env" for details
188 shmctl(shmid, IPC_RMID, 0);
195 check that a wire string matches the flags specified
196 not 100% accurate, but close enough for testing
198 BOOL wire_bad_flags(WIRE_STRING *str, int flags, struct smbcli_state *cli)
202 if (!str || !str->s) return True;
203 len = strlen(str->s);
204 if (flags & STR_TERMINATE) len++;
206 server_unicode = (cli->transport->negotiate.capabilities&CAP_UNICODE)?True:False;
207 if (getenv("CLI_FORCE_ASCII") || !lp_unicode()) {
208 server_unicode = False;
211 if ((flags & STR_UNICODE) || server_unicode) {
213 } else if (flags & STR_TERMINATE_ASCII) {
216 if (str->private_length != len) {
217 printf("Expected wire_length %d but got %d for '%s'\n",
218 len, str->private_length, str->s);
225 check if 2 NTTIMEs are equal
227 BOOL nt_time_equal(NTTIME *t1, NTTIME *t2)
233 dump a all_info QFILEINFO structure
235 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
237 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
238 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
239 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
240 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
241 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
242 d_printf("\talloc_size: %llu\n", (uint64_t)finfo->all_info.out.alloc_size);
243 d_printf("\tsize: %llu\n", (uint64_t)finfo->all_info.out.size);
244 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
245 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
246 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
247 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
248 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
252 dump file infor by name
254 void torture_all_info(struct smbcli_tree *tree, const char *fname)
256 TALLOC_CTX *mem_ctx = talloc_init("%s", fname);
257 union smb_fileinfo finfo;
260 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
261 finfo.generic.in.fname = fname;
262 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
263 if (!NT_STATUS_IS_OK(status)) {
264 d_printf("%s - %s\n", fname, nt_errstr(status));
268 d_printf("%s:\n", fname);
269 dump_all_info(mem_ctx, &finfo);
270 talloc_free(mem_ctx);
275 split a UNC name into server and share names
277 BOOL split_unc_name(const char *unc, char **server, char **share)
279 char *p = strdup(unc);
280 if (!p) return False;
281 all_string_sub(p, "\\", "/", 0);
282 if (strncmp(p, "//", 2) != 0) return False;
285 p = strchr(*server, '/');
286 if (!p) return False;
295 set a attribute on a file
297 BOOL torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
299 union smb_setfileinfo sfinfo;
302 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
303 sfinfo.generic.file.fname = fname;
305 ZERO_STRUCT(sfinfo.basic_info.in);
306 sfinfo.basic_info.in.attrib = attrib;
307 status = smb_raw_setpathinfo(tree, &sfinfo);
308 return NT_STATUS_IS_OK(status);
313 set a file descriptor as sparse
315 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
321 mem_ctx = talloc_init("torture_set_sparse");
323 return NT_STATUS_NO_MEMORY;
326 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
327 nt.ntioctl.in.function = 0x900c4;
328 nt.ntioctl.in.fnum = fnum;
329 nt.ntioctl.in.fsctl = True;
330 nt.ntioctl.in.filter = 0;
332 status = smb_raw_ioctl(tree, mem_ctx, &nt);
334 talloc_free(mem_ctx);
340 check that an EA has the right value
342 NTSTATUS torture_check_ea(struct smbcli_state *cli,
343 const char *fname, const char *eaname, const char *value)
345 union smb_fileinfo info;
348 TALLOC_CTX *mem_ctx = talloc_new(cli);
350 info.ea_list.level = RAW_FILEINFO_EA_LIST;
351 info.ea_list.file.fname = fname;
352 info.ea_list.in.num_names = 1;
353 info.ea_list.in.ea_names = &ea;
357 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
358 if (!NT_STATUS_IS_OK(status)) {
359 talloc_free(mem_ctx);
363 if (info.ea_list.out.num_eas != 1) {
364 printf("Expected 1 ea in ea_list\n");
365 talloc_free(mem_ctx);
366 return NT_STATUS_EA_CORRUPT_ERROR;
369 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
370 printf("Expected ea '%s' not '%s' in ea_list\n",
371 eaname, info.ea_list.out.eas[0].name.s);
372 talloc_free(mem_ctx);
373 return NT_STATUS_EA_CORRUPT_ERROR;
377 if (info.ea_list.out.eas[0].value.length != 0) {
378 printf("Expected zero length ea for %s\n", eaname);
379 talloc_free(mem_ctx);
380 return NT_STATUS_EA_CORRUPT_ERROR;
382 talloc_free(mem_ctx);
386 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
387 memcmp(value, info.ea_list.out.eas[0].value.data,
388 info.ea_list.out.eas[0].value.length) == 0) {
389 talloc_free(mem_ctx);
393 printf("Expected value '%s' not '%*.*s' for ea %s\n",
395 (int)info.ea_list.out.eas[0].value.length,
396 (int)info.ea_list.out.eas[0].value.length,
397 info.ea_list.out.eas[0].value.data,
400 talloc_free(mem_ctx);
402 return NT_STATUS_EA_CORRUPT_ERROR;