be825b24a7eca684e529006c826efa44c8474654
[ira/wip.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/util.h"
27 #include "torture/smb2/proto.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "libcli/security/security.h"
30
31 #include "system/filesys.h"
32 #include "auth/credentials/credentials.h"
33 #include "lib/cmdline/popt_common.h"
34 #include "librpc/gen_ndr/security.h"
35 #include "lib/events/events.h"
36
37 #define FNAME "test_create.dat"
38 #define DNAME "smb2_open"
39
40 #define CHECK_STATUS(status, correct) do { \
41         if (!NT_STATUS_EQUAL(status, correct)) { \
42                 torture_result(torture, TORTURE_FAIL, \
43                         "(%s) Incorrect status %s - should be %s\n", \
44                          __location__, nt_errstr(status), nt_errstr(correct)); \
45                 return false; \
46         }} while (0)
47
48 #define CHECK_EQUAL(v, correct) do { \
49         if (v != correct) { \
50                 torture_result(torture, TORTURE_FAIL, \
51                         "(%s) Incorrect value for %s 0x%08llx - " \
52                         "should be 0x%08llx\n", \
53                          __location__, #v, \
54                         (unsigned long long)v, \
55                         (unsigned long long)correct); \
56                 return false;                                   \
57         }} while (0)
58
59 #define CHECK_TIME(t, field) do { \
60         time_t t1, t2; \
61         finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
62         finfo.all_info.in.file.handle = h1; \
63         status = smb2_getinfo_file(tree, torture, &finfo); \
64         CHECK_STATUS(status, NT_STATUS_OK); \
65         t1 = t & ~1; \
66         t2 = nt_time_to_unix(finfo.all_info.out.field) & ~1; \
67         if (abs(t1-t2) > 2) { \
68                 torture_result(torture, TORTURE_FAIL, \
69                         "(%s) wrong time for field %s  %s - %s\n", \
70                         __location__, #field, \
71                         timestring(torture, t1), \
72                         timestring(torture, t2)); \
73                 dump_all_info(torture, &finfo); \
74                 ret = false; \
75         }} while (0)
76
77 #define CHECK_NTTIME(t, field) do { \
78         NTTIME t2; \
79         finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
80         finfo.all_info.in.file.handle = h1; \
81         status = smb2_getinfo_file(tree, torture, &finfo); \
82         CHECK_STATUS(status, NT_STATUS_OK); \
83         t2 = finfo.all_info.out.field; \
84         if (t != t2) { \
85                 torture_result(torture, TORTURE_FAIL, \
86                         "(%s) wrong time for field %s  %s - %s\n", \
87                        __location__, #field, \
88                        nt_time_string(torture, t), \
89                        nt_time_string(torture, t2)); \
90                 dump_all_info(torture, &finfo); \
91                 ret = false; \
92         }} while (0)
93
94 #define CHECK_ALL_INFO(v, field) do { \
95         finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
96         finfo.all_info.in.file.handle = h1; \
97         status = smb2_getinfo_file(tree, torture, &finfo); \
98         CHECK_STATUS(status, NT_STATUS_OK); \
99         if ((v) != (finfo.all_info.out.field)) { \
100                torture_result(torture, TORTURE_FAIL, \
101                         "(%s) wrong value for field %s  0x%x - 0x%x\n", \
102                         __location__, #field, (int)v,\
103                         (int)(finfo.all_info.out.field)); \
104                 dump_all_info(torture, &finfo); \
105                 ret = false; \
106         }} while (0)
107
108 #define CHECK_VAL(v, correct) do { \
109         if ((v) != (correct)) { \
110                 torture_result(torture, TORTURE_FAIL, \
111                         "(%s) wrong value for %s  0x%x - should be 0x%x\n", \
112                        __location__, #v, (int)(v), (int)correct); \
113                 ret = false; \
114         }} while (0)
115
116 #define SET_ATTRIB(sattrib) do { \
117         union smb_setfileinfo sfinfo; \
118         ZERO_STRUCT(sfinfo.basic_info.in); \
119         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION; \
120         sfinfo.basic_info.in.file.handle = h1; \
121         sfinfo.basic_info.in.attrib = sattrib; \
122         status = smb2_setinfo_file(tree, &sfinfo); \
123         if (!NT_STATUS_IS_OK(status)) { \
124                 torture_comment(torture, \
125                     "(%s) Failed to set attrib 0x%x on %s\n", \
126                        __location__, sattrib, fname); \
127         }} while (0)
128
129 #define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
130
131 /*
132   test some interesting combinations found by gentest
133  */
134 static bool test_create_gentest(struct torture_context *torture, struct smb2_tree *tree)
135 {
136         struct smb2_create io;
137         NTSTATUS status;
138         TALLOC_CTX *tmp_ctx = talloc_new(tree);
139         uint32_t access_mask, file_attributes_set;
140         uint32_t ok_mask, not_supported_mask, invalid_parameter_mask;
141         uint32_t not_a_directory_mask, unexpected_mask;
142         union smb_fileinfo q;
143
144         ZERO_STRUCT(io);
145         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
146         io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
147         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
148         io.in.share_access = 
149                 NTCREATEX_SHARE_ACCESS_DELETE|
150                 NTCREATEX_SHARE_ACCESS_READ|
151                 NTCREATEX_SHARE_ACCESS_WRITE;
152         io.in.create_options = 0;
153         io.in.fname = FNAME;
154
155         status = smb2_create(tree, tmp_ctx, &io);
156         CHECK_STATUS(status, NT_STATUS_OK);
157
158         status = smb2_util_close(tree, io.out.file.handle);
159         CHECK_STATUS(status, NT_STATUS_OK);
160
161         io.in.create_options = 0xF0000000;
162         status = smb2_create(tree, tmp_ctx, &io);
163         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
164
165         io.in.create_options = 0;
166
167         io.in.file_attributes = FILE_ATTRIBUTE_DEVICE;
168         status = smb2_create(tree, tmp_ctx, &io);
169         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
170
171         io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
172         status = smb2_create(tree, tmp_ctx, &io);
173         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
174
175         io.in.create_disposition = NTCREATEX_DISP_OPEN;
176         io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
177         status = smb2_create(tree, tmp_ctx, &io);
178         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
179         
180         io.in.create_disposition = NTCREATEX_DISP_CREATE;
181         io.in.desired_access = 0x08000000;
182         status = smb2_create(tree, tmp_ctx, &io);
183         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
184
185         io.in.desired_access = 0x04000000;
186         status = smb2_create(tree, tmp_ctx, &io);
187         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
188
189         io.in.file_attributes = 0;
190         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
191         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
192         ok_mask = 0;
193         not_supported_mask = 0;
194         invalid_parameter_mask = 0;
195         not_a_directory_mask = 0;
196         unexpected_mask = 0;
197         {
198                 int i;
199                 for (i=0;i<32;i++) {
200                         io.in.create_options = 1<<i;
201                         if (io.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
202                                 continue;
203                         }
204                         status = smb2_create(tree, tmp_ctx, &io);
205                         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
206                                 not_supported_mask |= 1<<i;
207                         } else if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
208                                 invalid_parameter_mask |= 1<<i;
209                         } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
210                                 not_a_directory_mask |= 1<<i;
211                         } else if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
212                                 ok_mask |= 1<<i;
213                                 status = smb2_util_close(tree, io.out.file.handle);
214                                 CHECK_STATUS(status, NT_STATUS_OK);
215                         } else {
216                                 unexpected_mask |= 1<<i;
217                                 torture_comment(torture,
218                                     "create option 0x%08x returned %s\n",
219                                     1<<i, nt_errstr(status));
220                         }
221                 }
222         }
223         io.in.create_options = 0;
224
225         CHECK_EQUAL(ok_mask,                0x00efcf7e);
226         CHECK_EQUAL(not_a_directory_mask,   0x00000001);
227         CHECK_EQUAL(not_supported_mask,     0x00102080);
228         CHECK_EQUAL(invalid_parameter_mask, 0xff000000);
229         CHECK_EQUAL(unexpected_mask,        0x00000000);
230
231         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
232         io.in.file_attributes = 0;
233         access_mask = 0;
234         {
235                 int i;
236                 for (i=0;i<32;i++) {
237                         io.in.desired_access = 1<<i;
238                         status = smb2_create(tree, tmp_ctx, &io);
239                         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
240                             NT_STATUS_EQUAL(status, NT_STATUS_PRIVILEGE_NOT_HELD)) {
241                                 access_mask |= io.in.desired_access;
242                         } else {
243                                 CHECK_STATUS(status, NT_STATUS_OK);
244                                 status = smb2_util_close(tree, io.out.file.handle);
245                                 CHECK_STATUS(status, NT_STATUS_OK);
246                         }
247                 }
248         }
249
250         if (TARGET_IS_WIN7(torture)) {
251                 CHECK_EQUAL(access_mask, 0x0de0fe00);
252         } else {
253                 CHECK_EQUAL(access_mask, 0x0df0fe00);
254         }
255
256         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
257         io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
258         io.in.file_attributes = 0;
259         ok_mask = 0;
260         invalid_parameter_mask = 0;
261         unexpected_mask = 0;
262         file_attributes_set = 0;
263         {
264                 int i;
265                 for (i=0;i<32;i++) {
266                         io.in.file_attributes = 1<<i;
267                         if (io.in.file_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
268                                 continue;
269                         }
270                         smb2_deltree(tree, FNAME);
271                         status = smb2_create(tree, tmp_ctx, &io);
272                         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
273                                 invalid_parameter_mask |= 1<<i;
274                         } else if (NT_STATUS_IS_OK(status)) {
275                                 uint32_t expected;
276                                 ok_mask |= 1<<i;
277
278                                 expected = (io.in.file_attributes | FILE_ATTRIBUTE_ARCHIVE) & 0x00005127;
279                                 CHECK_EQUAL(io.out.file_attr, expected);
280                                 file_attributes_set |= io.out.file_attr;
281
282                                 status = smb2_util_close(tree, io.out.file.handle);
283                                 CHECK_STATUS(status, NT_STATUS_OK);
284                         } else {
285                                 unexpected_mask |= 1<<i;
286                                 torture_comment(torture,
287                                     "file attribute 0x%08x returned %s\n",
288                                     1<<i, nt_errstr(status));
289                         }
290                 }
291         }
292
293         CHECK_EQUAL(ok_mask,                0x00003fb7);
294         CHECK_EQUAL(invalid_parameter_mask, 0xffff8048);
295         CHECK_EQUAL(unexpected_mask,        0x00000000);
296         CHECK_EQUAL(file_attributes_set,    0x00001127);
297
298         smb2_deltree(tree, FNAME);
299
300         /*
301          * Standalone servers doesn't support encryption
302          */
303         io.in.file_attributes = FILE_ATTRIBUTE_ENCRYPTED;
304         status = smb2_create(tree, tmp_ctx, &io);
305         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
306                 torture_comment(torture,
307                     "FILE_ATTRIBUTE_ENCRYPTED returned %s\n",
308                     nt_errstr(status));
309         } else {
310                 CHECK_STATUS(status, NT_STATUS_OK);
311                 CHECK_EQUAL(io.out.file_attr, (FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_ARCHIVE));
312                 status = smb2_util_close(tree, io.out.file.handle);
313                 CHECK_STATUS(status, NT_STATUS_OK);
314         }
315
316         smb2_deltree(tree, FNAME);
317
318         ZERO_STRUCT(io);
319         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
320         io.in.file_attributes    = 0;
321         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
322         io.in.share_access = 
323                 NTCREATEX_SHARE_ACCESS_READ|
324                 NTCREATEX_SHARE_ACCESS_WRITE;
325         io.in.create_options = 0;
326         io.in.fname = FNAME ":stream1";
327         status = smb2_create(tree, tmp_ctx, &io);
328         CHECK_STATUS(status, NT_STATUS_OK);
329
330         status = smb2_util_close(tree, io.out.file.handle);
331         CHECK_STATUS(status, NT_STATUS_OK);
332
333         io.in.fname = FNAME;
334         io.in.file_attributes = 0x8040;
335         io.in.share_access = 
336                 NTCREATEX_SHARE_ACCESS_READ;
337         status = smb2_create(tree, tmp_ctx, &io);
338         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
339
340         io.in.fname = FNAME;
341         io.in.file_attributes = 0;
342         io.in.desired_access  = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
343         io.in.query_maximal_access = true;
344         status = smb2_create(tree, tmp_ctx, &io);
345         CHECK_STATUS(status, NT_STATUS_OK);
346         CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
347
348         q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
349         q.access_information.in.file.handle = io.out.file.handle;
350         status = smb2_getinfo_file(tree, tmp_ctx, &q);
351         CHECK_STATUS(status, NT_STATUS_OK);
352         CHECK_EQUAL(q.access_information.out.access_flags, io.in.desired_access);
353
354         io.in.file_attributes = 0;
355         io.in.desired_access  = 0;
356         io.in.query_maximal_access = false;
357         io.in.share_access = 0;
358         status = smb2_create(tree, tmp_ctx, &io);
359         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
360         
361         talloc_free(tmp_ctx);
362
363         smb2_deltree(tree, FNAME);
364         
365         return true;
366 }
367
368
369 /*
370   try the various request blobs
371  */
372 static bool test_create_blob(struct torture_context *torture, struct smb2_tree *tree)
373 {
374         struct smb2_create io;
375         NTSTATUS status;
376         TALLOC_CTX *tmp_ctx = talloc_new(tree);
377
378         smb2_deltree(tree, FNAME);
379
380         ZERO_STRUCT(io);
381         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
382         io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
383         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
384         io.in.share_access = 
385                 NTCREATEX_SHARE_ACCESS_DELETE|
386                 NTCREATEX_SHARE_ACCESS_READ|
387                 NTCREATEX_SHARE_ACCESS_WRITE;
388         io.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
389                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
390                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
391                                           0x00200000;
392         io.in.fname = FNAME;
393
394         status = smb2_create(tree, tmp_ctx, &io);
395         CHECK_STATUS(status, NT_STATUS_OK);
396
397         status = smb2_util_close(tree, io.out.file.handle);
398         CHECK_STATUS(status, NT_STATUS_OK);
399
400         torture_comment(torture, "testing alloc size\n");
401         io.in.alloc_size = 4096;
402         status = smb2_create(tree, tmp_ctx, &io);
403         CHECK_STATUS(status, NT_STATUS_OK);
404         CHECK_EQUAL(io.out.alloc_size, io.in.alloc_size);
405
406         status = smb2_util_close(tree, io.out.file.handle);
407         CHECK_STATUS(status, NT_STATUS_OK);
408
409         torture_comment(torture, "testing durable open\n");
410         io.in.durable_open = true;
411         status = smb2_create(tree, tmp_ctx, &io);
412         CHECK_STATUS(status, NT_STATUS_OK);
413
414         status = smb2_util_close(tree, io.out.file.handle);
415         CHECK_STATUS(status, NT_STATUS_OK);
416
417         torture_comment(torture, "testing query maximal access\n");
418         io.in.query_maximal_access = true;
419         status = smb2_create(tree, tmp_ctx, &io);
420         CHECK_STATUS(status, NT_STATUS_OK);
421         CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
422
423         status = smb2_util_close(tree, io.out.file.handle);
424         CHECK_STATUS(status, NT_STATUS_OK);
425
426         torture_comment(torture, "testing timewarp\n");
427         io.in.timewarp = 10000;
428         status = smb2_create(tree, tmp_ctx, &io);
429         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
430         io.in.timewarp = 0;
431
432         torture_comment(torture, "testing query_on_disk\n");
433         io.in.query_on_disk_id = true;
434         status = smb2_create(tree, tmp_ctx, &io);
435         CHECK_STATUS(status, NT_STATUS_OK);
436
437         status = smb2_util_close(tree, io.out.file.handle);
438         CHECK_STATUS(status, NT_STATUS_OK);
439
440         torture_comment(torture, "testing unknown tag\n");
441         status = smb2_create_blob_add(tmp_ctx, &io.in.blobs,
442                                       "FooO", data_blob(NULL, 0));
443         CHECK_STATUS(status, NT_STATUS_OK);
444
445         status = smb2_create(tree, tmp_ctx, &io);
446         CHECK_STATUS(status, NT_STATUS_OK);
447
448         status = smb2_util_close(tree, io.out.file.handle);
449         CHECK_STATUS(status, NT_STATUS_OK);
450
451         torture_comment(torture, "testing bad tag length\n");
452         status = smb2_create_blob_add(tmp_ctx, &io.in.blobs,
453                                       "xxx", data_blob(NULL, 0));
454         CHECK_STATUS(status, NT_STATUS_OK);
455
456         status = smb2_create(tree, tmp_ctx, &io);
457         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
458
459         talloc_free(tmp_ctx);
460
461         smb2_deltree(tree, FNAME);
462         
463         return true;
464 }
465
466 /*
467   try creating with acls
468  */
469 static bool test_create_acl(struct torture_context *torture, struct smb2_tree *tree)
470 {
471         struct smb2_create io;
472         NTSTATUS status;
473         TALLOC_CTX *tmp_ctx = talloc_new(tree);
474         struct security_ace ace;
475         struct security_descriptor *sd, *sd2;
476         struct dom_sid *test_sid;
477         union smb_fileinfo q;
478
479         smb2_deltree(tree, FNAME);
480
481         ZERO_STRUCT(io);
482         io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
483         io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
484         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
485         io.in.share_access = 
486                 NTCREATEX_SHARE_ACCESS_DELETE|
487                 NTCREATEX_SHARE_ACCESS_READ|
488                 NTCREATEX_SHARE_ACCESS_WRITE;
489         io.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
490                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
491                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
492                                           0x00200000;
493         io.in.fname = FNAME;
494
495         status = smb2_create(tree, tmp_ctx, &io);
496         CHECK_STATUS(status, NT_STATUS_OK);
497
498         q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
499         q.query_secdesc.in.file.handle = io.out.file.handle;
500         q.query_secdesc.in.secinfo_flags = 
501                 SECINFO_OWNER |
502                 SECINFO_GROUP |
503                 SECINFO_DACL;
504         status = smb2_getinfo_file(tree, tmp_ctx, &q);
505         CHECK_STATUS(status, NT_STATUS_OK);
506         sd = q.query_secdesc.out.sd;
507
508         status = smb2_util_close(tree, io.out.file.handle);
509         CHECK_STATUS(status, NT_STATUS_OK);
510
511         smb2_util_unlink(tree, FNAME);
512
513         torture_comment(torture, "adding a new ACE\n");
514         test_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-5-32-1234-54321");
515
516         ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
517         ace.flags = 0;
518         ace.access_mask = SEC_STD_ALL;
519         ace.trustee = *test_sid;
520
521         status = security_descriptor_dacl_add(sd, &ace);
522         CHECK_STATUS(status, NT_STATUS_OK);
523
524         torture_comment(torture, "creating a file with an initial ACL\n");
525
526         io.in.sec_desc = sd;
527         status = smb2_create(tree, tmp_ctx, &io);
528         CHECK_STATUS(status, NT_STATUS_OK);
529
530         q.query_secdesc.in.file.handle = io.out.file.handle;
531         status = smb2_getinfo_file(tree, tmp_ctx, &q);
532         CHECK_STATUS(status, NT_STATUS_OK);
533         sd2 = q.query_secdesc.out.sd;
534
535         if (!security_acl_equal(sd->dacl, sd2->dacl)) {
536                 torture_comment(torture,
537                     "%s: security descriptors don't match!\n", __location__);
538                 torture_comment(torture, "got:\n");
539                 NDR_PRINT_DEBUG(security_descriptor, sd2);
540                 torture_comment(torture, "expected:\n");
541                 NDR_PRINT_DEBUG(security_descriptor, sd);
542                 return false;
543         }
544
545         talloc_free(tmp_ctx);
546         
547         return true;
548 }
549
550 /*
551   test SMB2 open
552 */
553 static bool test_smb2_open(struct torture_context *torture,
554                            struct smb2_tree *tree)
555 {
556         TALLOC_CTX *mem_ctx = talloc_new(torture);
557         union smb_open io;
558         union smb_fileinfo finfo;
559         const char *fname = DNAME "\\torture_ntcreatex.txt";
560         const char *dname = DNAME "\\torture_ntcreatex.dir";
561         NTSTATUS status;
562         struct smb2_handle h, h1;
563         bool ret = true;
564         int i;
565         struct {
566                 uint32_t create_disp;
567                 bool with_file;
568                 NTSTATUS correct_status;
569         } open_funcs[] = {
570                 { NTCREATEX_DISP_SUPERSEDE,     true,  NT_STATUS_OK },
571                 { NTCREATEX_DISP_SUPERSEDE,     false, NT_STATUS_OK },
572                 { NTCREATEX_DISP_OPEN,          true,  NT_STATUS_OK },
573                 { NTCREATEX_DISP_OPEN,          false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
574                 { NTCREATEX_DISP_CREATE,        true,  NT_STATUS_OBJECT_NAME_COLLISION },
575                 { NTCREATEX_DISP_CREATE,        false, NT_STATUS_OK },
576                 { NTCREATEX_DISP_OPEN_IF,       true,  NT_STATUS_OK },
577                 { NTCREATEX_DISP_OPEN_IF,       false, NT_STATUS_OK },
578                 { NTCREATEX_DISP_OVERWRITE,     true,  NT_STATUS_OK },
579                 { NTCREATEX_DISP_OVERWRITE,     false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
580                 { NTCREATEX_DISP_OVERWRITE_IF,  true,  NT_STATUS_OK },
581                 { NTCREATEX_DISP_OVERWRITE_IF,  false, NT_STATUS_OK },
582                 { 6,                            true,  NT_STATUS_INVALID_PARAMETER },
583                 { 6,                            false, NT_STATUS_INVALID_PARAMETER },
584         };
585
586         torture_comment(torture, "Checking SMB2 Open\n");
587
588         smb2_util_unlink(tree, fname);
589         smb2_util_rmdir(tree, dname);
590
591         status = torture_smb2_testdir(tree, DNAME, &h);
592         CHECK_STATUS(status, NT_STATUS_OK);
593
594         ZERO_STRUCT(io.smb2);
595         /* reasonable default parameters */
596         io.generic.level = RAW_OPEN_SMB2;
597         io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
598         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
599         io.smb2.in.alloc_size = 1024*1024;
600         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
601         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
602         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
603         io.smb2.in.create_options = 0;
604         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
605         io.smb2.in.security_flags = 0;
606         io.smb2.in.fname = fname;
607
608         /* test the create disposition */
609         for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
610                 if (open_funcs[i].with_file) {
611                         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
612                         status= smb2_create(tree, mem_ctx, &(io.smb2));
613                         if (!NT_STATUS_IS_OK(status)) {
614                                 torture_comment(torture,
615                                     "Failed to create file %s status %s %d\n",
616                                     fname, nt_errstr(status), i);
617
618                                 ret = false;
619                                 goto done;
620                         }
621                         smb2_util_close(tree, io.smb2.out.file.handle);
622                 }
623                 io.smb2.in.create_disposition = open_funcs[i].create_disp;
624                 status = smb2_create(tree, mem_ctx, &(io.smb2));
625                 if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
626                         torture_comment(torture,
627                             "(%s) incorrect status %s should be %s (i=%d "
628                             "with_file=%d open_disp=%d)\n",
629                          __location__, nt_errstr(status),
630                         nt_errstr(open_funcs[i].correct_status),
631                         i, (int)open_funcs[i].with_file,
632                         (int)open_funcs[i].create_disp);
633
634                         ret = false;
635                         goto done;
636                 }
637                 if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
638                         smb2_util_close(tree, io.smb2.out.file.handle);
639                         smb2_util_unlink(tree, fname);
640                 }
641         }
642
643         /* basic field testing */
644         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
645
646         status = smb2_create(tree, mem_ctx, &(io.smb2));
647         CHECK_STATUS(status, NT_STATUS_OK);
648         h1 = io.smb2.out.file.handle;
649
650         CHECK_VAL(io.smb2.out.oplock_level, 0);
651         CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
652         CHECK_NTTIME(io.smb2.out.create_time, create_time);
653         CHECK_NTTIME(io.smb2.out.access_time, access_time);
654         CHECK_NTTIME(io.smb2.out.write_time, write_time);
655         CHECK_NTTIME(io.smb2.out.change_time, change_time);
656         CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
657         CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
658         CHECK_ALL_INFO(io.smb2.out.size, size);
659
660         /* check fields when the file already existed */
661         smb2_util_close(tree, h1);
662         smb2_util_unlink(tree, fname);
663
664         status = smb2_create_complex_file(tree, fname, &h1);
665         CHECK_STATUS(status, NT_STATUS_OK);
666
667         smb2_util_close(tree, h1);
668
669         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
670         status = smb2_create(tree, mem_ctx, &(io.smb2));
671         CHECK_STATUS(status, NT_STATUS_OK);
672         h1 = io.smb2.out.file.handle;
673
674         CHECK_VAL(io.smb2.out.oplock_level, 0);
675         CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_EXISTED);
676         CHECK_NTTIME(io.smb2.out.create_time, create_time);
677         CHECK_NTTIME(io.smb2.out.access_time, access_time);
678         CHECK_NTTIME(io.smb2.out.write_time, write_time);
679         CHECK_NTTIME(io.smb2.out.change_time, change_time);
680         CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
681         CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
682         CHECK_ALL_INFO(io.smb2.out.size, size);
683         smb2_util_close(tree, h1);
684         smb2_util_unlink(tree, fname);
685
686         /* create a directory */
687         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
688         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
689         io.smb2.in.alloc_size = 0;
690         io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
691         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
692         io.smb2.in.create_options = 0;
693         io.smb2.in.fname = dname;
694         fname = dname;
695
696         smb2_util_rmdir(tree, fname);
697         smb2_util_unlink(tree, fname);
698
699         io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
700         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
701         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
702         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
703                                 NTCREATEX_SHARE_ACCESS_WRITE;
704         status = smb2_create(tree, mem_ctx, &(io.smb2));
705         CHECK_STATUS(status, NT_STATUS_OK);
706         h1 = io.smb2.out.file.handle;
707
708         CHECK_VAL(io.smb2.out.oplock_level, 0);
709         CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
710         CHECK_NTTIME(io.smb2.out.create_time, create_time);
711         CHECK_NTTIME(io.smb2.out.access_time, access_time);
712         CHECK_NTTIME(io.smb2.out.write_time, write_time);
713         CHECK_NTTIME(io.smb2.out.change_time, change_time);
714         CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
715         CHECK_VAL(io.smb2.out.file_attr & ~FILE_ATTRIBUTE_NONINDEXED,
716                   FILE_ATTRIBUTE_DIRECTORY);
717         CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
718         CHECK_ALL_INFO(io.smb2.out.size, size);
719         CHECK_VAL(io.smb2.out.size, 0);
720         CHECK_VAL(io.smb2.out.alloc_size, 0);
721         smb2_util_unlink(tree, fname);
722
723 done:
724         smb2_util_close(tree, h1);
725         smb2_util_unlink(tree, fname);
726         smb2_deltree(tree, DNAME);
727         talloc_free(mem_ctx);
728         return ret;
729 }
730
731 /*
732   test with an already opened and byte range locked file
733 */
734
735 static bool test_smb2_open_brlocked(struct torture_context *torture,
736                                     struct smb2_tree *tree)
737 {
738         union smb_open io, io1;
739         union smb_lock io2;
740         struct smb2_lock_element lock[1];
741         const char *fname = DNAME "\\torture_ntcreatex.txt";
742         NTSTATUS status;
743         bool ret = true;
744         struct smb2_handle h;
745
746         torture_comment(torture,
747                 "Testing SMB2 open with a byte range locked file\n");
748
749         smb2_util_unlink(tree, fname);
750
751         status = torture_smb2_testdir(tree, DNAME, &h);
752         CHECK_STATUS(status, NT_STATUS_OK);
753
754         ZERO_STRUCT(io.smb2);
755         io.generic.level = RAW_OPEN_SMB2;
756         io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
757         io.smb2.in.desired_access = 0x2019f;
758         io.smb2.in.alloc_size = 0;
759         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
760         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
761                 NTCREATEX_SHARE_ACCESS_WRITE;
762         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
763         io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
764         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
765         io.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
766         io.smb2.in.fname = fname;
767
768         status = smb2_create(tree, torture, &(io.smb2));
769         CHECK_STATUS(status, NT_STATUS_OK);
770
771         ZERO_STRUCT(io2.smb2);
772         io2.smb2.level = RAW_LOCK_SMB2;
773         io2.smb2.in.file.handle = io.smb2.out.file.handle;
774         io2.smb2.in.lock_count = 1;
775
776         lock[0].offset = 0;
777         lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
778                         SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
779         io2.smb2.in.locks = &lock[0];
780         status = smb2_lock(tree, &(io2.smb2));
781         CHECK_STATUS(status, NT_STATUS_OK);
782
783         ZERO_STRUCT(io1.smb2);
784         io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
785         io1.smb2.in.desired_access = 0x20196;
786         io1.smb2.in.alloc_size = 0;
787         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
788         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
789                 NTCREATEX_SHARE_ACCESS_WRITE;
790         io1.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
791         io1.smb2.in.create_options = 0;
792         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
793         io1.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
794         io1.smb2.in.fname = fname;
795
796         status = smb2_create(tree, torture, &(io1.smb2));
797         CHECK_STATUS(status, NT_STATUS_OK);
798
799         smb2_util_close(tree, io.smb2.out.file.handle);
800         smb2_util_close(tree, io1.smb2.out.file.handle);
801         smb2_util_unlink(tree, fname);
802         smb2_deltree(tree, DNAME);
803
804         return ret;
805 }
806
807 /* A little torture test to expose a race condition in Samba 3.0.20 ... :-) */
808
809 static bool test_smb2_open_multi(struct torture_context *torture,
810                                 struct smb2_tree *tree)
811 {
812         TALLOC_CTX *mem_ctx = talloc_init("torture_test_oplock_multi");
813         const char *fname = "test_oplock.dat";
814         NTSTATUS status;
815         bool ret = true;
816         union smb_open io;
817         struct smb2_tree **trees;
818         struct smb2_request **requests;
819         union smb_open *ios;
820         int i, num_files = 3;
821         int num_ok = 0;
822         int num_collision = 0;
823
824         if (mem_ctx == NULL) {
825                 ret = false;
826                 goto done;
827         }
828
829         torture_comment(torture,
830                 "Testing SMB2 Open with multiple connections\n");
831         trees = talloc_array(mem_ctx, struct smb2_tree *, num_files);
832         requests = talloc_array(mem_ctx, struct smb2_request *, num_files);
833         ios = talloc_array(mem_ctx, union smb_open, num_files);
834         if ((torture->ev == NULL) || (trees == NULL) || (requests == NULL) ||
835             (ios == NULL)) {
836                 torture_comment(torture, ("talloc failed\n"));
837                 ret = false;
838                 goto done;
839         }
840
841         tree->session->transport->options.request_timeout = 60;
842
843         for (i=0; i<num_files; i++) {
844                 if (!torture_smb2_connection(torture, &(trees[i]))) {
845                         torture_comment(torture,
846                                 "Could not open %d'th connection\n", i);
847                         ret = false;
848                         goto done;
849                 }
850                 trees[i]->session->transport->options.request_timeout = 60;
851         }
852
853         /* cleanup */
854         smb2_util_unlink(tree, fname);
855
856         /*
857           base ntcreatex parms
858         */
859         ZERO_STRUCT(io.smb2);
860         io.generic.level = RAW_OPEN_SMB2;
861         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
862         io.smb2.in.alloc_size = 0;
863         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
864         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
865                 NTCREATEX_SHARE_ACCESS_WRITE|
866                 NTCREATEX_SHARE_ACCESS_DELETE;
867         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
868         io.smb2.in.create_options = 0;
869         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
870         io.smb2.in.security_flags = 0;
871         io.smb2.in.fname = fname;
872         io.smb2.in.create_flags = 0;
873
874         for (i=0; i<num_files; i++) {
875                 ios[i] = io;
876                 requests[i] = smb2_create_send(trees[i], &(ios[i].smb2));
877                 if (requests[i] == NULL) {
878                         torture_comment(torture,
879                                 "could not send %d'th request\n", i);
880                         ret = false;
881                         goto done;
882                 }
883         }
884
885         torture_comment(torture, "waiting for replies\n");
886         while (1) {
887                 bool unreplied = false;
888                 for (i=0; i<num_files; i++) {
889                         if (requests[i] == NULL) {
890                                 continue;
891                         }
892                         if (requests[i]->state < SMB2_REQUEST_DONE) {
893                                 unreplied = true;
894                                 break;
895                         }
896                         status = smb2_create_recv(requests[i], mem_ctx,
897                                                   &(ios[i].smb2));
898
899                         torture_comment(torture,
900                                 "File %d returned status %s\n", i,
901                                 nt_errstr(status));
902
903                         if (NT_STATUS_IS_OK(status)) {
904                                 num_ok += 1;
905                         }
906
907                         if (NT_STATUS_EQUAL(status,
908                                             NT_STATUS_OBJECT_NAME_COLLISION)) {
909                                 num_collision += 1;
910                         }
911
912                         requests[i] = NULL;
913                 }
914                 if (!unreplied) {
915                         break;
916                 }
917
918                 if (event_loop_once(torture->ev) != 0) {
919                         torture_comment(torture, "event_loop_once failed\n");
920                         ret = false;
921                         goto done;
922                 }
923         }
924
925         if ((num_ok != 1) || (num_ok + num_collision != num_files)) {
926                 ret = false;
927         }
928 done:
929         talloc_free(mem_ctx);
930         smb2_deltree(tree, fname);
931
932         return ret;
933 }
934
935 /*
936   test opening for delete on a read-only attribute file.
937 */
938
939 static bool test_smb2_open_for_delete(struct torture_context *torture,
940                                       struct smb2_tree *tree)
941 {
942         union smb_open io;
943         union smb_fileinfo finfo;
944         const char *fname = DNAME "\\torture_open_for_delete.txt";
945         NTSTATUS status;
946         struct smb2_handle h, h1;
947         bool ret = true;
948
949         torture_comment(torture,
950                 "Checking SMB2_OPEN for delete on a readonly file.\n");
951         smb2_util_unlink(tree, fname);
952         smb2_deltree(tree, fname);
953
954         status = torture_smb2_testdir(tree, DNAME, &h);
955         CHECK_STATUS(status, NT_STATUS_OK);
956
957         /* reasonable default parameters */
958         ZERO_STRUCT(io.smb2);
959         io.generic.level = RAW_OPEN_SMB2;
960         io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
961         io.smb2.in.alloc_size = 0;
962         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
963         io.smb2.in.file_attributes = FILE_ATTRIBUTE_READONLY;
964         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
965         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
966         io.smb2.in.create_options = 0;
967         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
968         io.smb2.in.security_flags = 0;
969         io.smb2.in.fname = fname;
970
971         /* Create the readonly file. */
972
973         status = smb2_create(tree, torture, &(io.smb2));
974         CHECK_STATUS(status, NT_STATUS_OK);
975         h1 = io.smb2.out.file.handle;
976
977         CHECK_VAL(io.smb2.out.oplock_level, 0);
978         io.smb2.in.create_options = 0;
979         CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
980         CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
981         smb2_util_close(tree, h1);
982
983         /* Now try and open for delete only - should succeed. */
984         io.smb2.in.desired_access = SEC_STD_DELETE;
985         io.smb2.in.file_attributes = 0;
986         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
987                                 NTCREATEX_SHARE_ACCESS_WRITE |
988                                 NTCREATEX_SHARE_ACCESS_DELETE;
989         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
990         status = smb2_create(tree, torture, &(io.smb2));
991         CHECK_STATUS(status, NT_STATUS_OK);
992
993         smb2_util_unlink(tree, fname);
994
995         smb2_util_close(tree, h1);
996         smb2_util_unlink(tree, fname);
997         smb2_deltree(tree, DNAME);
998
999         return ret;
1000 }
1001
1002 /*
1003   test SMB2 open with a leading slash on the path.
1004   Trying to create a directory with a leading slash
1005   should give NT_STATUS_INVALID_PARAMETER error
1006 */
1007 static bool test_smb2_leading_slash(struct torture_context *torture,
1008                                     struct smb2_tree *tree)
1009 {
1010         union smb_open io;
1011         const char *dnameslash = "\\"DNAME;
1012         NTSTATUS status;
1013         bool ret = true;
1014
1015         torture_comment(torture,
1016                 "Trying to create a directory with leading slash on path\n");
1017         smb2_deltree(tree, dnameslash);
1018
1019         ZERO_STRUCT(io.smb2);
1020         io.generic.level = RAW_OPEN_SMB2;
1021         io.smb2.in.oplock_level = 0;
1022         io.smb2.in.desired_access = SEC_RIGHTS_DIR_ALL;
1023         io.smb2.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
1024         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1025         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1026                                 NTCREATEX_SHARE_ACCESS_WRITE |
1027                                 NTCREATEX_SHARE_ACCESS_DELETE;
1028         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1029         io.smb2.in.fname = dnameslash;
1030
1031         status = smb2_create(tree, tree, &(io.smb2));
1032         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1033
1034         smb2_deltree(tree, dnameslash);
1035         return ret;
1036 }
1037
1038
1039 /*
1040    basic testing of SMB2 read
1041 */
1042 struct torture_suite *torture_smb2_create_init(void)
1043 {
1044         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "CREATE");
1045
1046         torture_suite_add_1smb2_test(suite, "GENTEST", test_create_gentest);
1047         torture_suite_add_1smb2_test(suite, "BLOB", test_create_blob);
1048         torture_suite_add_1smb2_test(suite, "ACL", test_create_acl);
1049         torture_suite_add_1smb2_test(suite, "OPEN", test_smb2_open);
1050         torture_suite_add_1smb2_test(suite, "BRLOCKED", test_smb2_open_brlocked);
1051         torture_suite_add_1smb2_test(suite, "MULTI", test_smb2_open_multi);
1052         torture_suite_add_1smb2_test(suite, "DELETE", test_smb2_open_for_delete);
1053         torture_suite_add_1smb2_test(suite, "LEADING-SLASH", test_smb2_leading_slash);
1054
1055         suite->description = talloc_strdup(suite, "SMB2-CREATE tests");
1056
1057         return suite;
1058 }