r5037: got rid of all of the TALLOC_DEPRECATED stuff. My apologies for the
[ab/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 #include "librpc/gen_ndr/ndr_security.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 int create_directory_handle(struct smbcli_tree *tree, const char *dname)
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_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_CREATE;
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         if (!NT_STATUS_IS_OK(status)) {
68                 talloc_free(mem_ctx);
69                 return -1;
70         }
71
72         talloc_free(mem_ctx);
73         return io.ntcreatex.out.fnum;
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         /* setup some EAs */
103         setfile.generic.level = RAW_SFILEINFO_EA_SET;
104         setfile.generic.file.fnum = fnum;
105         setfile.ea_set.in.num_eas = 2;  
106         setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
107         setfile.ea_set.in.eas[0].flags = 0;
108         setfile.ea_set.in.eas[0].name.s = "EAONE";
109         setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
110         setfile.ea_set.in.eas[1].flags = 0;
111         setfile.ea_set.in.eas[1].name.s = "SECONDEA";
112         setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
113         status = smb_raw_setfileinfo(cli->tree, &setfile);
114         if (!NT_STATUS_IS_OK(status)) {
115                 printf("Failed to setup EAs\n");
116         }
117
118         /* make sure all the timestamps aren't the same, and are also 
119            in different DST zones*/
120         setfile.generic.level = RAW_SFILEINFO_SETATTRE;
121         setfile.generic.file.fnum = fnum;
122
123         setfile.setattre.in.create_time = t + 9*30*24*60*60;
124         setfile.setattre.in.access_time = t + 6*30*24*60*60;
125         setfile.setattre.in.write_time  = t + 3*30*24*60*60;
126
127         status = smb_raw_setfileinfo(cli->tree, &setfile);
128         if (!NT_STATUS_IS_OK(status)) {
129                 printf("Failed to setup file times - %s\n", nt_errstr(status));
130         }
131
132         /* make sure all the timestamps aren't the same */
133         fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
134         fileinfo.generic.in.fnum = fnum;
135
136         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
137         if (!NT_STATUS_IS_OK(status)) {
138                 printf("Failed to query file times - %s\n", nt_errstr(status));
139         }
140
141         if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
142                 printf("create_time not setup correctly\n");
143         }
144         if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
145                 printf("access_time not setup correctly\n");
146         }
147         if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
148                 printf("write_time not setup correctly\n");
149         }
150
151         return fnum;
152 }
153
154
155
156 /* return a pointer to a anonymous shared memory segment of size "size"
157    which will persist across fork() but will disappear when all processes
158    exit 
159
160    The memory is not zeroed 
161
162    This function uses system5 shared memory. It takes advantage of a property
163    that the memory is not destroyed if it is attached when the id is removed
164    */
165 void *shm_setup(int size)
166 {
167         int shmid;
168         void *ret;
169
170         shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
171         if (shmid == -1) {
172                 printf("can't get shared memory\n");
173                 exit(1);
174         }
175         ret = (void *)shmat(shmid, 0, 0);
176         if (!ret || ret == (void *)-1) {
177                 printf("can't attach to shared memory\n");
178                 return NULL;
179         }
180         /* the following releases the ipc, but note that this process
181            and all its children will still have access to the memory, its
182            just that the shmid is no longer valid for other shm calls. This
183            means we don't leave behind lots of shm segments after we exit 
184
185            See Stevens "advanced programming in unix env" for details
186            */
187         shmctl(shmid, IPC_RMID, 0);
188         
189         return ret;
190 }
191
192
193 /*
194   check that a wire string matches the flags specified 
195   not 100% accurate, but close enough for testing
196 */
197 BOOL wire_bad_flags(WIRE_STRING *str, int flags, struct smbcli_state *cli)
198 {
199         BOOL server_unicode;
200         int len;
201         if (!str || !str->s) return True;
202         len = strlen(str->s);
203         if (flags & STR_TERMINATE) len++;
204
205         server_unicode = (cli->transport->negotiate.capabilities&CAP_UNICODE)?True:False;
206         if (getenv("CLI_FORCE_ASCII") || !lp_unicode()) {
207                 server_unicode = False;
208         }
209
210         if ((flags & STR_UNICODE) || server_unicode) {
211                 len *= 2;
212         } else if (flags & STR_TERMINATE_ASCII) {
213                 len++;
214         }
215         if (str->private_length != len) {
216                 printf("Expected wire_length %d but got %d for '%s'\n", 
217                        len, str->private_length, str->s);
218                 return True;
219         }
220         return False;
221 }
222
223 /*
224   check if 2 NTTIMEs are equal
225 */
226 BOOL nt_time_equal(NTTIME *t1, NTTIME *t2)
227 {
228         return *t1 == *t2;
229 }
230
231 /*
232   dump a all_info QFILEINFO structure
233 */
234 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
235 {
236         d_printf("\tcreate_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
237         d_printf("\taccess_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
238         d_printf("\twrite_time:     %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
239         d_printf("\tchange_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
240         d_printf("\tattrib:         0x%x\n", finfo->all_info.out.attrib);
241         d_printf("\talloc_size:     %llu\n", (uint64_t)finfo->all_info.out.alloc_size);
242         d_printf("\tsize:           %llu\n", (uint64_t)finfo->all_info.out.size);
243         d_printf("\tnlink:          %u\n", finfo->all_info.out.nlink);
244         d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
245         d_printf("\tdirectory:      %u\n", finfo->all_info.out.directory);
246         d_printf("\tea_size:        %u\n", finfo->all_info.out.ea_size);
247         d_printf("\tfname:          '%s'\n", finfo->all_info.out.fname.s);
248 }
249
250 /*
251   dump file infor by name
252 */
253 void torture_all_info(struct smbcli_tree *tree, const char *fname)
254 {
255         TALLOC_CTX *mem_ctx = talloc_init("%s", fname);
256         union smb_fileinfo finfo;
257         NTSTATUS status;
258
259         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
260         finfo.generic.in.fname = fname;
261         status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
262         if (!NT_STATUS_IS_OK(status)) {
263                 d_printf("%s - %s\n", fname, nt_errstr(status));
264                 return;
265         }
266
267         d_printf("%s:\n", fname);
268         dump_all_info(mem_ctx, &finfo);
269         talloc_free(mem_ctx);
270 }
271
272
273 /*
274   split a UNC name into server and share names
275 */
276 BOOL split_unc_name(const char *unc, char **server, char **share)
277 {
278         char *p = strdup(unc);
279         if (!p) return False;
280         all_string_sub(p, "\\", "/", 0);
281         if (strncmp(p, "//", 2) != 0) return False;
282
283         (*server) = p+2;
284         p = strchr(*server, '/');
285         if (!p) return False;
286
287         *p = 0;
288         (*share) = p+1;
289         
290         return True;
291 }
292
293 /*
294   split a USER%PASS pair into username and password
295 */
296 BOOL split_username(const char *pair, char **user, char **pass)
297 {
298         char *p = strdup(pair);
299         if (!p) return False;
300
301         (*user) = p;
302
303         p = strchr(*user, '%');
304         if (!p) return False;
305
306         *p = 0;
307         (*pass) = p+1;
308         
309         return True;
310 }
311
312 /*
313   set a attribute on a file
314 */
315 BOOL torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
316 {
317         union smb_setfileinfo sfinfo;
318         NTSTATUS status;
319
320         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
321         sfinfo.generic.file.fname = fname;
322
323         ZERO_STRUCT(sfinfo.basic_info.in);
324         sfinfo.basic_info.in.attrib = attrib;
325         status = smb_raw_setpathinfo(tree, &sfinfo);
326         return NT_STATUS_IS_OK(status);
327 }
328
329
330 /*
331   set a file descriptor as sparse
332 */
333 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
334 {
335         union smb_ioctl nt;
336         NTSTATUS status;
337         TALLOC_CTX *mem_ctx;
338
339         mem_ctx = talloc_init("torture_set_sparse");
340         if (!mem_ctx) {
341                 return NT_STATUS_NO_MEMORY;
342         }
343
344         nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
345         nt.ntioctl.in.function = 0x900c4;
346         nt.ntioctl.in.fnum = fnum;
347         nt.ntioctl.in.fsctl = True;
348         nt.ntioctl.in.filter = 0;
349
350         status = smb_raw_ioctl(tree, mem_ctx, &nt);
351
352         talloc_free(mem_ctx);
353
354         return status;
355 }
356
357 /*
358   check that an EA has the right value 
359 */
360 NTSTATUS torture_check_ea(struct smbcli_state *cli, 
361                           const char *fname, const char *eaname, const char *value)
362 {
363         union smb_fileinfo info;
364         NTSTATUS status;
365         struct ea_name ea;
366         TALLOC_CTX *mem_ctx = talloc_new(cli);
367
368         info.ea_list.level = RAW_FILEINFO_EA_LIST;
369         info.ea_list.file.fname = fname;
370         info.ea_list.in.num_names = 1;
371         info.ea_list.in.ea_names = &ea;
372
373         ea.name.s = eaname;
374
375         status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
376         if (!NT_STATUS_IS_OK(status)) {
377                 talloc_free(mem_ctx);
378                 return status;
379         }
380
381         if (info.ea_list.out.num_eas != 1) {
382                 printf("Expected 1 ea in ea_list\n");
383                 talloc_free(mem_ctx);
384                 return NT_STATUS_EA_CORRUPT_ERROR;
385         }
386
387         if (StrCaseCmp(eaname, info.ea_list.out.eas[0].name.s) != 0) {
388                 printf("Expected ea '%s' not '%s' in ea_list\n",
389                        eaname, info.ea_list.out.eas[0].name.s);
390                 talloc_free(mem_ctx);
391                 return NT_STATUS_EA_CORRUPT_ERROR;
392         }
393
394         if (value == NULL) {
395                 if (info.ea_list.out.eas[0].value.length != 0) {
396                         printf("Expected zero length ea for %s\n", eaname);
397                         talloc_free(mem_ctx);
398                         return NT_STATUS_EA_CORRUPT_ERROR;
399                 }
400                 talloc_free(mem_ctx);
401                 return NT_STATUS_OK;
402         }
403
404         if (strlen(value) == info.ea_list.out.eas[0].value.length &&
405             memcmp(value, info.ea_list.out.eas[0].value.data,
406                    info.ea_list.out.eas[0].value.length) == 0) {
407                 talloc_free(mem_ctx);
408                 return NT_STATUS_OK;
409         }
410
411         printf("Expected value '%s' not '%*.*s' for ea %s\n",
412                value, 
413                info.ea_list.out.eas[0].value.length,
414                info.ea_list.out.eas[0].value.length,
415                info.ea_list.out.eas[0].value.data,
416                eaname);
417
418         talloc_free(mem_ctx);
419
420         return NT_STATUS_EA_CORRUPT_ERROR;
421 }
422