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