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