22aa9ffedd39e7a2ae35a1d06f1a1cf0e076c5df
[gd/samba-autobuild/.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   create a directory, returning a handle to it
29 */
30 int create_directory_handle(struct smbcli_tree *tree, const char *dname)
31 {
32         NTSTATUS status;
33         union smb_open io;
34         TALLOC_CTX *mem_ctx;
35
36         mem_ctx = talloc_init("create_directory_handle");
37
38         io.generic.level = RAW_OPEN_NTCREATEX;
39         io.ntcreatex.in.root_fid = 0;
40         io.ntcreatex.in.flags = 0;
41         io.ntcreatex.in.access_mask = SA_RIGHT_FILE_ALL_ACCESS;
42         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
43         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
44         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
45         io.ntcreatex.in.alloc_size = 0;
46         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
47         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
48         io.ntcreatex.in.security_flags = 0;
49         io.ntcreatex.in.fname = dname;
50
51         status = smb_raw_open(tree, mem_ctx, &io);
52         if (!NT_STATUS_IS_OK(status)) {
53                 talloc_destroy(mem_ctx);
54                 return -1;
55         }
56
57         talloc_destroy(mem_ctx);
58         return io.ntcreatex.out.fnum;
59 }
60
61 /*
62   sometimes we need a fairly complex file to work with, so we can test
63   all possible attributes. 
64 */
65 int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
66 {
67         int fnum;
68         char buf[7] = "abc";
69         union smb_setfileinfo setfile;
70         union smb_fileinfo fileinfo;
71         time_t t = (time(NULL) & ~1);
72         NTSTATUS status;
73
74         smbcli_unlink(cli->tree, fname);
75         fnum = smbcli_nt_create_full(cli->tree, fname, 0, GENERIC_RIGHTS_FILE_ALL_ACCESS,
76                                   FILE_ATTRIBUTE_NORMAL,
77                                   NTCREATEX_SHARE_ACCESS_DELETE|
78                                   NTCREATEX_SHARE_ACCESS_READ|
79                                   NTCREATEX_SHARE_ACCESS_WRITE, 
80                                   NTCREATEX_DISP_OVERWRITE_IF,
81                                   0, 0);
82         if (fnum == -1) return -1;
83
84         smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
85
86         /* setup some EAs */
87         setfile.generic.level = RAW_SFILEINFO_EA_SET;
88         setfile.generic.file.fnum = fnum;
89         setfile.ea_set.in.ea.flags = 0;
90         setfile.ea_set.in.ea.name.s = "EAONE";
91         setfile.ea_set.in.ea.value = data_blob_talloc(mem_ctx, "VALUE1", 6);
92
93         status = smb_raw_setfileinfo(cli->tree, &setfile);
94         if (!NT_STATUS_IS_OK(status)) {
95                 printf("Failed to setup EAs\n");
96         }
97
98         setfile.ea_set.in.ea.name.s = "SECONDEA";
99         setfile.ea_set.in.ea.value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
100         status = smb_raw_setfileinfo(cli->tree, &setfile);
101         if (!NT_STATUS_IS_OK(status)) {
102                 printf("Failed to setup EAs\n");
103         }
104
105         /* make sure all the timestamps aren't the same, and are also 
106            in different DST zones*/
107         setfile.generic.level = RAW_SFILEINFO_SETATTRE;
108         setfile.generic.file.fnum = fnum;
109
110         setfile.setattre.in.create_time = t + 9*30*24*60*60;
111         setfile.setattre.in.access_time = t + 6*30*24*60*60;
112         setfile.setattre.in.write_time  = t + 3*30*24*60*60;
113
114         status = smb_raw_setfileinfo(cli->tree, &setfile);
115         if (!NT_STATUS_IS_OK(status)) {
116                 printf("Failed to setup file times - %s\n", nt_errstr(status));
117         }
118
119         /* make sure all the timestamps aren't the same */
120         fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
121         fileinfo.generic.in.fnum = fnum;
122
123         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
124         if (!NT_STATUS_IS_OK(status)) {
125                 printf("Failed to query file times - %s\n", nt_errstr(status));
126         }
127
128         if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
129                 printf("create_time not setup correctly\n");
130         }
131         if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
132                 printf("access_time not setup correctly\n");
133         }
134         if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
135                 printf("write_time not setup correctly\n");
136         }
137
138         return fnum;
139 }
140
141
142
143 /* return a pointer to a anonymous shared memory segment of size "size"
144    which will persist across fork() but will disappear when all processes
145    exit 
146
147    The memory is not zeroed 
148
149    This function uses system5 shared memory. It takes advantage of a property
150    that the memory is not destroyed if it is attached when the id is removed
151    */
152 void *shm_setup(int size)
153 {
154         int shmid;
155         void *ret;
156
157         shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
158         if (shmid == -1) {
159                 printf("can't get shared memory\n");
160                 exit(1);
161         }
162         ret = (void *)shmat(shmid, 0, 0);
163         if (!ret || ret == (void *)-1) {
164                 printf("can't attach to shared memory\n");
165                 return NULL;
166         }
167         /* the following releases the ipc, but note that this process
168            and all its children will still have access to the memory, its
169            just that the shmid is no longer valid for other shm calls. This
170            means we don't leave behind lots of shm segments after we exit 
171
172            See Stevens "advanced programming in unix env" for details
173            */
174         shmctl(shmid, IPC_RMID, 0);
175         
176         return ret;
177 }
178
179
180 /*
181   check that a wire string matches the flags specified 
182   not 100% accurate, but close enough for testing
183 */
184 BOOL wire_bad_flags(WIRE_STRING *str, int flags, struct smbcli_state *cli)
185 {
186         BOOL server_unicode;
187         int len;
188         if (!str || !str->s) return True;
189         len = strlen(str->s);
190         if (flags & STR_TERMINATE) len++;
191
192         server_unicode = (cli->transport->negotiate.capabilities&CAP_UNICODE)?True:False;
193         if (getenv("CLI_FORCE_ASCII") || !lp_unicode()) {
194                 server_unicode = False;
195         }
196
197         if ((flags & STR_UNICODE) || server_unicode) {
198                 len *= 2;
199         } else if (flags & STR_TERMINATE_ASCII) {
200                 len++;
201         }
202         if (str->private_length != len) {
203                 printf("Expected wire_length %d but got %d for '%s'\n", 
204                        len, str->private_length, str->s);
205                 return True;
206         }
207         return False;
208 }
209
210 /*
211   check if 2 NTTIMEs are equal
212 */
213 BOOL nt_time_equal(NTTIME *t1, NTTIME *t2)
214 {
215         return *t1 == *t2;
216 }
217
218 /*
219   dump a all_info QFILEINFO structure
220 */
221 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
222 {
223         d_printf("\tcreate_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
224         d_printf("\taccess_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
225         d_printf("\twrite_time:     %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
226         d_printf("\tchange_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
227         d_printf("\tattrib:         0x%x\n", finfo->all_info.out.attrib);
228         d_printf("\talloc_size:     %llu\n", (uint64_t)finfo->all_info.out.alloc_size);
229         d_printf("\tsize:           %llu\n", (uint64_t)finfo->all_info.out.size);
230         d_printf("\tnlink:          %u\n", finfo->all_info.out.nlink);
231         d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
232         d_printf("\tdirectory:      %u\n", finfo->all_info.out.directory);
233         d_printf("\tea_size:        %u\n", finfo->all_info.out.ea_size);
234         d_printf("\tfname:          '%s'\n", finfo->all_info.out.fname.s);
235 }
236
237 /*
238   dump file infor by name
239 */
240 void torture_all_info(struct smbcli_tree *tree, const char *fname)
241 {
242         TALLOC_CTX *mem_ctx = talloc_init("%s", fname);
243         union smb_fileinfo finfo;
244         NTSTATUS status;
245
246         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
247         finfo.generic.in.fname = fname;
248         status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
249         if (!NT_STATUS_IS_OK(status)) {
250                 d_printf("%s - %s\n", fname, nt_errstr(status));
251                 return;
252         }
253
254         d_printf("%s:\n", fname);
255         dump_all_info(mem_ctx, &finfo);
256         talloc_destroy(mem_ctx);
257 }
258
259
260 /*
261   split a UNC name into server and share names
262 */
263 BOOL split_unc_name(const char *unc, char **server, char **share)
264 {
265         char *p = strdup(unc);
266         if (!p) return False;
267         all_string_sub(p, "\\", "/", 0);
268         if (strncmp(p, "//", 2) != 0) return False;
269
270         (*server) = p+2;
271         p = strchr(*server, '/');
272         if (!p) return False;
273
274         *p = 0;
275         (*share) = p+1;
276         
277         return True;
278 }
279
280 /*
281   split a USER%PASS pair into username and password
282 */
283 BOOL split_username(const char *pair, char **user, char **pass)
284 {
285         char *p = strdup(pair);
286         if (!p) return False;
287
288         (*user) = p;
289
290         p = strchr(*user, '%');
291         if (!p) return False;
292
293         *p = 0;
294         (*pass) = p+1;
295         
296         return True;
297 }
298
299 /*
300   set a attribute on a file
301 */
302 BOOL torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
303 {
304         union smb_setfileinfo sfinfo;
305         NTSTATUS status;
306
307         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
308         sfinfo.generic.file.fname = fname;
309
310         ZERO_STRUCT(sfinfo.basic_info.in);
311         sfinfo.basic_info.in.attrib = attrib;
312         status = smb_raw_setpathinfo(tree, &sfinfo);
313         return NT_STATUS_IS_OK(status);
314 }
315
316
317 /*
318   set a file descriptor as sparse
319 */
320 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
321 {
322         union smb_ioctl nt;
323         NTSTATUS status;
324         TALLOC_CTX *mem_ctx;
325
326         mem_ctx = talloc_init("torture_set_sparse");
327         if (!mem_ctx) {
328                 return NT_STATUS_NO_MEMORY;
329         }
330
331         nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
332         nt.ntioctl.in.function = 0x900c4;
333         nt.ntioctl.in.fnum = fnum;
334         nt.ntioctl.in.fsctl = True;
335         nt.ntioctl.in.filter = 0;
336
337         status = smb_raw_ioctl(tree, mem_ctx, &nt);
338
339         talloc_destroy(mem_ctx);
340
341         return status;
342 }