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