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.
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/libcli.h"
25 #include "system/shmem.h"
26 #include "system/time.h"
30 setup a directory ready for a test
32 BOOL torture_setup_dir(struct smbcli_state *cli, const char *dname)
34 smb_raw_exit(cli->session);
35 if (smbcli_deltree(cli->tree, dname) == -1 ||
36 NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
37 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
44 create a directory, returning a handle to it
46 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
52 mem_ctx = talloc_init("create_directory_handle");
54 io.generic.level = RAW_OPEN_NTCREATEX;
55 io.ntcreatex.in.root_fid = 0;
56 io.ntcreatex.in.flags = 0;
57 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
58 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
59 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
60 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
61 io.ntcreatex.in.alloc_size = 0;
62 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
63 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
64 io.ntcreatex.in.security_flags = 0;
65 io.ntcreatex.in.fname = dname;
67 status = smb_raw_open(tree, mem_ctx, &io);
70 if (NT_STATUS_IS_OK(status)) {
71 *fnum = io.ntcreatex.file.fnum;
79 sometimes we need a fairly complex file to work with, so we can test
80 all possible attributes.
82 int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
86 union smb_setfileinfo setfile;
87 union smb_fileinfo fileinfo;
88 time_t t = (time(NULL) & ~1);
91 smbcli_unlink(cli->tree, fname);
92 fnum = smbcli_nt_create_full(cli->tree, fname, 0,
94 FILE_ATTRIBUTE_NORMAL,
95 NTCREATEX_SHARE_ACCESS_DELETE|
96 NTCREATEX_SHARE_ACCESS_READ|
97 NTCREATEX_SHARE_ACCESS_WRITE,
98 NTCREATEX_DISP_OVERWRITE_IF,
100 if (fnum == -1) return -1;
102 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
104 if (strchr(fname, ':') == NULL) {
106 setfile.generic.level = RAW_SFILEINFO_EA_SET;
107 setfile.generic.file.fnum = fnum;
108 setfile.ea_set.in.num_eas = 2;
109 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
110 setfile.ea_set.in.eas[0].flags = 0;
111 setfile.ea_set.in.eas[0].name.s = "EAONE";
112 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
113 setfile.ea_set.in.eas[1].flags = 0;
114 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
115 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
116 status = smb_raw_setfileinfo(cli->tree, &setfile);
117 if (!NT_STATUS_IS_OK(status)) {
118 printf("Failed to setup EAs\n");
122 /* make sure all the timestamps aren't the same, and are also
123 in different DST zones*/
124 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
125 setfile.generic.file.fnum = fnum;
127 setfile.setattre.in.create_time = t + 9*30*24*60*60;
128 setfile.setattre.in.access_time = t + 6*30*24*60*60;
129 setfile.setattre.in.write_time = t + 3*30*24*60*60;
131 status = smb_raw_setfileinfo(cli->tree, &setfile);
132 if (!NT_STATUS_IS_OK(status)) {
133 printf("Failed to setup file times - %s\n", nt_errstr(status));
136 /* make sure all the timestamps aren't the same */
137 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
138 fileinfo.generic.file.fnum = fnum;
140 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
141 if (!NT_STATUS_IS_OK(status)) {
142 printf("Failed to query file times - %s\n", nt_errstr(status));
145 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
146 printf("create_time not setup correctly\n");
148 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
149 printf("access_time not setup correctly\n");
151 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
152 printf("write_time not setup correctly\n");
160 sometimes we need a fairly complex directory to work with, so we can test
161 all possible attributes.
163 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
166 union smb_setfileinfo setfile;
167 union smb_fileinfo fileinfo;
168 time_t t = (time(NULL) & ~1);
171 smbcli_deltree(cli->tree, dname);
172 fnum = smbcli_nt_create_full(cli->tree, dname, 0,
174 FILE_ATTRIBUTE_DIRECTORY,
175 NTCREATEX_SHARE_ACCESS_READ|
176 NTCREATEX_SHARE_ACCESS_WRITE,
177 NTCREATEX_DISP_OPEN_IF,
178 NTCREATEX_OPTIONS_DIRECTORY, 0);
179 if (fnum == -1) return -1;
181 if (strchr(dname, ':') == NULL) {
183 setfile.generic.level = RAW_SFILEINFO_EA_SET;
184 setfile.generic.file.fnum = fnum;
185 setfile.ea_set.in.num_eas = 2;
186 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
187 setfile.ea_set.in.eas[0].flags = 0;
188 setfile.ea_set.in.eas[0].name.s = "EAONE";
189 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
190 setfile.ea_set.in.eas[1].flags = 0;
191 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
192 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
193 status = smb_raw_setfileinfo(cli->tree, &setfile);
194 if (!NT_STATUS_IS_OK(status)) {
195 printf("Failed to setup EAs\n");
199 /* make sure all the timestamps aren't the same, and are also
200 in different DST zones*/
201 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
202 setfile.generic.file.fnum = fnum;
204 setfile.setattre.in.create_time = t + 9*30*24*60*60;
205 setfile.setattre.in.access_time = t + 6*30*24*60*60;
206 setfile.setattre.in.write_time = t + 3*30*24*60*60;
208 status = smb_raw_setfileinfo(cli->tree, &setfile);
209 if (!NT_STATUS_IS_OK(status)) {
210 printf("Failed to setup file times - %s\n", nt_errstr(status));
213 /* make sure all the timestamps aren't the same */
214 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
215 fileinfo.generic.file.fnum = fnum;
217 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
218 if (!NT_STATUS_IS_OK(status)) {
219 printf("Failed to query file times - %s\n", nt_errstr(status));
222 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
223 printf("create_time not setup correctly\n");
225 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
226 printf("access_time not setup correctly\n");
228 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
229 printf("write_time not setup correctly\n");
237 /* return a pointer to a anonymous shared memory segment of size "size"
238 which will persist across fork() but will disappear when all processes
241 The memory is not zeroed
243 This function uses system5 shared memory. It takes advantage of a property
244 that the memory is not destroyed if it is attached when the id is removed
246 void *shm_setup(int size)
251 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
253 printf("can't get shared memory\n");
256 ret = (void *)shmat(shmid, 0, 0);
257 if (!ret || ret == (void *)-1) {
258 printf("can't attach to shared memory\n");
261 /* the following releases the ipc, but note that this process
262 and all its children will still have access to the memory, its
263 just that the shmid is no longer valid for other shm calls. This
264 means we don't leave behind lots of shm segments after we exit
266 See Stevens "advanced programming in unix env" for details
268 shmctl(shmid, IPC_RMID, 0);
275 check that a wire string matches the flags specified
276 not 100% accurate, but close enough for testing
278 BOOL wire_bad_flags(struct smb_wire_string *str, int flags, struct smbcli_state *cli)
282 if (!str || !str->s) return True;
283 len = strlen(str->s);
284 if (flags & STR_TERMINATE) len++;
286 server_unicode = (cli->transport->negotiate.capabilities&CAP_UNICODE)?True:False;
287 if (getenv("CLI_FORCE_ASCII") || !lp_unicode()) {
288 server_unicode = False;
291 if ((flags & STR_UNICODE) || server_unicode) {
293 } else if (flags & STR_TERMINATE_ASCII) {
296 if (str->private_length != len) {
297 printf("Expected wire_length %d but got %d for '%s'\n",
298 len, str->private_length, str->s);
305 check if 2 NTTIMEs are equal
307 BOOL nt_time_equal(NTTIME *t1, NTTIME *t2)
313 dump a all_info QFILEINFO structure
315 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
317 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
318 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
319 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
320 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
321 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
322 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
323 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
324 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
325 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
326 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
327 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
328 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
332 dump file infor by name
334 void torture_all_info(struct smbcli_tree *tree, const char *fname)
336 TALLOC_CTX *mem_ctx = talloc_init("%s", fname);
337 union smb_fileinfo finfo;
340 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
341 finfo.generic.file.path = fname;
342 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
343 if (!NT_STATUS_IS_OK(status)) {
344 d_printf("%s - %s\n", fname, nt_errstr(status));
348 d_printf("%s:\n", fname);
349 dump_all_info(mem_ctx, &finfo);
350 talloc_free(mem_ctx);
355 split a UNC name into server and share names
357 BOOL split_unc_name(const char *unc, char **server, char **share)
359 char *p = strdup(unc);
360 if (!p) return False;
361 all_string_sub(p, "\\", "/", 0);
362 if (strncmp(p, "//", 2) != 0) return False;
365 p = strchr(*server, '/');
366 if (!p) return False;
375 set a attribute on a file
377 BOOL torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
379 union smb_setfileinfo sfinfo;
382 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
383 sfinfo.generic.file.path = fname;
385 ZERO_STRUCT(sfinfo.basic_info.in);
386 sfinfo.basic_info.in.attrib = attrib;
387 status = smb_raw_setpathinfo(tree, &sfinfo);
388 return NT_STATUS_IS_OK(status);
393 set a file descriptor as sparse
395 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
401 mem_ctx = talloc_init("torture_set_sparse");
403 return NT_STATUS_NO_MEMORY;
406 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
407 nt.ntioctl.in.function = 0x900c4;
408 nt.ntioctl.file.fnum = fnum;
409 nt.ntioctl.in.fsctl = True;
410 nt.ntioctl.in.filter = 0;
412 status = smb_raw_ioctl(tree, mem_ctx, &nt);
414 talloc_free(mem_ctx);
420 check that an EA has the right value
422 NTSTATUS torture_check_ea(struct smbcli_state *cli,
423 const char *fname, const char *eaname, const char *value)
425 union smb_fileinfo info;
428 TALLOC_CTX *mem_ctx = talloc_new(cli);
430 info.ea_list.level = RAW_FILEINFO_EA_LIST;
431 info.ea_list.file.path = fname;
432 info.ea_list.in.num_names = 1;
433 info.ea_list.in.ea_names = &ea;
437 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
438 if (!NT_STATUS_IS_OK(status)) {
439 talloc_free(mem_ctx);
443 if (info.ea_list.out.num_eas != 1) {
444 printf("Expected 1 ea in ea_list\n");
445 talloc_free(mem_ctx);
446 return NT_STATUS_EA_CORRUPT_ERROR;
449 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
450 printf("Expected ea '%s' not '%s' in ea_list\n",
451 eaname, info.ea_list.out.eas[0].name.s);
452 talloc_free(mem_ctx);
453 return NT_STATUS_EA_CORRUPT_ERROR;
457 if (info.ea_list.out.eas[0].value.length != 0) {
458 printf("Expected zero length ea for %s\n", eaname);
459 talloc_free(mem_ctx);
460 return NT_STATUS_EA_CORRUPT_ERROR;
462 talloc_free(mem_ctx);
466 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
467 memcmp(value, info.ea_list.out.eas[0].value.data,
468 info.ea_list.out.eas[0].value.length) == 0) {
469 talloc_free(mem_ctx);
473 printf("Expected value '%s' not '%*.*s' for ea %s\n",
475 (int)info.ea_list.out.eas[0].value.length,
476 (int)info.ea_list.out.eas[0].value.length,
477 info.ea_list.out.eas[0].value.data,
480 talloc_free(mem_ctx);
482 return NT_STATUS_EA_CORRUPT_ERROR;