r16044: Create a samba3 specific file in torture/rpc. The tests in there survive
[ira/wip.git] / source / 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 "smb.h"
23 #include "lib/cmdline/popt_common.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/raw/ioctl.h"
26 #include "libcli/libcli.h"
27 #include "system/shmem.h"
28 #include "system/time.h"
29 #include "torture/torture.h"
30
31
32 /**
33   setup a directory ready for a test
34 */
35 _PUBLIC_ BOOL torture_setup_dir(struct smbcli_state *cli, const char *dname)
36 {
37         smb_raw_exit(cli->session);
38         if (smbcli_deltree(cli->tree, dname) == -1 ||
39             NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
40                 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
41                 return False;
42         }
43         return True;
44 }
45
46 /*
47   create a directory, returning a handle to it
48 */
49 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
50 {
51         NTSTATUS status;
52         union smb_open io;
53         TALLOC_CTX *mem_ctx;
54
55         mem_ctx = talloc_init("create_directory_handle");
56
57         io.generic.level = RAW_OPEN_NTCREATEX;
58         io.ntcreatex.in.root_fid = 0;
59         io.ntcreatex.in.flags = 0;
60         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
61         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
62         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
63         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
64         io.ntcreatex.in.alloc_size = 0;
65         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
66         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
67         io.ntcreatex.in.security_flags = 0;
68         io.ntcreatex.in.fname = dname;
69
70         status = smb_raw_open(tree, mem_ctx, &io);
71         talloc_free(mem_ctx);
72
73         if (NT_STATUS_IS_OK(status)) {
74                 *fnum = io.ntcreatex.out.file.fnum;
75         }
76
77         return status;
78 }
79
80
81 /**
82   sometimes we need a fairly complex file to work with, so we can test
83   all possible attributes. 
84 */
85 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
86 {
87         int fnum;
88         char buf[7] = "abc";
89         union smb_setfileinfo setfile;
90         union smb_fileinfo fileinfo;
91         time_t t = (time(NULL) & ~1);
92         NTSTATUS status;
93
94         smbcli_unlink(cli->tree, fname);
95         fnum = smbcli_nt_create_full(cli->tree, fname, 0, 
96                                      SEC_RIGHTS_FILE_ALL,
97                                      FILE_ATTRIBUTE_NORMAL,
98                                      NTCREATEX_SHARE_ACCESS_DELETE|
99                                      NTCREATEX_SHARE_ACCESS_READ|
100                                      NTCREATEX_SHARE_ACCESS_WRITE, 
101                                      NTCREATEX_DISP_OVERWRITE_IF,
102                                      0, 0);
103         if (fnum == -1) return -1;
104
105         smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
106
107         if (strchr(fname, ':') == NULL) {
108                 /* setup some EAs */
109                 setfile.generic.level = RAW_SFILEINFO_EA_SET;
110                 setfile.generic.in.file.fnum = fnum;
111                 setfile.ea_set.in.num_eas = 2;  
112                 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
113                 setfile.ea_set.in.eas[0].flags = 0;
114                 setfile.ea_set.in.eas[0].name.s = "EAONE";
115                 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
116                 setfile.ea_set.in.eas[1].flags = 0;
117                 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
118                 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
119                 status = smb_raw_setfileinfo(cli->tree, &setfile);
120                 if (!NT_STATUS_IS_OK(status)) {
121                         printf("Failed to setup EAs\n");
122                 }
123         }
124
125         /* make sure all the timestamps aren't the same, and are also 
126            in different DST zones*/
127         setfile.generic.level = RAW_SFILEINFO_SETATTRE;
128         setfile.generic.in.file.fnum = fnum;
129
130         setfile.setattre.in.create_time = t + 9*30*24*60*60;
131         setfile.setattre.in.access_time = t + 6*30*24*60*60;
132         setfile.setattre.in.write_time  = t + 3*30*24*60*60;
133
134         status = smb_raw_setfileinfo(cli->tree, &setfile);
135         if (!NT_STATUS_IS_OK(status)) {
136                 printf("Failed to setup file times - %s\n", nt_errstr(status));
137         }
138
139         /* make sure all the timestamps aren't the same */
140         fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
141         fileinfo.generic.in.file.fnum = fnum;
142
143         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
144         if (!NT_STATUS_IS_OK(status)) {
145                 printf("Failed to query file times - %s\n", nt_errstr(status));
146         }
147
148         if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
149                 printf("create_time not setup correctly\n");
150         }
151         if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
152                 printf("access_time not setup correctly\n");
153         }
154         if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
155                 printf("write_time not setup correctly\n");
156         }
157
158         return fnum;
159 }
160
161
162 /*
163   sometimes we need a fairly complex directory to work with, so we can test
164   all possible attributes. 
165 */
166 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
167 {
168         int fnum;
169         union smb_setfileinfo setfile;
170         union smb_fileinfo fileinfo;
171         time_t t = (time(NULL) & ~1);
172         NTSTATUS status;
173
174         smbcli_deltree(cli->tree, dname);
175         fnum = smbcli_nt_create_full(cli->tree, dname, 0, 
176                                      SEC_RIGHTS_DIR_ALL,
177                                      FILE_ATTRIBUTE_DIRECTORY,
178                                      NTCREATEX_SHARE_ACCESS_READ|
179                                      NTCREATEX_SHARE_ACCESS_WRITE, 
180                                      NTCREATEX_DISP_OPEN_IF,
181                                      NTCREATEX_OPTIONS_DIRECTORY, 0);
182         if (fnum == -1) return -1;
183
184         if (strchr(dname, ':') == NULL) {
185                 /* setup some EAs */
186                 setfile.generic.level = RAW_SFILEINFO_EA_SET;
187                 setfile.generic.in.file.fnum = fnum;
188                 setfile.ea_set.in.num_eas = 2;  
189                 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
190                 setfile.ea_set.in.eas[0].flags = 0;
191                 setfile.ea_set.in.eas[0].name.s = "EAONE";
192                 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
193                 setfile.ea_set.in.eas[1].flags = 0;
194                 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
195                 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
196                 status = smb_raw_setfileinfo(cli->tree, &setfile);
197                 if (!NT_STATUS_IS_OK(status)) {
198                         printf("Failed to setup EAs\n");
199                 }
200         }
201
202         /* make sure all the timestamps aren't the same, and are also 
203            in different DST zones*/
204         setfile.generic.level = RAW_SFILEINFO_SETATTRE;
205         setfile.generic.in.file.fnum = fnum;
206
207         setfile.setattre.in.create_time = t + 9*30*24*60*60;
208         setfile.setattre.in.access_time = t + 6*30*24*60*60;
209         setfile.setattre.in.write_time  = t + 3*30*24*60*60;
210
211         status = smb_raw_setfileinfo(cli->tree, &setfile);
212         if (!NT_STATUS_IS_OK(status)) {
213                 printf("Failed to setup file times - %s\n", nt_errstr(status));
214         }
215
216         /* make sure all the timestamps aren't the same */
217         fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
218         fileinfo.generic.in.file.fnum = fnum;
219
220         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
221         if (!NT_STATUS_IS_OK(status)) {
222                 printf("Failed to query file times - %s\n", nt_errstr(status));
223         }
224
225         if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
226                 printf("create_time not setup correctly\n");
227         }
228         if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
229                 printf("access_time not setup correctly\n");
230         }
231         if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
232                 printf("write_time not setup correctly\n");
233         }
234
235         return fnum;
236 }
237
238
239
240 /* return a pointer to a anonymous shared memory segment of size "size"
241    which will persist across fork() but will disappear when all processes
242    exit 
243
244    The memory is not zeroed 
245
246    This function uses system5 shared memory. It takes advantage of a property
247    that the memory is not destroyed if it is attached when the id is removed
248    */
249 void *shm_setup(int size)
250 {
251         int shmid;
252         void *ret;
253
254         shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
255         if (shmid == -1) {
256                 printf("can't get shared memory\n");
257                 exit(1);
258         }
259         ret = (void *)shmat(shmid, 0, 0);
260         if (!ret || ret == (void *)-1) {
261                 printf("can't attach to shared memory\n");
262                 return NULL;
263         }
264         /* the following releases the ipc, but note that this process
265            and all its children will still have access to the memory, its
266            just that the shmid is no longer valid for other shm calls. This
267            means we don't leave behind lots of shm segments after we exit 
268
269            See Stevens "advanced programming in unix env" for details
270            */
271         shmctl(shmid, IPC_RMID, 0);
272         
273         return ret;
274 }
275
276
277 /*
278   check that a wire string matches the flags specified 
279   not 100% accurate, but close enough for testing
280 */
281 BOOL wire_bad_flags(struct smb_wire_string *str, int flags, struct smbcli_state *cli)
282 {
283         BOOL server_unicode;
284         int len;
285         if (!str || !str->s) return True;
286         len = strlen(str->s);
287         if (flags & STR_TERMINATE) len++;
288
289         server_unicode = (cli->transport->negotiate.capabilities&CAP_UNICODE)?True:False;
290         if (getenv("CLI_FORCE_ASCII") || !lp_unicode()) {
291                 server_unicode = False;
292         }
293
294         if ((flags & STR_UNICODE) || server_unicode) {
295                 len *= 2;
296         } else if (flags & STR_TERMINATE_ASCII) {
297                 len++;
298         }
299         if (str->private_length != len) {
300                 printf("Expected wire_length %d but got %d for '%s'\n", 
301                        len, str->private_length, str->s);
302                 return True;
303         }
304         return False;
305 }
306
307 /*
308   check if 2 NTTIMEs are equal
309 */
310 BOOL nt_time_equal(NTTIME *t1, NTTIME *t2)
311 {
312         return *t1 == *t2;
313 }
314
315 /*
316   dump a all_info QFILEINFO structure
317 */
318 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
319 {
320         d_printf("\tcreate_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
321         d_printf("\taccess_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
322         d_printf("\twrite_time:     %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
323         d_printf("\tchange_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
324         d_printf("\tattrib:         0x%x\n", finfo->all_info.out.attrib);
325         d_printf("\talloc_size:     %llu\n", (long long)finfo->all_info.out.alloc_size);
326         d_printf("\tsize:           %llu\n", (long long)finfo->all_info.out.size);
327         d_printf("\tnlink:          %u\n", finfo->all_info.out.nlink);
328         d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
329         d_printf("\tdirectory:      %u\n", finfo->all_info.out.directory);
330         d_printf("\tea_size:        %u\n", finfo->all_info.out.ea_size);
331         d_printf("\tfname:          '%s'\n", finfo->all_info.out.fname.s);
332 }
333
334 /*
335   dump file infor by name
336 */
337 void torture_all_info(struct smbcli_tree *tree, const char *fname)
338 {
339         TALLOC_CTX *mem_ctx = talloc_init("%s", fname);
340         union smb_fileinfo finfo;
341         NTSTATUS status;
342
343         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
344         finfo.generic.in.file.path = fname;
345         status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
346         if (!NT_STATUS_IS_OK(status)) {
347                 d_printf("%s - %s\n", fname, nt_errstr(status));
348                 return;
349         }
350
351         d_printf("%s:\n", fname);
352         dump_all_info(mem_ctx, &finfo);
353         talloc_free(mem_ctx);
354 }
355
356
357 /*
358   set a attribute on a file
359 */
360 BOOL torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
361 {
362         union smb_setfileinfo sfinfo;
363         NTSTATUS status;
364
365         ZERO_STRUCT(sfinfo.basic_info.in);
366         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
367         sfinfo.basic_info.in.file.path = fname;
368         sfinfo.basic_info.in.attrib = attrib;
369         status = smb_raw_setpathinfo(tree, &sfinfo);
370         return NT_STATUS_IS_OK(status);
371 }
372
373
374 /*
375   set a file descriptor as sparse
376 */
377 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
378 {
379         union smb_ioctl nt;
380         NTSTATUS status;
381         TALLOC_CTX *mem_ctx;
382
383         mem_ctx = talloc_init("torture_set_sparse");
384         if (!mem_ctx) {
385                 return NT_STATUS_NO_MEMORY;
386         }
387
388         nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
389         nt.ntioctl.in.function = FSCTL_SET_SPARSE;
390         nt.ntioctl.in.file.fnum = fnum;
391         nt.ntioctl.in.fsctl = True;
392         nt.ntioctl.in.filter = 0;
393         nt.ntioctl.in.max_data = 0;
394         nt.ntioctl.in.blob = data_blob(NULL, 0);
395
396         status = smb_raw_ioctl(tree, mem_ctx, &nt);
397
398         talloc_free(mem_ctx);
399
400         return status;
401 }
402
403 /*
404   check that an EA has the right value 
405 */
406 NTSTATUS torture_check_ea(struct smbcli_state *cli, 
407                           const char *fname, const char *eaname, const char *value)
408 {
409         union smb_fileinfo info;
410         NTSTATUS status;
411         struct ea_name ea;
412         TALLOC_CTX *mem_ctx = talloc_new(cli);
413
414         info.ea_list.level = RAW_FILEINFO_EA_LIST;
415         info.ea_list.in.file.path = fname;
416         info.ea_list.in.num_names = 1;
417         info.ea_list.in.ea_names = &ea;
418
419         ea.name.s = eaname;
420
421         status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
422         if (!NT_STATUS_IS_OK(status)) {
423                 talloc_free(mem_ctx);
424                 return status;
425         }
426
427         if (info.ea_list.out.num_eas != 1) {
428                 printf("Expected 1 ea in ea_list\n");
429                 talloc_free(mem_ctx);
430                 return NT_STATUS_EA_CORRUPT_ERROR;
431         }
432
433         if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
434                 printf("Expected ea '%s' not '%s' in ea_list\n",
435                        eaname, info.ea_list.out.eas[0].name.s);
436                 talloc_free(mem_ctx);
437                 return NT_STATUS_EA_CORRUPT_ERROR;
438         }
439
440         if (value == NULL) {
441                 if (info.ea_list.out.eas[0].value.length != 0) {
442                         printf("Expected zero length ea for %s\n", eaname);
443                         talloc_free(mem_ctx);
444                         return NT_STATUS_EA_CORRUPT_ERROR;
445                 }
446                 talloc_free(mem_ctx);
447                 return NT_STATUS_OK;
448         }
449
450         if (strlen(value) == info.ea_list.out.eas[0].value.length &&
451             memcmp(value, info.ea_list.out.eas[0].value.data,
452                    info.ea_list.out.eas[0].value.length) == 0) {
453                 talloc_free(mem_ctx);
454                 return NT_STATUS_OK;
455         }
456
457         printf("Expected value '%s' not '%*.*s' for ea %s\n",
458                value, 
459                (int)info.ea_list.out.eas[0].value.length,
460                (int)info.ea_list.out.eas[0].value.length,
461                info.ea_list.out.eas[0].value.data,
462                eaname);
463
464         talloc_free(mem_ctx);
465
466         return NT_STATUS_EA_CORRUPT_ERROR;
467 }
468
469 BOOL torture_open_connection_share(TALLOC_CTX *mem_ctx,
470                                    struct smbcli_state **c, 
471                                    const char *hostname, 
472                                    const char *sharename,
473                                    struct event_context *ev)
474 {
475         NTSTATUS status;
476
477         status = smbcli_full_connection(mem_ctx, c, hostname, 
478                                         sharename, NULL,
479                                         cmdline_credentials, ev);
480         if (!NT_STATUS_IS_OK(status)) {
481                 printf("Failed to open connection - %s\n", nt_errstr(status));
482                 return False;
483         }
484
485         (*c)->transport->options.use_oplocks = use_oplocks;
486         (*c)->transport->options.use_level2_oplocks = use_level_II_oplocks;
487
488         return True;
489 }
490
491 _PUBLIC_ BOOL torture_open_connection(struct smbcli_state **c)
492 {
493         const char *host = lp_parm_string(-1, "torture", "host");
494         const char *share = lp_parm_string(-1, "torture", "share");
495
496         return torture_open_connection_share(NULL, c, host, share, NULL);
497 }
498
499 _PUBLIC_ BOOL torture_open_connection_ev(struct smbcli_state **c, 
500                                          struct event_context *ev)
501 {
502         const char *host = lp_parm_string(-1, "torture", "host");
503         const char *share = lp_parm_string(-1, "torture", "share");
504
505         return torture_open_connection_share(NULL, c, host, share, ev);
506 }
507
508
509
510 _PUBLIC_ BOOL torture_close_connection(struct smbcli_state *c)
511 {
512         BOOL ret = True;
513         if (!c) return True;
514         if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
515                 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
516                 ret = False;
517         }
518         talloc_free(c);
519         return ret;
520 }
521
522
523 /* check if the server produced the expected error code */
524 _PUBLIC_ BOOL check_error(const char *location, struct smbcli_state *c, 
525                  uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
526 {
527         NTSTATUS status;
528         
529         status = smbcli_nt_error(c->tree);
530         if (NT_STATUS_IS_DOS(status)) {
531                 int class, num;
532                 class = NT_STATUS_DOS_CLASS(status);
533                 num = NT_STATUS_DOS_CODE(status);
534                 if (eclass != class || ecode != num) {
535                         printf("unexpected error code %s\n", nt_errstr(status));
536                         printf(" expected %s or %s (at %s)\n", 
537                                nt_errstr(NT_STATUS_DOS(eclass, ecode)), 
538                                nt_errstr(nterr), location);
539                         return False;
540                 }
541         } else {
542                 if (!NT_STATUS_EQUAL(nterr, status)) {
543                         printf("unexpected error code %s\n", nt_errstr(status));
544                         printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
545                         return False;
546                 }
547         }
548
549         return True;
550 }
551
552