r12694: Move some headers to the directory of the subsystem they belong to.
[samba.git] / source4 / torture / torture_util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester utility functions
4    Copyright (C) Andrew Tridgell 2003
5    
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.
10    
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.
15    
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.
19 */
20
21 #include "includes.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/libcli.h"
24 #include "system/shmem.h"
25 #include "system/time.h"
26
27
28 /*
29   setup a directory ready for a test
30 */
31 BOOL torture_setup_dir(struct smbcli_state *cli, const char *dname)
32 {
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));
37                 return False;
38         }
39         return True;
40 }
41
42 /*
43   create a directory, returning a handle to it
44 */
45 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
46 {
47         NTSTATUS status;
48         union smb_open io;
49         TALLOC_CTX *mem_ctx;
50
51         mem_ctx = talloc_init("create_directory_handle");
52
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;
65
66         status = smb_raw_open(tree, mem_ctx, &io);
67         talloc_free(mem_ctx);
68
69         if (NT_STATUS_IS_OK(status)) {
70                 *fnum = io.ntcreatex.out.fnum;
71         }
72
73         return status;
74 }
75
76
77 /*
78   sometimes we need a fairly complex file to work with, so we can test
79   all possible attributes. 
80 */
81 int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
82 {
83         int fnum;
84         char buf[7] = "abc";
85         union smb_setfileinfo setfile;
86         union smb_fileinfo fileinfo;
87         time_t t = (time(NULL) & ~1);
88         NTSTATUS status;
89
90         smbcli_unlink(cli->tree, fname);
91         fnum = smbcli_nt_create_full(cli->tree, fname, 0, 
92                                      SEC_RIGHTS_FILE_ALL,
93                                      FILE_ATTRIBUTE_NORMAL,
94                                      NTCREATEX_SHARE_ACCESS_DELETE|
95                                      NTCREATEX_SHARE_ACCESS_READ|
96                                      NTCREATEX_SHARE_ACCESS_WRITE, 
97                                      NTCREATEX_DISP_OVERWRITE_IF,
98                                      0, 0);
99         if (fnum == -1) return -1;
100
101         smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
102
103         if (strchr(fname, ':') == NULL) {
104                 /* setup some EAs */
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");
118                 }
119         }
120
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;
125
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;
129
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));
133         }
134
135         /* make sure all the timestamps aren't the same */
136         fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
137         fileinfo.generic.in.fnum = fnum;
138
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));
142         }
143
144         if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
145                 printf("create_time not setup correctly\n");
146         }
147         if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
148                 printf("access_time not setup correctly\n");
149         }
150         if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
151                 printf("write_time not setup correctly\n");
152         }
153
154         return fnum;
155 }
156
157
158 /*
159   sometimes we need a fairly complex directory to work with, so we can test
160   all possible attributes. 
161 */
162 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
163 {
164         int fnum;
165         union smb_setfileinfo setfile;
166         union smb_fileinfo fileinfo;
167         time_t t = (time(NULL) & ~1);
168         NTSTATUS status;
169
170         smbcli_deltree(cli->tree, dname);
171         fnum = smbcli_nt_create_full(cli->tree, dname, 0, 
172                                      SEC_RIGHTS_DIR_ALL,
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;
179
180         if (strchr(dname, ':') == NULL) {
181                 /* setup some EAs */
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");
195                 }
196         }
197
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;
202
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;
206
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));
210         }
211
212         /* make sure all the timestamps aren't the same */
213         fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
214         fileinfo.generic.in.fnum = fnum;
215
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));
219         }
220
221         if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
222                 printf("create_time not setup correctly\n");
223         }
224         if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
225                 printf("access_time not setup correctly\n");
226         }
227         if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
228                 printf("write_time not setup correctly\n");
229         }
230
231         return fnum;
232 }
233
234
235
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
238    exit 
239
240    The memory is not zeroed 
241
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
244    */
245 void *shm_setup(int size)
246 {
247         int shmid;
248         void *ret;
249
250         shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
251         if (shmid == -1) {
252                 printf("can't get shared memory\n");
253                 exit(1);
254         }
255         ret = (void *)shmat(shmid, 0, 0);
256         if (!ret || ret == (void *)-1) {
257                 printf("can't attach to shared memory\n");
258                 return NULL;
259         }
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 
264
265            See Stevens "advanced programming in unix env" for details
266            */
267         shmctl(shmid, IPC_RMID, 0);
268         
269         return ret;
270 }
271
272
273 /*
274   check that a wire string matches the flags specified 
275   not 100% accurate, but close enough for testing
276 */
277 BOOL wire_bad_flags(WIRE_STRING *str, int flags, struct smbcli_state *cli)
278 {
279         BOOL server_unicode;
280         int len;
281         if (!str || !str->s) return True;
282         len = strlen(str->s);
283         if (flags & STR_TERMINATE) len++;
284
285         server_unicode = (cli->transport->negotiate.capabilities&CAP_UNICODE)?True:False;
286         if (getenv("CLI_FORCE_ASCII") || !lp_unicode()) {
287                 server_unicode = False;
288         }
289
290         if ((flags & STR_UNICODE) || server_unicode) {
291                 len *= 2;
292         } else if (flags & STR_TERMINATE_ASCII) {
293                 len++;
294         }
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);
298                 return True;
299         }
300         return False;
301 }
302
303 /*
304   check if 2 NTTIMEs are equal
305 */
306 BOOL nt_time_equal(NTTIME *t1, NTTIME *t2)
307 {
308         return *t1 == *t2;
309 }
310
311 /*
312   dump a all_info QFILEINFO structure
313 */
314 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
315 {
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);
328 }
329
330 /*
331   dump file infor by name
332 */
333 void torture_all_info(struct smbcli_tree *tree, const char *fname)
334 {
335         TALLOC_CTX *mem_ctx = talloc_init("%s", fname);
336         union smb_fileinfo finfo;
337         NTSTATUS status;
338
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));
344                 return;
345         }
346
347         d_printf("%s:\n", fname);
348         dump_all_info(mem_ctx, &finfo);
349         talloc_free(mem_ctx);
350 }
351
352
353 /*
354   split a UNC name into server and share names
355 */
356 BOOL split_unc_name(const char *unc, char **server, char **share)
357 {
358         char *p = strdup(unc);
359         if (!p) return False;
360         all_string_sub(p, "\\", "/", 0);
361         if (strncmp(p, "//", 2) != 0) return False;
362
363         (*server) = p+2;
364         p = strchr(*server, '/');
365         if (!p) return False;
366
367         *p = 0;
368         (*share) = p+1;
369         
370         return True;
371 }
372
373 /*
374   set a attribute on a file
375 */
376 BOOL torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
377 {
378         union smb_setfileinfo sfinfo;
379         NTSTATUS status;
380
381         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
382         sfinfo.generic.file.fname = fname;
383
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);
388 }
389
390
391 /*
392   set a file descriptor as sparse
393 */
394 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
395 {
396         union smb_ioctl nt;
397         NTSTATUS status;
398         TALLOC_CTX *mem_ctx;
399
400         mem_ctx = talloc_init("torture_set_sparse");
401         if (!mem_ctx) {
402                 return NT_STATUS_NO_MEMORY;
403         }
404
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;
410
411         status = smb_raw_ioctl(tree, mem_ctx, &nt);
412
413         talloc_free(mem_ctx);
414
415         return status;
416 }
417
418 /*
419   check that an EA has the right value 
420 */
421 NTSTATUS torture_check_ea(struct smbcli_state *cli, 
422                           const char *fname, const char *eaname, const char *value)
423 {
424         union smb_fileinfo info;
425         NTSTATUS status;
426         struct ea_name ea;
427         TALLOC_CTX *mem_ctx = talloc_new(cli);
428
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;
433
434         ea.name.s = eaname;
435
436         status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
437         if (!NT_STATUS_IS_OK(status)) {
438                 talloc_free(mem_ctx);
439                 return status;
440         }
441
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;
446         }
447
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;
453         }
454
455         if (value == NULL) {
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;
460                 }
461                 talloc_free(mem_ctx);
462                 return NT_STATUS_OK;
463         }
464
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);
469                 return NT_STATUS_OK;
470         }
471
472         printf("Expected value '%s' not '%*.*s' for ea %s\n",
473                value, 
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,
477                eaname);
478
479         talloc_free(mem_ctx);
480
481         return NT_STATUS_EA_CORRUPT_ERROR;
482 }
483