check error code for zero desired_access in SMB2 create
[kai/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_set;
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         ok_mask = 0;
170         invalid_parameter_mask = 0;
171         unexpected_mask = 0;
172         file_attributes_set = 0;
173         {
174                 int i;
175                 for (i=0;i<32;i++) {
176                         io.in.file_attributes = 1<<i;
177                         if (io.in.file_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
178                                 continue;
179                         }
180                         smb2_deltree(tree, FNAME);
181                         status = smb2_create(tree, tmp_ctx, &io);
182                         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
183                                 invalid_parameter_mask |= 1<<i;
184                         } else if (NT_STATUS_IS_OK(status)) {
185                                 uint32_t expected;
186                                 ok_mask |= 1<<i;
187
188                                 expected = (io.in.file_attributes | FILE_ATTRIBUTE_ARCHIVE) & 0x00005127;
189                                 CHECK_EQUAL(io.out.file_attr, expected);
190                                 file_attributes_set |= io.out.file_attr;
191
192                                 status = smb2_util_close(tree, io.out.file.handle);
193                                 CHECK_STATUS(status, NT_STATUS_OK);
194                         } else {
195                                 unexpected_mask |= 1<<i;
196                                 printf("file attribute 0x%08x returned %s\n", 1<<i, nt_errstr(status));
197                         }
198                 }
199         }
200
201         CHECK_EQUAL(ok_mask,                0x00003fb7);
202         CHECK_EQUAL(invalid_parameter_mask, 0xffff8048);
203         CHECK_EQUAL(unexpected_mask,        0x00000000);
204         CHECK_EQUAL(file_attributes_set,    0x00001127);
205
206         smb2_deltree(tree, FNAME);
207
208         /*
209          * Standalone servers doesn't support encryption
210          */
211         io.in.file_attributes = FILE_ATTRIBUTE_ENCRYPTED;
212         status = smb2_create(tree, tmp_ctx, &io);
213         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
214                 printf("FILE_ATTRIBUTE_ENCRYPTED returned %s\n", nt_errstr(status));
215         } else {
216                 CHECK_STATUS(status, NT_STATUS_OK);
217                 CHECK_EQUAL(io.out.file_attr, (FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_ARCHIVE));
218                 status = smb2_util_close(tree, io.out.file.handle);
219                 CHECK_STATUS(status, NT_STATUS_OK);
220         }
221
222         smb2_deltree(tree, FNAME);
223
224         ZERO_STRUCT(io);
225         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
226         io.in.file_attributes    = 0;
227         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
228         io.in.share_access = 
229                 NTCREATEX_SHARE_ACCESS_READ|
230                 NTCREATEX_SHARE_ACCESS_WRITE;
231         io.in.create_options = 0;
232         io.in.fname = FNAME ":stream1";
233         status = smb2_create(tree, tmp_ctx, &io);
234         CHECK_STATUS(status, NT_STATUS_OK);
235
236         status = smb2_util_close(tree, io.out.file.handle);
237         CHECK_STATUS(status, NT_STATUS_OK);
238
239         io.in.fname = FNAME;
240         io.in.file_attributes = 0x8040;
241         io.in.share_access = 
242                 NTCREATEX_SHARE_ACCESS_READ;
243         status = smb2_create(tree, tmp_ctx, &io);
244         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
245
246         io.in.fname = FNAME;
247         io.in.file_attributes = 0;
248         io.in.desired_access  = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
249         io.in.query_maximal_access = true;
250         status = smb2_create(tree, tmp_ctx, &io);
251         CHECK_STATUS(status, NT_STATUS_OK);
252         CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
253
254         q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
255         q.access_information.in.file.handle = io.out.file.handle;
256         status = smb2_getinfo_file(tree, tmp_ctx, &q);
257         CHECK_STATUS(status, NT_STATUS_OK);
258         CHECK_EQUAL(q.access_information.out.access_flags, io.in.desired_access);
259
260         io.in.file_attributes = 0;
261         io.in.desired_access  = 0;
262         io.in.query_maximal_access = false;
263         io.in.share_access = 0;
264         status = smb2_create(tree, tmp_ctx, &io);
265         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
266         
267         talloc_free(tmp_ctx);
268
269         smb2_deltree(tree, FNAME);
270         
271         return true;
272 }
273
274
275 /*
276   try the various request blobs
277  */
278 static bool test_create_blob(struct torture_context *torture, struct smb2_tree *tree)
279 {
280         struct smb2_create io;
281         NTSTATUS status;
282         TALLOC_CTX *tmp_ctx = talloc_new(tree);
283
284         smb2_deltree(tree, FNAME);
285
286         ZERO_STRUCT(io);
287         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
288         io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
289         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
290         io.in.share_access = 
291                 NTCREATEX_SHARE_ACCESS_DELETE|
292                 NTCREATEX_SHARE_ACCESS_READ|
293                 NTCREATEX_SHARE_ACCESS_WRITE;
294         io.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
295                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
296                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
297                                           0x00200000;
298         io.in.fname = FNAME;
299
300         status = smb2_create(tree, tmp_ctx, &io);
301         CHECK_STATUS(status, NT_STATUS_OK);
302
303         status = smb2_util_close(tree, io.out.file.handle);
304         CHECK_STATUS(status, NT_STATUS_OK);
305
306         printf("testing alloc size\n");
307         io.in.alloc_size = 4096;
308         status = smb2_create(tree, tmp_ctx, &io);
309         CHECK_STATUS(status, NT_STATUS_OK);
310         CHECK_EQUAL(io.out.alloc_size, io.in.alloc_size);
311
312         status = smb2_util_close(tree, io.out.file.handle);
313         CHECK_STATUS(status, NT_STATUS_OK);
314
315         printf("testing durable open\n");
316         io.in.durable_open = true;
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 query maximal access\n");
324         io.in.query_maximal_access = true;
325         status = smb2_create(tree, tmp_ctx, &io);
326         CHECK_STATUS(status, NT_STATUS_OK);
327         CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
328
329         status = smb2_util_close(tree, io.out.file.handle);
330         CHECK_STATUS(status, NT_STATUS_OK);
331
332         printf("testing timewarp\n");
333         io.in.timewarp = 10000;
334         status = smb2_create(tree, tmp_ctx, &io);
335         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
336         io.in.timewarp = 0;
337
338         printf("testing query_on_disk\n");
339         io.in.query_on_disk_id = true;
340         status = smb2_create(tree, tmp_ctx, &io);
341         CHECK_STATUS(status, NT_STATUS_OK);
342
343         status = smb2_util_close(tree, io.out.file.handle);
344         CHECK_STATUS(status, NT_STATUS_OK);
345
346         printf("testing unknown tag\n");
347         status = smb2_create_blob_add(tmp_ctx, &io.in.blobs,
348                                       "FooO", data_blob(NULL, 0));
349         CHECK_STATUS(status, NT_STATUS_OK);
350
351         status = smb2_create(tree, tmp_ctx, &io);
352         CHECK_STATUS(status, NT_STATUS_OK);
353
354         status = smb2_util_close(tree, io.out.file.handle);
355         CHECK_STATUS(status, NT_STATUS_OK);
356
357         printf("testing bad tag length\n");
358         status = smb2_create_blob_add(tmp_ctx, &io.in.blobs,
359                                       "xxx", data_blob(NULL, 0));
360         CHECK_STATUS(status, NT_STATUS_OK);
361
362         status = smb2_create(tree, tmp_ctx, &io);
363         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
364
365         talloc_free(tmp_ctx);
366
367         smb2_deltree(tree, FNAME);
368         
369         return true;
370 }
371
372 /*
373   try creating with acls
374  */
375 static bool test_create_acl(struct torture_context *torture, struct smb2_tree *tree)
376 {
377         struct smb2_create io;
378         NTSTATUS status;
379         TALLOC_CTX *tmp_ctx = talloc_new(tree);
380         struct security_ace ace;
381         struct security_descriptor *sd, *sd2;
382         struct dom_sid *test_sid;
383         union smb_fileinfo q;
384
385         smb2_deltree(tree, FNAME);
386
387         ZERO_STRUCT(io);
388         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
389         io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
390         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
391         io.in.share_access = 
392                 NTCREATEX_SHARE_ACCESS_DELETE|
393                 NTCREATEX_SHARE_ACCESS_READ|
394                 NTCREATEX_SHARE_ACCESS_WRITE;
395         io.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
396                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
397                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
398                                           0x00200000;
399         io.in.fname = FNAME;
400
401         status = smb2_create(tree, tmp_ctx, &io);
402         CHECK_STATUS(status, NT_STATUS_OK);
403
404         q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
405         q.query_secdesc.in.file.handle = io.out.file.handle;
406         q.query_secdesc.in.secinfo_flags = 
407                 SECINFO_OWNER |
408                 SECINFO_GROUP |
409                 SECINFO_DACL;
410         status = smb2_getinfo_file(tree, tmp_ctx, &q);
411         CHECK_STATUS(status, NT_STATUS_OK);
412         sd = q.query_secdesc.out.sd;
413
414         status = smb2_util_close(tree, io.out.file.handle);
415         CHECK_STATUS(status, NT_STATUS_OK);
416
417         smb2_util_unlink(tree, FNAME);
418
419         printf("adding a new ACE\n");
420         test_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-5-32-1234-54321");
421
422         ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
423         ace.flags = 0;
424         ace.access_mask = SEC_STD_ALL;
425         ace.trustee = *test_sid;
426
427         status = security_descriptor_dacl_add(sd, &ace);
428         CHECK_STATUS(status, NT_STATUS_OK);
429         
430         printf("creating a file with an initial ACL\n");
431
432         io.in.sec_desc = sd;
433         status = smb2_create(tree, tmp_ctx, &io);
434         CHECK_STATUS(status, NT_STATUS_OK);
435
436         q.query_secdesc.in.file.handle = io.out.file.handle;
437         status = smb2_getinfo_file(tree, tmp_ctx, &q);
438         CHECK_STATUS(status, NT_STATUS_OK);
439         sd2 = q.query_secdesc.out.sd;
440
441         if (!security_acl_equal(sd->dacl, sd2->dacl)) {
442                 printf("%s: security descriptors don't match!\n", __location__);
443                 printf("got:\n");
444                 NDR_PRINT_DEBUG(security_descriptor, sd2);
445                 printf("expected:\n");
446                 NDR_PRINT_DEBUG(security_descriptor, sd);
447                 return false;
448         }
449
450         talloc_free(tmp_ctx);
451         
452         return true;
453 }
454
455 /* 
456    basic testing of SMB2 read
457 */
458 struct torture_suite *torture_smb2_create_init(void)
459 {
460         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "CREATE");
461
462         torture_suite_add_1smb2_test(suite, "GENTEST", test_create_gentest);
463         torture_suite_add_1smb2_test(suite, "BLOB", test_create_blob);
464         torture_suite_add_1smb2_test(suite, "ACL", test_create_acl);
465
466         suite->description = talloc_strdup(suite, "SMB2-CREATE tests");
467
468         return suite;
469 }