4995bbe978bb11473d3994300523f1dab961e918
[kai/samba.git] / source4 / torture / smb2 / util.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    helper functions for SMB2 test suite
5
6    Copyright (C) Andrew Tridgell 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25 #include "libcli/smb_composite/smb_composite.h"
26 #include "lib/cmdline/popt_common.h"
27 #include "lib/events/events.h"
28 #include "system/time.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "param/param.h"
31 #include "libcli/resolve/resolve.h"
32
33 #include "torture/torture.h"
34 #include "torture/smb2/proto.h"
35
36
37 /*
38   close a handle with SMB2
39 */
40 NTSTATUS smb2_util_close(struct smb2_tree *tree, struct smb2_handle h)
41 {
42         struct smb2_close c;
43
44         ZERO_STRUCT(c);
45         c.in.file.handle = h;
46
47         return smb2_close(tree, &c);
48 }
49
50 /*
51   unlink a file with SMB2
52 */
53 NTSTATUS smb2_util_unlink(struct smb2_tree *tree, const char *fname)
54 {
55         union smb_unlink io;
56         
57         ZERO_STRUCT(io);
58         io.unlink.in.pattern = fname;
59
60         return smb2_composite_unlink(tree, &io);
61 }
62
63 /*
64   write to a file on SMB2
65 */
66 NTSTATUS smb2_util_write(struct smb2_tree *tree,
67                          struct smb2_handle handle, 
68                          const void *buf, off_t offset, size_t size)
69 {
70         struct smb2_write w;
71
72         ZERO_STRUCT(w);
73         w.in.file.handle = handle;
74         w.in.offset      = offset;
75         w.in.data        = data_blob_const(buf, size);
76
77         return smb2_write(tree, &w);
78 }
79
80 /*
81   create a complex file/dir using the SMB2 protocol
82 */
83 static NTSTATUS smb2_create_complex(struct smb2_tree *tree, const char *fname, 
84                                          struct smb2_handle *handle, bool dir)
85 {
86         TALLOC_CTX *tmp_ctx = talloc_new(tree);
87         char buf[7] = "abc";
88         struct smb2_create io;
89         union smb_setfileinfo setfile;
90         union smb_fileinfo fileinfo;
91         time_t t = (time(NULL) & ~1);
92         NTSTATUS status;
93
94         smb2_util_unlink(tree, fname);
95         ZERO_STRUCT(io);
96         io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
97         io.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
98         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
99         io.in.share_access = 
100                 NTCREATEX_SHARE_ACCESS_DELETE|
101                 NTCREATEX_SHARE_ACCESS_READ|
102                 NTCREATEX_SHARE_ACCESS_WRITE;
103         io.in.create_options = 0;
104         io.in.fname = fname;
105         if (dir) {
106                 io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
107                 io.in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE;
108                 io.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
109                 io.in.create_disposition = NTCREATEX_DISP_CREATE;
110         }
111
112         /* it seems vista is now fussier about alignment? */
113         if (strchr(fname, ':') == NULL) {
114                 /* setup some EAs */
115                 io.in.eas.num_eas = 2;
116                 io.in.eas.eas = talloc_array(tmp_ctx, struct ea_struct, 2);
117                 io.in.eas.eas[0].flags = 0;
118                 io.in.eas.eas[0].name.s = "EAONE";
119                 io.in.eas.eas[0].value = data_blob_talloc(tmp_ctx, "VALUE1", 6);
120                 io.in.eas.eas[1].flags = 0;
121                 io.in.eas.eas[1].name.s = "SECONDEA";
122                 io.in.eas.eas[1].value = data_blob_talloc(tmp_ctx, "ValueTwo", 8);
123         }
124
125         status = smb2_create(tree, tmp_ctx, &io);
126         talloc_free(tmp_ctx);
127         NT_STATUS_NOT_OK_RETURN(status);
128
129         *handle = io.out.file.handle;
130
131         if (!dir) {
132                 status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
133                 NT_STATUS_NOT_OK_RETURN(status);
134         }
135
136         /* make sure all the timestamps aren't the same, and are also 
137            in different DST zones*/
138         setfile.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
139         setfile.generic.in.file.handle = *handle;
140
141         unix_to_nt_time(&setfile.basic_info.in.create_time, t + 9*30*24*60*60);
142         unix_to_nt_time(&setfile.basic_info.in.access_time, t + 6*30*24*60*60);
143         unix_to_nt_time(&setfile.basic_info.in.write_time,  t + 3*30*24*60*60);
144         unix_to_nt_time(&setfile.basic_info.in.change_time, t + 1*30*24*60*60);
145         setfile.basic_info.in.attrib      = FILE_ATTRIBUTE_NORMAL;
146
147         status = smb2_setinfo_file(tree, &setfile);
148         if (!NT_STATUS_IS_OK(status)) {
149                 printf("Failed to setup file times - %s\n", nt_errstr(status));
150                 return status;
151         }
152
153         /* make sure all the timestamps aren't the same */
154         fileinfo.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
155         fileinfo.generic.in.file.handle = *handle;
156
157         status = smb2_getinfo_file(tree, tree, &fileinfo);
158         if (!NT_STATUS_IS_OK(status)) {
159                 printf("Failed to query file times - %s\n", nt_errstr(status));
160                 return status;
161                 
162         }
163
164 #define CHECK_TIME(field) do {\
165         if (setfile.basic_info.in.field != fileinfo.all_info2.out.field) { \
166                 printf("(%s) " #field " not setup correctly: %s(%llu) => %s(%llu)\n", \
167                         __location__, \
168                         nt_time_string(tree, setfile.basic_info.in.field), \
169                         (unsigned long long)setfile.basic_info.in.field, \
170                         nt_time_string(tree, fileinfo.basic_info.out.field), \
171                         (unsigned long long)fileinfo.basic_info.out.field); \
172                 status = NT_STATUS_INVALID_PARAMETER; \
173         } \
174 } while (0)
175
176         CHECK_TIME(create_time);
177         CHECK_TIME(access_time);
178         CHECK_TIME(write_time);
179         CHECK_TIME(change_time);
180
181         return status;
182 }
183
184 /*
185   create a complex file using the SMB2 protocol
186 */
187 NTSTATUS smb2_create_complex_file(struct smb2_tree *tree, const char *fname, 
188                                          struct smb2_handle *handle)
189 {
190         return smb2_create_complex(tree, fname, handle, false);
191 }
192
193 /*
194   create a complex dir using the SMB2 protocol
195 */
196 NTSTATUS smb2_create_complex_dir(struct smb2_tree *tree, const char *fname, 
197                                  struct smb2_handle *handle)
198 {
199         return smb2_create_complex(tree, fname, handle, true);
200 }
201
202 /*
203   show lots of information about a file
204 */
205 void torture_smb2_all_info(struct smb2_tree *tree, struct smb2_handle handle)
206 {
207         NTSTATUS status;
208         TALLOC_CTX *tmp_ctx = talloc_new(tree);
209         union smb_fileinfo io;
210
211         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
212         io.generic.in.file.handle = handle;
213
214         status = smb2_getinfo_file(tree, tmp_ctx, &io);
215         if (!NT_STATUS_IS_OK(status)) {
216                 DEBUG(0,("getinfo failed - %s\n", nt_errstr(status)));
217                 talloc_free(tmp_ctx);
218                 return;
219         }
220
221         d_printf("all_info for '%s'\n", io.all_info2.out.fname.s);
222         d_printf("\tcreate_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.create_time));
223         d_printf("\taccess_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.access_time));
224         d_printf("\twrite_time:     %s\n", nt_time_string(tmp_ctx, io.all_info2.out.write_time));
225         d_printf("\tchange_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.change_time));
226         d_printf("\tattrib:         0x%x\n", io.all_info2.out.attrib);
227         d_printf("\tunknown1:       0x%x\n", io.all_info2.out.unknown1);
228         d_printf("\talloc_size:     %llu\n", (long long)io.all_info2.out.alloc_size);
229         d_printf("\tsize:           %llu\n", (long long)io.all_info2.out.size);
230         d_printf("\tnlink:          %u\n", io.all_info2.out.nlink);
231         d_printf("\tdelete_pending: %u\n", io.all_info2.out.delete_pending);
232         d_printf("\tdirectory:      %u\n", io.all_info2.out.directory);
233         d_printf("\tfile_id:        %llu\n", (long long)io.all_info2.out.file_id);
234         d_printf("\tea_size:        %u\n", io.all_info2.out.ea_size);
235         d_printf("\taccess_mask:    0x%08x\n", io.all_info2.out.access_mask);
236         d_printf("\tposition:       0x%llx\n", (long long)io.all_info2.out.position);
237         d_printf("\tmode:           0x%llx\n", (long long)io.all_info2.out.mode);
238
239         /* short name, if any */
240         io.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION;
241         status = smb2_getinfo_file(tree, tmp_ctx, &io);
242         if (NT_STATUS_IS_OK(status)) {
243                 d_printf("\tshort name:     '%s'\n", io.alt_name_info.out.fname.s);
244         }
245
246         /* the EAs, if any */
247         io.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
248         status = smb2_getinfo_file(tree, tmp_ctx, &io);
249         if (NT_STATUS_IS_OK(status)) {
250                 int i;
251                 for (i=0;i<io.all_eas.out.num_eas;i++) {
252                         d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
253                                  io.all_eas.out.eas[i].flags,
254                                  (int)io.all_eas.out.eas[i].value.length,
255                                  io.all_eas.out.eas[i].name.s);
256                 }
257         }
258
259         /* streams, if available */
260         io.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
261         status = smb2_getinfo_file(tree, tmp_ctx, &io);
262         if (NT_STATUS_IS_OK(status)) {
263                 int i;
264                 for (i=0;i<io.stream_info.out.num_streams;i++) {
265                         d_printf("\tstream %d:\n", i);
266                         d_printf("\t\tsize       %ld\n", 
267                                  (long)io.stream_info.out.streams[i].size);
268                         d_printf("\t\talloc size %ld\n", 
269                                  (long)io.stream_info.out.streams[i].alloc_size);
270                         d_printf("\t\tname       %s\n", io.stream_info.out.streams[i].stream_name.s);
271                 }
272         }       
273
274         if (DEBUGLVL(1)) {
275                 /* the security descriptor */
276                 io.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
277                 io.query_secdesc.in.secinfo_flags = 
278                         SECINFO_OWNER|SECINFO_GROUP|
279                         SECINFO_DACL;
280                 status = smb2_getinfo_file(tree, tmp_ctx, &io);
281                 if (NT_STATUS_IS_OK(status)) {
282                         NDR_PRINT_DEBUG(security_descriptor, io.query_secdesc.out.sd);
283                 }
284         }
285
286         talloc_free(tmp_ctx);   
287 }
288
289
290 /*
291   open a smb2 connection
292 */
293 bool torture_smb2_connection(struct torture_context *tctx, struct smb2_tree **tree)
294 {
295         NTSTATUS status;
296         const char *host = torture_setting_string(tctx, "host", NULL);
297         const char *share = torture_setting_string(tctx, "share", NULL);
298         struct cli_credentials *credentials = cmdline_credentials;
299
300         status = smb2_connect(tctx, host, share, 
301                               lp_resolve_context(tctx->lp_ctx),
302                               credentials, tree, 
303                               tctx->ev);
304         if (!NT_STATUS_IS_OK(status)) {
305                 printf("Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
306                        host, share, nt_errstr(status));
307                 return false;
308         }
309         return true;
310 }
311
312
313 /*
314   create and return a handle to a test file
315 */
316 NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname, 
317                                struct smb2_handle *handle)
318 {
319         struct smb2_create io;
320         struct smb2_read r;
321         NTSTATUS status;
322
323         ZERO_STRUCT(io);
324         io.in.oplock_level = 0;
325         io.in.desired_access = SEC_RIGHTS_FILE_ALL;
326         io.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
327         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
328         io.in.share_access = 
329                 NTCREATEX_SHARE_ACCESS_DELETE|
330                 NTCREATEX_SHARE_ACCESS_READ|
331                 NTCREATEX_SHARE_ACCESS_WRITE;
332         io.in.create_options = 0;
333         io.in.fname = fname;
334
335         status = smb2_create(tree, tree, &io);
336         NT_STATUS_NOT_OK_RETURN(status);
337
338         *handle = io.out.file.handle;
339
340         ZERO_STRUCT(r);
341         r.in.file.handle = *handle;
342         r.in.length      = 5;
343         r.in.offset      = 0;
344
345         smb2_read(tree, tree, &r);
346
347         return NT_STATUS_OK;
348 }
349
350 /*
351   create and return a handle to a test directory
352 */
353 NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname, 
354                               struct smb2_handle *handle)
355 {
356         struct smb2_create io;
357         NTSTATUS status;
358
359         ZERO_STRUCT(io);
360         io.in.oplock_level = 0;
361         io.in.desired_access = SEC_RIGHTS_DIR_ALL;
362         io.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
363         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
364         io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
365         io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
366         io.in.fname = fname;
367
368         status = smb2_create(tree, tree, &io);
369         NT_STATUS_NOT_OK_RETURN(status);
370
371         *handle = io.out.file.handle;
372
373         return NT_STATUS_OK;
374 }
375
376
377 /*
378   create a complex file using the old SMB protocol, to make it easier to 
379   find fields in SMB2 getinfo levels
380 */
381 NTSTATUS torture_setup_complex_file(struct smb2_tree *tree, const char *fname)
382 {
383         struct smb2_handle handle;
384         NTSTATUS status = smb2_create_complex_file(tree, fname, &handle);
385         NT_STATUS_NOT_OK_RETURN(status);
386         return smb2_util_close(tree, handle);
387 }
388
389
390 /*
391   create a complex dir using the old SMB protocol, to make it easier to 
392   find fields in SMB2 getinfo levels
393 */
394 NTSTATUS torture_setup_complex_dir(struct smb2_tree *tree, const char *fname)
395 {
396         struct smb2_handle handle;
397         NTSTATUS status = smb2_create_complex_dir(tree, fname, &handle);
398         NT_STATUS_NOT_OK_RETURN(status);
399         return smb2_util_close(tree, handle);
400 }
401
402
403 /*
404   return a handle to the root of the share
405 */
406 NTSTATUS smb2_util_roothandle(struct smb2_tree *tree, struct smb2_handle *handle)
407 {
408         struct smb2_create io;
409         NTSTATUS status;
410
411         ZERO_STRUCT(io);
412         io.in.oplock_level = 0;
413         io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
414         io.in.file_attributes   = 0;
415         io.in.create_disposition = NTCREATEX_DISP_OPEN;
416         io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
417         io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT;
418         io.in.fname = NULL;
419
420         status = smb2_create(tree, tree, &io);
421         NT_STATUS_NOT_OK_RETURN(status);
422
423         *handle = io.out.file.handle;
424
425         return NT_STATUS_OK;
426 }