744c5d2b6c63ff5539fdebfb453c6b9355620729
[tprouty/samba.git] / source4 / torture / smb2 / create.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    SMB2 create test suite
5
6    Copyright (C) Andrew Tridgell 2008
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 "torture/torture.h"
26 #include "torture/smb2/proto.h"
27 #include "param/param.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "libcli/security/security.h"
30
31 #define FNAME "test_create.dat"
32
33 #define CHECK_STATUS(status, correct) do { \
34         if (!NT_STATUS_EQUAL(status, correct)) { \
35                 printf("(%s) Incorrect status %s - should be %s\n", \
36                        __location__, nt_errstr(status), nt_errstr(correct)); \
37                 return false; \
38         }} while (0)
39
40 #define CHECK_EQUAL(v, correct) do { \
41         if (v != correct) { \
42                 printf("(%s) Incorrect value for %s 0x%08llx - should be 0x%08llx\n", \
43                        __location__, #v, (unsigned long long)v, (unsigned long long)correct); \
44                 return false;                                   \
45         }} while (0)
46
47 /*
48   test some interesting combinations found by gentest
49  */
50 static bool test_create_gentest(struct torture_context *torture, struct smb2_tree *tree)
51 {
52         struct smb2_create io;
53         NTSTATUS status;
54         TALLOC_CTX *tmp_ctx = talloc_new(tree);
55         uint32_t access_mask, file_attributes, file_attributes_set, denied_mask;
56         uint32_t ok_mask, not_supported_mask, invalid_parameter_mask;
57         union smb_fileinfo q;
58
59         ZERO_STRUCT(io);
60         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
61         io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
62         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
63         io.in.share_access = 
64                 NTCREATEX_SHARE_ACCESS_DELETE|
65                 NTCREATEX_SHARE_ACCESS_READ|
66                 NTCREATEX_SHARE_ACCESS_WRITE;
67         io.in.create_options = 0;
68         io.in.fname = FNAME;
69
70         status = smb2_create(tree, tmp_ctx, &io);
71         CHECK_STATUS(status, NT_STATUS_OK);
72
73         status = smb2_util_close(tree, io.out.file.handle);
74         CHECK_STATUS(status, NT_STATUS_OK);
75
76         io.in.create_options = 0xF0000000;
77         status = smb2_create(tree, tmp_ctx, &io);
78         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
79
80         io.in.create_options = 0;
81
82         io.in.file_attributes = FILE_ATTRIBUTE_DEVICE;
83         status = smb2_create(tree, tmp_ctx, &io);
84         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
85
86         io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
87         status = smb2_create(tree, tmp_ctx, &io);
88         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
89
90         io.in.create_disposition = NTCREATEX_DISP_OPEN;
91         io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
92         status = smb2_create(tree, tmp_ctx, &io);
93         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
94         
95         io.in.create_disposition = NTCREATEX_DISP_CREATE;
96         io.in.desired_access = 0x08000000;
97         status = smb2_create(tree, tmp_ctx, &io);
98         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
99
100         io.in.desired_access = 0x04000000;
101         status = smb2_create(tree, tmp_ctx, &io);
102         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
103
104         io.in.file_attributes = 0;
105         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
106         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
107         ok_mask = not_supported_mask = invalid_parameter_mask = 0;
108         {
109                 int i;
110                 for (i=0;i<32;i++) {
111                         io.in.create_options = 1<<i;
112                         if (io.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
113                                 continue;
114                         }
115                         status = smb2_create(tree, tmp_ctx, &io);
116                         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
117                                 not_supported_mask |= 1<<i;
118                         } else if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
119                                 invalid_parameter_mask |= 1<<i;
120                         } else if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
121                                 ok_mask |= 1<<i;
122                                 status = smb2_util_close(tree, io.out.file.handle);
123                                 CHECK_STATUS(status, NT_STATUS_OK);
124                         } else {
125                                 printf("create option 0x%08x returned %s\n", 1<<i, nt_errstr(status));
126                         }
127                 }
128         }
129         io.in.create_options = 0;
130
131         CHECK_EQUAL(ok_mask,                0x00efcf7e);
132         CHECK_EQUAL(not_supported_mask,     0x00102080);
133         CHECK_EQUAL(invalid_parameter_mask, 0xff000000);
134
135         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
136         io.in.file_attributes = 0;
137         access_mask = 0;
138         {
139                 int i;
140                 for (i=0;i<32;i++) {
141                         io.in.desired_access = 1<<i;
142                         status = smb2_create(tree, tmp_ctx, &io);
143                         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
144                             NT_STATUS_EQUAL(status, NT_STATUS_PRIVILEGE_NOT_HELD)) {
145                                 access_mask |= io.in.desired_access;
146                         } else {
147                                 CHECK_STATUS(status, NT_STATUS_OK);
148                                 status = smb2_util_close(tree, io.out.file.handle);
149                                 CHECK_STATUS(status, NT_STATUS_OK);
150                         }
151                 }
152         }
153
154         CHECK_EQUAL(access_mask, 0x0df0fe00);
155
156         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
157         io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
158         io.in.file_attributes = 0;
159         file_attributes = 0;
160         file_attributes_set = 0;
161         denied_mask = 0;
162         {
163                 int i;
164                 for (i=0;i<32;i++) {
165                         io.in.file_attributes = 1<<i;
166                         smb2_deltree(tree, FNAME);
167                         status = smb2_create(tree, tmp_ctx, &io);
168                         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
169                                 file_attributes |= io.in.file_attributes;
170                         } else if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
171                                 denied_mask |= io.in.file_attributes;
172                         } else {
173                                 CHECK_STATUS(status, NT_STATUS_OK);
174                                 status = smb2_util_close(tree, io.out.file.handle);
175                                 CHECK_STATUS(status, NT_STATUS_OK);
176                                 file_attributes_set |= io.out.file_attr;
177                         }
178                 }
179         }
180
181         CHECK_EQUAL(file_attributes, 0xffff8048);
182         CHECK_EQUAL(denied_mask, 0x4000);
183         CHECK_EQUAL(file_attributes_set, 0x00001127);
184
185         smb2_deltree(tree, FNAME);
186
187         ZERO_STRUCT(io);
188         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
189         io.in.file_attributes    = 0;
190         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
191         io.in.share_access = 
192                 NTCREATEX_SHARE_ACCESS_READ|
193                 NTCREATEX_SHARE_ACCESS_WRITE;
194         io.in.create_options = 0;
195         io.in.fname = FNAME ":stream1";
196         status = smb2_create(tree, tmp_ctx, &io);
197         CHECK_STATUS(status, NT_STATUS_OK);
198
199         status = smb2_util_close(tree, io.out.file.handle);
200         CHECK_STATUS(status, NT_STATUS_OK);
201
202         io.in.fname = FNAME;
203         io.in.file_attributes = 0x8040;
204         io.in.share_access = 
205                 NTCREATEX_SHARE_ACCESS_READ;
206         status = smb2_create(tree, tmp_ctx, &io);
207         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
208
209         io.in.fname = FNAME;
210         io.in.file_attributes = 0;
211         io.in.desired_access  = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
212         io.in.query_maximal_access = true;
213         status = smb2_create(tree, tmp_ctx, &io);
214         CHECK_STATUS(status, NT_STATUS_OK);
215         CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
216
217         q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
218         q.access_information.in.file.handle = io.out.file.handle;
219         status = smb2_getinfo_file(tree, tmp_ctx, &q);
220         CHECK_STATUS(status, NT_STATUS_OK);
221         CHECK_EQUAL(q.access_information.out.access_flags, io.in.desired_access);
222         
223         talloc_free(tmp_ctx);
224
225         smb2_deltree(tree, FNAME);
226         
227         return true;
228 }
229
230
231 /*
232   try the various request blobs
233  */
234 static bool test_create_blob(struct torture_context *torture, struct smb2_tree *tree)
235 {
236         struct smb2_create io;
237         NTSTATUS status;
238         TALLOC_CTX *tmp_ctx = talloc_new(tree);
239
240         smb2_deltree(tree, FNAME);
241
242         ZERO_STRUCT(io);
243         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
244         io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
245         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
246         io.in.share_access = 
247                 NTCREATEX_SHARE_ACCESS_DELETE|
248                 NTCREATEX_SHARE_ACCESS_READ|
249                 NTCREATEX_SHARE_ACCESS_WRITE;
250         io.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
251                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
252                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
253                                           0x00200000;
254         io.in.fname = FNAME;
255
256         status = smb2_create(tree, tmp_ctx, &io);
257         CHECK_STATUS(status, NT_STATUS_OK);
258
259         status = smb2_util_close(tree, io.out.file.handle);
260         CHECK_STATUS(status, NT_STATUS_OK);
261
262         printf("testing alloc size\n");
263         io.in.alloc_size = 4096;
264         status = smb2_create(tree, tmp_ctx, &io);
265         CHECK_STATUS(status, NT_STATUS_OK);
266         CHECK_EQUAL(io.out.alloc_size, io.in.alloc_size);
267
268         status = smb2_util_close(tree, io.out.file.handle);
269         CHECK_STATUS(status, NT_STATUS_OK);
270
271         printf("testing durable open\n");
272         io.in.durable_open = true;
273         status = smb2_create(tree, tmp_ctx, &io);
274         CHECK_STATUS(status, NT_STATUS_OK);
275
276         status = smb2_util_close(tree, io.out.file.handle);
277         CHECK_STATUS(status, NT_STATUS_OK);
278
279         printf("testing query maximal access\n");
280         io.in.query_maximal_access = true;
281         status = smb2_create(tree, tmp_ctx, &io);
282         CHECK_STATUS(status, NT_STATUS_OK);
283         CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
284
285         status = smb2_util_close(tree, io.out.file.handle);
286         CHECK_STATUS(status, NT_STATUS_OK);
287
288         printf("testing timewarp\n");
289         io.in.timewarp = 10000;
290         status = smb2_create(tree, tmp_ctx, &io);
291         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
292         io.in.timewarp = 0;
293
294         printf("testing query_on_disk\n");
295         io.in.query_on_disk_id = true;
296         status = smb2_create(tree, tmp_ctx, &io);
297         CHECK_STATUS(status, NT_STATUS_OK);
298
299         status = smb2_util_close(tree, io.out.file.handle);
300         CHECK_STATUS(status, NT_STATUS_OK);
301
302         printf("testing unknown tag\n");
303         status = smb2_create_blob_add(tmp_ctx, &io.in.blobs,
304                                       "FooO", data_blob(NULL, 0));
305         CHECK_STATUS(status, NT_STATUS_OK);
306
307         status = smb2_create(tree, tmp_ctx, &io);
308         CHECK_STATUS(status, NT_STATUS_OK);
309
310         status = smb2_util_close(tree, io.out.file.handle);
311         CHECK_STATUS(status, NT_STATUS_OK);
312
313         printf("testing bad tag length\n");
314         status = smb2_create_blob_add(tmp_ctx, &io.in.blobs,
315                                       "xxx", data_blob(NULL, 0));
316         CHECK_STATUS(status, NT_STATUS_OK);
317
318         status = smb2_create(tree, tmp_ctx, &io);
319         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
320
321         talloc_free(tmp_ctx);
322
323         smb2_deltree(tree, FNAME);
324         
325         return true;
326 }
327
328 /*
329   try creating with acls
330  */
331 static bool test_create_acl(struct torture_context *torture, struct smb2_tree *tree)
332 {
333         struct smb2_create io;
334         NTSTATUS status;
335         TALLOC_CTX *tmp_ctx = talloc_new(tree);
336         struct security_ace ace;
337         struct security_descriptor *sd, *sd2;
338         struct dom_sid *test_sid;
339         union smb_fileinfo q;
340
341         smb2_deltree(tree, FNAME);
342
343         ZERO_STRUCT(io);
344         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
345         io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
346         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
347         io.in.share_access = 
348                 NTCREATEX_SHARE_ACCESS_DELETE|
349                 NTCREATEX_SHARE_ACCESS_READ|
350                 NTCREATEX_SHARE_ACCESS_WRITE;
351         io.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
352                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
353                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
354                                           0x00200000;
355         io.in.fname = FNAME;
356
357         status = smb2_create(tree, tmp_ctx, &io);
358         CHECK_STATUS(status, NT_STATUS_OK);
359
360         q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
361         q.query_secdesc.in.file.handle = io.out.file.handle;
362         q.query_secdesc.in.secinfo_flags = 
363                 SECINFO_OWNER |
364                 SECINFO_GROUP |
365                 SECINFO_DACL;
366         status = smb2_getinfo_file(tree, tmp_ctx, &q);
367         CHECK_STATUS(status, NT_STATUS_OK);
368         sd = q.query_secdesc.out.sd;
369
370         status = smb2_util_close(tree, io.out.file.handle);
371         CHECK_STATUS(status, NT_STATUS_OK);
372
373         smb2_util_unlink(tree, FNAME);
374
375         printf("adding a new ACE\n");
376         test_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-5-32-1234-54321");
377
378         ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
379         ace.flags = 0;
380         ace.access_mask = SEC_STD_ALL;
381         ace.trustee = *test_sid;
382
383         status = security_descriptor_dacl_add(sd, &ace);
384         CHECK_STATUS(status, NT_STATUS_OK);
385         
386         printf("creating a file with an initial ACL\n");
387
388         io.in.sec_desc = sd;
389         status = smb2_create(tree, tmp_ctx, &io);
390         CHECK_STATUS(status, NT_STATUS_OK);
391
392         q.query_secdesc.in.file.handle = io.out.file.handle;
393         status = smb2_getinfo_file(tree, tmp_ctx, &q);
394         CHECK_STATUS(status, NT_STATUS_OK);
395         sd2 = q.query_secdesc.out.sd;
396
397         if (!security_acl_equal(sd->dacl, sd2->dacl)) {
398                 printf("%s: security descriptors don't match!\n", __location__);
399                 printf("got:\n");
400                 NDR_PRINT_DEBUG(security_descriptor, sd2);
401                 printf("expected:\n");
402                 NDR_PRINT_DEBUG(security_descriptor, sd);
403                 return false;
404         }
405
406         talloc_free(tmp_ctx);
407         
408         return true;
409 }
410
411 /* 
412    basic testing of SMB2 read
413 */
414 struct torture_suite *torture_smb2_create_init(void)
415 {
416         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "CREATE");
417
418         torture_suite_add_1smb2_test(suite, "GENTEST", test_create_gentest);
419         torture_suite_add_1smb2_test(suite, "BLOB", test_create_blob);
420         torture_suite_add_1smb2_test(suite, "ACL", test_create_acl);
421
422         suite->description = talloc_strdup(suite, "SMB2-CREATE tests");
423
424         return suite;
425 }