Add context for libcli_resolve.
[samba-svnmirror.git] / source / 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.access_mask = SEC_RIGHTS_FILE_ALL;
59         io.in.file_attr   = FILE_ATTRIBUTE_NORMAL;
60         io.in.open_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.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
111         io.in.file_attr   = FILE_ATTRIBUTE_NORMAL;
112         io.in.open_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_attr   = FILE_ATTRIBUTE_DIRECTORY;
123                 io.in.open_disposition = NTCREATEX_DISP_CREATE;
124         }
125
126         if (strchr(fname, ':') == NULL) {
127                 /* setup some EAs */
128                 io.in.eas.num_eas = 2;
129                 io.in.eas.eas = talloc_array(tmp_ctx, struct ea_struct, 2);
130                 io.in.eas.eas[0].flags = 0;
131                 io.in.eas.eas[0].name.s = "EAONE";
132                 io.in.eas.eas[0].value = data_blob_talloc(tmp_ctx, "VALUE1", 6);
133                 io.in.eas.eas[1].flags = 0;
134                 io.in.eas.eas[1].name.s = "SECONDEA";
135                 io.in.eas.eas[1].value = data_blob_talloc(tmp_ctx, "ValueTwo", 8);
136         }
137
138         status = smb2_create(tree, tmp_ctx, &io);
139         talloc_free(tmp_ctx);
140         NT_STATUS_NOT_OK_RETURN(status);
141
142         *handle = io.out.file.handle;
143
144         if (!dir) {
145                 status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
146                 NT_STATUS_NOT_OK_RETURN(status);
147         }
148
149         /* make sure all the timestamps aren't the same, and are also 
150            in different DST zones*/
151         setfile.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
152         setfile.generic.in.file.handle = *handle;
153
154         unix_to_nt_time(&setfile.basic_info.in.create_time, t + 9*30*24*60*60);
155         unix_to_nt_time(&setfile.basic_info.in.access_time, t + 6*30*24*60*60);
156         unix_to_nt_time(&setfile.basic_info.in.write_time,  t + 3*30*24*60*60);
157         unix_to_nt_time(&setfile.basic_info.in.change_time, t + 1*30*24*60*60);
158         setfile.basic_info.in.attrib      = FILE_ATTRIBUTE_NORMAL;
159
160         status = smb2_setinfo_file(tree, &setfile);
161         if (!NT_STATUS_IS_OK(status)) {
162                 printf("Failed to setup file times - %s\n", nt_errstr(status));
163                 return status;
164         }
165
166         /* make sure all the timestamps aren't the same */
167         fileinfo.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
168         fileinfo.generic.in.file.handle = *handle;
169
170         status = smb2_getinfo_file(tree, tree, &fileinfo);
171         if (!NT_STATUS_IS_OK(status)) {
172                 printf("Failed to query file times - %s\n", nt_errstr(status));
173                 return status;
174                 
175         }
176
177 #define CHECK_TIME(field) do {\
178         if (setfile.basic_info.in.field != fileinfo.all_info2.out.field) { \
179                 printf("(%s) " #field " not setup correctly: %s(%llu) => %s(%llu)\n", \
180                         __location__, \
181                         nt_time_string(tree, setfile.basic_info.in.field), \
182                         (unsigned long long)setfile.basic_info.in.field, \
183                         nt_time_string(tree, fileinfo.basic_info.out.field), \
184                         (unsigned long long)fileinfo.basic_info.out.field); \
185                 status = NT_STATUS_INVALID_PARAMETER; \
186         } \
187 } while (0)
188
189         CHECK_TIME(create_time);
190         CHECK_TIME(access_time);
191         CHECK_TIME(write_time);
192         CHECK_TIME(change_time);
193
194         return status;
195 }
196
197 /*
198   create a complex file using the SMB2 protocol
199 */
200 NTSTATUS smb2_create_complex_file(struct smb2_tree *tree, const char *fname, 
201                                          struct smb2_handle *handle)
202 {
203         return smb2_create_complex(tree, fname, handle, false);
204 }
205
206 /*
207   create a complex dir using the SMB2 protocol
208 */
209 NTSTATUS smb2_create_complex_dir(struct smb2_tree *tree, const char *fname, 
210                                  struct smb2_handle *handle)
211 {
212         return smb2_create_complex(tree, fname, handle, true);
213 }
214
215 /*
216   show lots of information about a file
217 */
218 void torture_smb2_all_info(struct smb2_tree *tree, struct smb2_handle handle)
219 {
220         NTSTATUS status;
221         TALLOC_CTX *tmp_ctx = talloc_new(tree);
222         union smb_fileinfo io;
223
224         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
225         io.generic.in.file.handle = handle;
226
227         status = smb2_getinfo_file(tree, tmp_ctx, &io);
228         if (!NT_STATUS_IS_OK(status)) {
229                 DEBUG(0,("getinfo failed - %s\n", nt_errstr(status)));
230                 talloc_free(tmp_ctx);
231                 return;
232         }
233
234         d_printf("all_info for '%s'\n", io.all_info2.out.fname.s);
235         d_printf("\tcreate_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.create_time));
236         d_printf("\taccess_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.access_time));
237         d_printf("\twrite_time:     %s\n", nt_time_string(tmp_ctx, io.all_info2.out.write_time));
238         d_printf("\tchange_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.change_time));
239         d_printf("\tattrib:         0x%x\n", io.all_info2.out.attrib);
240         d_printf("\tunknown1:       0x%x\n", io.all_info2.out.unknown1);
241         d_printf("\talloc_size:     %llu\n", (long long)io.all_info2.out.alloc_size);
242         d_printf("\tsize:           %llu\n", (long long)io.all_info2.out.size);
243         d_printf("\tnlink:          %u\n", io.all_info2.out.nlink);
244         d_printf("\tdelete_pending: %u\n", io.all_info2.out.delete_pending);
245         d_printf("\tdirectory:      %u\n", io.all_info2.out.directory);
246         d_printf("\tfile_id:        %llu\n", (long long)io.all_info2.out.file_id);
247         d_printf("\tea_size:        %u\n", io.all_info2.out.ea_size);
248         d_printf("\taccess_mask:    0x%08x\n", io.all_info2.out.access_mask);
249         d_printf("\tposition:       0x%llx\n", (long long)io.all_info2.out.position);
250         d_printf("\tmode:           0x%llx\n", (long long)io.all_info2.out.mode);
251
252         /* short name, if any */
253         io.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION;
254         status = smb2_getinfo_file(tree, tmp_ctx, &io);
255         if (NT_STATUS_IS_OK(status)) {
256                 d_printf("\tshort name:     '%s'\n", io.alt_name_info.out.fname.s);
257         }
258
259         /* the EAs, if any */
260         io.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
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.all_eas.out.num_eas;i++) {
265                         d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
266                                  io.all_eas.out.eas[i].flags,
267                                  (int)io.all_eas.out.eas[i].value.length,
268                                  io.all_eas.out.eas[i].name.s);
269                 }
270         }
271
272         /* streams, if available */
273         io.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
274         status = smb2_getinfo_file(tree, tmp_ctx, &io);
275         if (NT_STATUS_IS_OK(status)) {
276                 int i;
277                 for (i=0;i<io.stream_info.out.num_streams;i++) {
278                         d_printf("\tstream %d:\n", i);
279                         d_printf("\t\tsize       %ld\n", 
280                                  (long)io.stream_info.out.streams[i].size);
281                         d_printf("\t\talloc size %ld\n", 
282                                  (long)io.stream_info.out.streams[i].alloc_size);
283                         d_printf("\t\tname       %s\n", io.stream_info.out.streams[i].stream_name.s);
284                 }
285         }       
286
287         if (DEBUGLVL(1)) {
288                 /* the security descriptor */
289                 io.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
290                 io.query_secdesc.in.secinfo_flags = 
291                         SECINFO_OWNER|SECINFO_GROUP|
292                         SECINFO_DACL;
293                 status = smb2_getinfo_file(tree, tmp_ctx, &io);
294                 if (NT_STATUS_IS_OK(status)) {
295                         NDR_PRINT_DEBUG(security_descriptor, io.query_secdesc.out.sd);
296                 }
297         }
298
299         talloc_free(tmp_ctx);   
300 }
301
302
303 /*
304   open a smb2 connection
305 */
306 bool torture_smb2_connection(struct torture_context *tctx, struct smb2_tree **tree)
307 {
308         NTSTATUS status;
309         const char *host = torture_setting_string(tctx, "host", NULL);
310         const char *share = torture_setting_string(tctx, "share", NULL);
311         struct cli_credentials *credentials = cmdline_credentials;
312
313         status = smb2_connect(tctx, host, share, 
314                               lp_resolve_context(tctx->lp_ctx),
315                               credentials, tree, 
316                               event_context_find(tctx));
317         if (!NT_STATUS_IS_OK(status)) {
318                 printf("Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
319                        host, share, nt_errstr(status));
320                 return false;
321         }
322         return true;
323 }
324
325
326 /*
327   create and return a handle to a test file
328 */
329 NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname, 
330                                struct smb2_handle *handle)
331 {
332         struct smb2_create io;
333         struct smb2_read r;
334         NTSTATUS status;
335
336         ZERO_STRUCT(io);
337         io.in.oplock_flags = 0;
338         io.in.access_mask = SEC_RIGHTS_FILE_ALL;
339         io.in.file_attr   = FILE_ATTRIBUTE_NORMAL;
340         io.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
341         io.in.share_access = 
342                 NTCREATEX_SHARE_ACCESS_DELETE|
343                 NTCREATEX_SHARE_ACCESS_READ|
344                 NTCREATEX_SHARE_ACCESS_WRITE;
345         io.in.create_options = 0;
346         io.in.fname = fname;
347
348         status = smb2_create(tree, tree, &io);
349         NT_STATUS_NOT_OK_RETURN(status);
350
351         *handle = io.out.file.handle;
352
353         ZERO_STRUCT(r);
354         r.in.file.handle = *handle;
355         r.in.length      = 5;
356         r.in.offset      = 0;
357
358         smb2_read(tree, tree, &r);
359
360         return NT_STATUS_OK;
361 }
362
363 /*
364   create and return a handle to a test directory
365 */
366 NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname, 
367                               struct smb2_handle *handle)
368 {
369         struct smb2_create io;
370         NTSTATUS status;
371
372         ZERO_STRUCT(io);
373         io.in.oplock_flags = 0;
374         io.in.access_mask = SEC_RIGHTS_DIR_ALL;
375         io.in.file_attr   = FILE_ATTRIBUTE_DIRECTORY;
376         io.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
377         io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
378         io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
379         io.in.fname = fname;
380
381         status = smb2_create(tree, tree, &io);
382         NT_STATUS_NOT_OK_RETURN(status);
383
384         *handle = io.out.file.handle;
385
386         return NT_STATUS_OK;
387 }
388
389
390 /*
391   create a complex file using the old SMB protocol, to make it easier to 
392   find fields in SMB2 getinfo levels
393 */
394 NTSTATUS torture_setup_complex_file(struct smb2_tree *tree, const char *fname)
395 {
396         struct smb2_handle handle;
397         NTSTATUS status = smb2_create_complex_file(tree, fname, &handle);
398         NT_STATUS_NOT_OK_RETURN(status);
399         return smb2_util_close(tree, handle);
400 }
401
402
403 /*
404   create a complex dir using the old SMB protocol, to make it easier to 
405   find fields in SMB2 getinfo levels
406 */
407 NTSTATUS torture_setup_complex_dir(struct smb2_tree *tree, const char *fname)
408 {
409         struct smb2_handle handle;
410         NTSTATUS status = smb2_create_complex_dir(tree, fname, &handle);
411         NT_STATUS_NOT_OK_RETURN(status);
412         return smb2_util_close(tree, handle);
413 }
414
415
416 /*
417   return a handle to the root of the share
418 */
419 NTSTATUS smb2_util_roothandle(struct smb2_tree *tree, struct smb2_handle *handle)
420 {
421         struct smb2_create io;
422         NTSTATUS status;
423
424         ZERO_STRUCT(io);
425         io.in.oplock_flags = 0;
426         io.in.access_mask = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
427         io.in.file_attr   = 0;
428         io.in.open_disposition = NTCREATEX_DISP_OPEN;
429         io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
430         io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT;
431         io.in.fname = "";
432
433         status = smb2_create(tree, tree, &io);
434         NT_STATUS_NOT_OK_RETURN(status);
435
436         *handle = io.out.file.handle;
437
438         return NT_STATUS_OK;
439 }