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