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