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