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