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