added support for creating files on SMB2 with initial EA lists and an ACL
[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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/smb2/smb2.h"
26 #include "libcli/smb2/smb2_calls.h"
27 #include "lib/cmdline/popt_common.h"
28 #include "lib/events/events.h"
29 #include "system/time.h"
30
31
32 /*
33   close a handle with SMB2
34 */
35 NTSTATUS smb2_util_close(struct smb2_tree *tree, struct smb2_handle h)
36 {
37         struct smb2_close c;
38
39         ZERO_STRUCT(c);
40         c.in.handle = h;
41
42         return smb2_close(tree, &c);
43 }
44
45 /*
46   unlink a file with SMB2
47 */
48 NTSTATUS smb2_util_unlink(struct smb2_tree *tree, const char *fname)
49 {
50         struct smb2_create io;
51         NTSTATUS status;
52
53         ZERO_STRUCT(io);
54         io.in.access_mask = SEC_RIGHTS_FILE_ALL;
55         io.in.file_attr   = FILE_ATTRIBUTE_NORMAL;
56         io.in.open_disposition = NTCREATEX_DISP_OPEN;
57         io.in.share_access = 
58                 NTCREATEX_SHARE_ACCESS_DELETE|
59                 NTCREATEX_SHARE_ACCESS_READ|
60                 NTCREATEX_SHARE_ACCESS_WRITE;
61         io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
62         io.in.fname = fname;
63
64         status = smb2_create(tree, tree, &io);
65         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
66                 return NT_STATUS_OK;
67         }
68         NT_STATUS_NOT_OK_RETURN(status);
69
70         return smb2_util_close(tree, io.out.handle);
71 }
72
73 /*
74   write to a file on SMB2
75 */
76 NTSTATUS smb2_util_write(struct smb2_tree *tree,
77                          struct smb2_handle handle, 
78                          const void *buf, off_t offset, size_t size)
79 {
80         struct smb2_write w;
81
82         ZERO_STRUCT(w);
83         w.in.offset      = offset;
84         w.in.handle      = handle;
85         w.in.data        = data_blob_const(buf, size);
86
87         return smb2_write(tree, &w);
88 }
89
90 /*
91   create a complex file using the SMB2 protocol
92 */
93 NTSTATUS smb2_create_complex_file(struct smb2_tree *tree, const char *fname, struct smb2_handle *handle)
94 {
95         TALLOC_CTX *tmp_ctx = talloc_new(tree);
96         char buf[7] = "abc";
97         struct smb2_create io;
98         union smb_setfileinfo setfile;
99         union smb_fileinfo fileinfo;
100         time_t t = (time(NULL) & ~1);
101         NTSTATUS status;
102
103         ZERO_STRUCT(io);
104         io.in.access_mask = SEC_RIGHTS_FILE_ALL;
105         io.in.file_attr   = FILE_ATTRIBUTE_NORMAL;
106         io.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
107         io.in.share_access = 
108                 NTCREATEX_SHARE_ACCESS_DELETE|
109                 NTCREATEX_SHARE_ACCESS_READ|
110                 NTCREATEX_SHARE_ACCESS_WRITE;
111         io.in.create_options = 0;
112         io.in.fname = fname;
113
114         io.in.sd = security_descriptor_create(tmp_ctx,
115                                               NULL, NULL,
116                                               SID_NT_AUTHENTICATED_USERS,
117                                               SEC_ACE_TYPE_ACCESS_ALLOWED,
118                                               SEC_RIGHTS_FILE_ALL | SEC_STD_ALL,
119                                               0,
120                                               SID_WORLD,
121                                               SEC_ACE_TYPE_ACCESS_ALLOWED,
122                                               SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
123                                               0,
124                                               NULL);
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.handle;
143
144         status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
145         NT_STATUS_NOT_OK_RETURN(status);
146
147         /* make sure all the timestamps aren't the same, and are also 
148            in different DST zones*/
149         setfile.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
150         setfile.generic.file.handle = *handle;
151
152         setfile.basic_info.in.create_time = t +  9*30*24*60*60;
153         setfile.basic_info.in.access_time = t +  6*30*24*60*60;
154         setfile.basic_info.in.write_time  = t +  3*30*24*60*60;
155         setfile.basic_info.in.change_time = t +  1*30*24*60*60;
156         setfile.basic_info.in.attrib      = FILE_ATTRIBUTE_NORMAL;
157
158         status = smb2_setinfo_file(tree, &setfile);
159         if (!NT_STATUS_IS_OK(status)) {
160                 printf("Failed to setup file times - %s\n", nt_errstr(status));
161         }
162
163         /* make sure all the timestamps aren't the same */
164         fileinfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
165         fileinfo.generic.in.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         }
171
172         if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
173                 printf("create_time not setup correctly\n");
174         }
175         if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
176                 printf("access_time not setup correctly\n");
177         }
178         if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
179                 printf("write_time not setup correctly\n");
180         }
181         
182         return NT_STATUS_OK;
183 }
184
185 /*
186   show lots of information about a file
187 */
188 void torture_smb2_all_info(struct smb2_tree *tree, struct smb2_handle handle)
189 {
190         NTSTATUS status;
191         TALLOC_CTX *tmp_ctx = talloc_new(tree);
192         union smb_fileinfo io;
193
194         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
195         io.generic.in.handle = handle;
196
197         status = smb2_getinfo_file(tree, tmp_ctx, &io);
198         if (!NT_STATUS_IS_OK(status)) {
199                 DEBUG(0,("getinfo failed - %s\n", nt_errstr(status)));
200                 talloc_free(tmp_ctx);
201                 return;
202         }
203
204         d_printf("\tcreate_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.create_time));
205         d_printf("\taccess_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.access_time));
206         d_printf("\twrite_time:     %s\n", nt_time_string(tmp_ctx, io.all_info2.out.write_time));
207         d_printf("\tchange_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.change_time));
208         d_printf("\tattrib:         0x%x\n", io.all_info2.out.attrib);
209         d_printf("\tunknown1:       0x%x\n", io.all_info2.out.unknown1);
210         d_printf("\talloc_size:     %llu\n", (uint64_t)io.all_info2.out.alloc_size);
211         d_printf("\tsize:           %llu\n", (uint64_t)io.all_info2.out.size);
212         d_printf("\tnlink:          %u\n", io.all_info2.out.nlink);
213         d_printf("\tdelete_pending: %u\n", io.all_info2.out.delete_pending);
214         d_printf("\tdirectory:      %u\n", io.all_info2.out.directory);
215         d_printf("\tfile_id:        %llu\n", io.all_info2.out.file_id);
216         d_printf("\tea_size:        %u\n", io.all_info2.out.ea_size);
217         d_printf("\taccess_mask:    0x%08x\n", io.all_info2.out.access_mask);
218         d_printf("\tunknown2:       0x%llx\n", io.all_info2.out.unknown2);
219         d_printf("\tunknown3:       0x%llx\n", io.all_info2.out.unknown3);
220         d_printf("\tfname:          '%s'\n", io.all_info2.out.fname.s);
221
222         /* short name, if any */
223         io.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION;
224         status = smb2_getinfo_file(tree, tmp_ctx, &io);
225         if (NT_STATUS_IS_OK(status)) {
226                 d_printf("\tshort name:     '%s'\n", io.alt_name_info.out.fname.s);
227         }
228
229         /* the EAs, if any */
230         io.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
231         status = smb2_getinfo_file(tree, tmp_ctx, &io);
232         if (NT_STATUS_IS_OK(status)) {
233                 int i;
234                 for (i=0;i<io.all_eas.out.num_eas;i++) {
235                         d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
236                                  io.all_eas.out.eas[i].flags,
237                                  (int)io.all_eas.out.eas[i].value.length,
238                                  io.all_eas.out.eas[i].name.s);
239                 }
240         }
241
242         /* streams, if available */
243         io.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
244         status = smb2_getinfo_file(tree, tmp_ctx, &io);
245         if (NT_STATUS_IS_OK(status)) {
246                 int i;
247                 for (i=0;i<io.stream_info.out.num_streams;i++) {
248                         d_printf("\tstream %d:\n", i);
249                         d_printf("\t\tsize       %ld\n", 
250                                  (long)io.stream_info.out.streams[i].size);
251                         d_printf("\t\talloc size %ld\n", 
252                                  (long)io.stream_info.out.streams[i].alloc_size);
253                         d_printf("\t\tname       %s\n", io.stream_info.out.streams[i].stream_name.s);
254                 }
255         }       
256
257         talloc_free(tmp_ctx);   
258 }
259
260
261 /*
262   open a smb2 connection
263 */
264 BOOL torture_smb2_connection(TALLOC_CTX *mem_ctx, struct smb2_tree **tree)
265 {
266         NTSTATUS status;
267         const char *host = lp_parm_string(-1, "torture", "host");
268         const char *share = lp_parm_string(-1, "torture", "share");
269         struct cli_credentials *credentials = cmdline_credentials;
270
271         status = smb2_connect(mem_ctx, host, share, credentials, tree, 
272                               event_context_find(mem_ctx));
273         if (!NT_STATUS_IS_OK(status)) {
274                 printf("Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
275                        host, share, nt_errstr(status));
276                 return False;
277         }
278         return True;
279 }
280
281
282 /*
283   create and return a handle to a test file
284 */
285 NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname, 
286                                struct smb2_handle *handle)
287 {
288         struct smb2_create io;
289         struct smb2_read r;
290         NTSTATUS status;
291
292         ZERO_STRUCT(io);
293         io.in.oplock_flags = 0;
294         io.in.access_mask = SEC_RIGHTS_FILE_ALL;
295         io.in.file_attr   = FILE_ATTRIBUTE_NORMAL;
296         io.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
297         io.in.share_access = 
298                 NTCREATEX_SHARE_ACCESS_DELETE|
299                 NTCREATEX_SHARE_ACCESS_READ|
300                 NTCREATEX_SHARE_ACCESS_WRITE;
301         io.in.create_options = 0;
302         io.in.fname = fname;
303
304         status = smb2_create(tree, tree, &io);
305         NT_STATUS_NOT_OK_RETURN(status);
306
307         *handle = io.out.handle;
308
309         ZERO_STRUCT(r);
310         r.in.length      = 5;
311         r.in.offset      = 0;
312         r.in.handle      = *handle;
313
314         smb2_read(tree, tree, &r);
315
316         return NT_STATUS_OK;
317 }
318
319 /*
320   create and return a handle to a test directory
321 */
322 NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname, 
323                               struct smb2_handle *handle)
324 {
325         struct smb2_create io;
326         NTSTATUS status;
327
328         ZERO_STRUCT(io);
329         io.in.oplock_flags = 0;
330         io.in.access_mask = SEC_RIGHTS_DIR_ALL;
331         io.in.file_attr   = FILE_ATTRIBUTE_DIRECTORY;
332         io.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
333         io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
334         io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
335         io.in.fname = fname;
336
337         status = smb2_create(tree, tree, &io);
338         NT_STATUS_NOT_OK_RETURN(status);
339
340         *handle = io.out.handle;
341
342         return NT_STATUS_OK;
343 }
344
345
346 /*
347   create a complex file using the old SMB protocol, to make it easier to 
348   find fields in SMB2 getinfo levels
349 */
350 BOOL torture_setup_complex_file(const char *fname)
351 {
352         struct smbcli_state *cli;
353         int fnum;
354
355         if (!torture_open_connection(&cli)) {
356                 return False;
357         }
358
359         fnum = create_complex_file(cli, cli, fname);
360
361         if (DEBUGLVL(1)) {
362                 torture_all_info(cli->tree, fname);
363         }
364         
365         talloc_free(cli);
366         return fnum != -1;
367 }
368
369 /*
370   create a complex directory using the old SMB protocol, to make it easier to 
371   find fields in SMB2 getinfo levels
372 */
373 BOOL torture_setup_complex_dir(const char *dname)
374 {
375         struct smbcli_state *cli;
376         int fnum;
377
378         if (!torture_open_connection(&cli)) {
379                 return False;
380         }
381
382         fnum = create_complex_dir(cli, cli, dname);
383
384         if (DEBUGLVL(1)) {
385                 torture_all_info(cli->tree, dname);
386         }
387         
388         talloc_free(cli);
389         return fnum != -1;
390 }