Adds the impersonation level in ntcreatex requests to SAMBA 3 misc torture test
[ira/wip.git] / source4 / torture / raw / samba3misc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Test some misc Samba3 code paths
4    Copyright (C) Volker Lendecke 2006
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "torture/torture.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/raw/raw_proto.h"
24 #include "system/time.h"
25 #include "system/filesys.h"
26 #include "libcli/libcli.h"
27 #include "torture/util.h"
28 #include "lib/events/events.h"
29 #include "param/param.h"
30
31 #define CHECK_STATUS(status, correct) do { \
32         if (!NT_STATUS_EQUAL(status, correct)) { \
33                 printf("(%s) Incorrect status %s - should be %s\n", \
34                        __location__, nt_errstr(status), nt_errstr(correct)); \
35                 ret = false; \
36         } \
37 } while (0)
38
39 bool torture_samba3_checkfsp(struct torture_context *torture)
40 {
41         struct smbcli_state *cli;
42         const char *fname = "test.txt";
43         const char *dirname = "testdir";
44         int fnum;
45         NTSTATUS status;
46         bool ret = true;
47         TALLOC_CTX *mem_ctx;
48         ssize_t nread;
49         char buf[16];
50         struct smbcli_tree *tree2;
51
52         if ((mem_ctx = talloc_init("torture_samba3_checkfsp")) == NULL) {
53                 d_printf("talloc_init failed\n");
54                 return false;
55         }
56
57         if (!torture_open_connection_share(
58                     torture, &cli, torture, torture_setting_string(torture, "host", NULL),
59                     torture_setting_string(torture, "share", NULL), torture->ev)) {
60                 d_printf("torture_open_connection_share failed\n");
61                 ret = false;
62                 goto done;
63         }
64
65         smbcli_deltree(cli->tree, dirname);
66
67         status = torture_second_tcon(torture, cli->session,
68                                      torture_setting_string(torture, "share", NULL),
69                                      &tree2);
70         CHECK_STATUS(status, NT_STATUS_OK);
71         if (!NT_STATUS_IS_OK(status))
72                 goto done;
73
74         /* Try a read on an invalid FID */
75
76         nread = smbcli_read(cli->tree, 4711, buf, 0, sizeof(buf));
77         CHECK_STATUS(smbcli_nt_error(cli->tree), NT_STATUS_INVALID_HANDLE);
78
79         /* Try a read on a directory handle */
80
81         status = smbcli_mkdir(cli->tree, dirname);
82         if (!NT_STATUS_IS_OK(status)) {
83                 d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status));
84                 ret = false;
85                 goto done;
86         }
87
88         /* Open the directory */
89         {
90                 union smb_open io;
91                 io.generic.level = RAW_OPEN_NTCREATEX;
92                 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
93                 io.ntcreatex.in.root_fid = 0;
94                 io.ntcreatex.in.security_flags = 0;
95                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
96                 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
97                 io.ntcreatex.in.alloc_size = 0;
98                 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
99                 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
100                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
101                 io.ntcreatex.in.create_options = 0;
102                 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
103                 io.ntcreatex.in.fname = dirname;
104                 status = smb_raw_open(cli->tree, mem_ctx, &io);
105                 if (!NT_STATUS_IS_OK(status)) {
106                         d_printf("smb_open on the directory failed: %s\n",
107                                  nt_errstr(status));
108                         ret = false;
109                         goto done;
110                 }
111                 fnum = io.ntcreatex.out.file.fnum;
112         }
113
114         /* Try a read on the directory */
115
116         nread = smbcli_read(cli->tree, fnum, buf, 0, sizeof(buf));
117         if (nread >= 0) {
118                 d_printf("smbcli_read on a directory succeeded, expected "
119                          "failure\n");
120                 ret = false;
121         }
122
123         CHECK_STATUS(smbcli_nt_error(cli->tree),
124                      NT_STATUS_INVALID_DEVICE_REQUEST);
125
126         /* Same test on the second tcon */
127
128         nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf));
129         if (nread >= 0) {
130                 d_printf("smbcli_read on a directory succeeded, expected "
131                          "failure\n");
132                 ret = false;
133         }
134
135         CHECK_STATUS(smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE);
136
137         smbcli_close(cli->tree, fnum);
138
139         /* Try a normal file read on a second tcon */
140
141         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
142         if (fnum == -1) {
143                 d_printf("Failed to create %s - %s\n", fname,
144                          smbcli_errstr(cli->tree));
145                 ret = false;
146                 goto done;
147         }
148
149         nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf));
150         CHECK_STATUS(smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE);
151
152         smbcli_close(cli->tree, fnum);
153
154  done:
155         smbcli_deltree(cli->tree, dirname);
156         torture_close_connection(cli);
157         talloc_free(mem_ctx);
158
159         return ret;
160 }
161
162 static NTSTATUS raw_smbcli_open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum)
163 {
164         union smb_open open_parms;
165         uint_t openfn=0;
166         uint_t accessmode=0;
167         TALLOC_CTX *mem_ctx;
168         NTSTATUS status;
169
170         mem_ctx = talloc_init("raw_open");
171         if (!mem_ctx) return NT_STATUS_NO_MEMORY;
172
173         if (flags & O_CREAT) {
174                 openfn |= OPENX_OPEN_FUNC_CREATE;
175         }
176         if (!(flags & O_EXCL)) {
177                 if (flags & O_TRUNC) {
178                         openfn |= OPENX_OPEN_FUNC_TRUNC;
179                 } else {
180                         openfn |= OPENX_OPEN_FUNC_OPEN;
181                 }
182         }
183
184         accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
185
186         if ((flags & O_ACCMODE) == O_RDWR) {
187                 accessmode |= OPENX_MODE_ACCESS_RDWR;
188         } else if ((flags & O_ACCMODE) == O_WRONLY) {
189                 accessmode |= OPENX_MODE_ACCESS_WRITE;
190         } else if ((flags & O_ACCMODE) == O_RDONLY) {
191                 accessmode |= OPENX_MODE_ACCESS_READ;
192         }
193
194 #if defined(O_SYNC)
195         if ((flags & O_SYNC) == O_SYNC) {
196                 accessmode |= OPENX_MODE_WRITE_THRU;
197         }
198 #endif
199
200         if (share_mode == DENY_FCB) {
201                 accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
202         }
203
204         open_parms.openx.level = RAW_OPEN_OPENX;
205         open_parms.openx.in.flags = 0;
206         open_parms.openx.in.open_mode = accessmode;
207         open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
208         open_parms.openx.in.file_attrs = 0;
209         open_parms.openx.in.write_time = 0;
210         open_parms.openx.in.open_func = openfn;
211         open_parms.openx.in.size = 0;
212         open_parms.openx.in.timeout = 0;
213         open_parms.openx.in.fname = fname;
214
215         status = smb_raw_open(tree, mem_ctx, &open_parms);
216         talloc_free(mem_ctx);
217
218         if (fnum && NT_STATUS_IS_OK(status)) {
219                 *fnum = open_parms.openx.out.file.fnum;
220         }
221
222         return status;
223 }
224
225 static NTSTATUS raw_smbcli_t2open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum)
226 {
227         union smb_open io;
228         uint_t openfn=0;
229         uint_t accessmode=0;
230         TALLOC_CTX *mem_ctx;
231         NTSTATUS status;
232
233         mem_ctx = talloc_init("raw_t2open");
234         if (!mem_ctx) return NT_STATUS_NO_MEMORY;
235
236         if (flags & O_CREAT) {
237                 openfn |= OPENX_OPEN_FUNC_CREATE;
238         }
239         if (!(flags & O_EXCL)) {
240                 if (flags & O_TRUNC) {
241                         openfn |= OPENX_OPEN_FUNC_TRUNC;
242                 } else {
243                         openfn |= OPENX_OPEN_FUNC_OPEN;
244                 }
245         }
246
247         accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
248
249         if ((flags & O_ACCMODE) == O_RDWR) {
250                 accessmode |= OPENX_MODE_ACCESS_RDWR;
251         } else if ((flags & O_ACCMODE) == O_WRONLY) {
252                 accessmode |= OPENX_MODE_ACCESS_WRITE;
253         } else if ((flags & O_ACCMODE) == O_RDONLY) {
254                 accessmode |= OPENX_MODE_ACCESS_READ;
255         }
256
257 #if defined(O_SYNC)
258         if ((flags & O_SYNC) == O_SYNC) {
259                 accessmode |= OPENX_MODE_WRITE_THRU;
260         }
261 #endif
262
263         if (share_mode == DENY_FCB) {
264                 accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
265         }
266
267         memset(&io, '\0', sizeof(io));
268         io.t2open.level = RAW_OPEN_T2OPEN;
269         io.t2open.in.flags = 0;
270         io.t2open.in.open_mode = accessmode;
271         io.t2open.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
272         io.t2open.in.file_attrs = 0;
273         io.t2open.in.write_time = 0;
274         io.t2open.in.open_func = openfn;
275         io.t2open.in.size = 0;
276         io.t2open.in.timeout = 0;
277         io.t2open.in.fname = fname;
278
279         io.t2open.in.num_eas = 1;
280         io.t2open.in.eas = talloc_array(mem_ctx, struct ea_struct, io.t2open.in.num_eas);
281         io.t2open.in.eas[0].flags = 0;
282         io.t2open.in.eas[0].name.s = ".CLASSINFO";
283         io.t2open.in.eas[0].value = data_blob_talloc(mem_ctx, "first value", 11);
284
285         status = smb_raw_open(tree, mem_ctx, &io);
286         talloc_free(mem_ctx);
287
288         if (fnum && NT_STATUS_IS_OK(status)) {
289                 *fnum = io.openx.out.file.fnum;
290         }
291
292         return status;
293 }
294
295 static NTSTATUS raw_smbcli_ntcreate(struct smbcli_tree *tree, const char *fname, int *fnum)
296 {
297         union smb_open io;
298         TALLOC_CTX *mem_ctx;
299         NTSTATUS status;
300
301         mem_ctx = talloc_init("raw_t2open");
302         if (!mem_ctx) return NT_STATUS_NO_MEMORY;
303
304         memset(&io, '\0', sizeof(io));
305         io.generic.level = RAW_OPEN_NTCREATEX;
306         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
307         io.ntcreatex.in.root_fid = 0;
308         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
309         io.ntcreatex.in.alloc_size = 0;
310         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
311         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
312         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
313         io.ntcreatex.in.create_options = 0;
314         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
315         io.ntcreatex.in.security_flags = 0;
316         io.ntcreatex.in.fname = fname;
317
318         status = smb_raw_open(tree, mem_ctx, &io);
319         talloc_free(mem_ctx);
320
321         if (fnum && NT_STATUS_IS_OK(status)) {
322                 *fnum = io.openx.out.file.fnum;
323         }
324
325         return status;
326 }
327
328
329 bool torture_samba3_badpath(struct torture_context *torture)
330 {
331         struct smbcli_state *cli_nt;
332         struct smbcli_state *cli_dos;
333         const char *fname = "test.txt";
334         const char *fname1 = "test1.txt";
335         const char *dirname = "testdir";
336         char *fpath;
337         char *fpath1;
338         int fnum;
339         NTSTATUS status;
340         bool ret = true;
341         TALLOC_CTX *mem_ctx;
342         bool nt_status_support;
343
344         if (!(mem_ctx = talloc_init("torture_samba3_badpath"))) {
345                 d_printf("talloc_init failed\n");
346                 return false;
347         }
348
349         nt_status_support = lp_nt_status_support(torture->lp_ctx);
350
351         if (!lp_set_cmdline(torture->lp_ctx, "nt status support", "yes")) {
352                 printf("Could not set 'nt status support = yes'\n");
353                 goto fail;
354         }
355
356         if (!torture_open_connection(&cli_nt, torture, 0)) {
357                 goto fail;
358         }
359
360         if (!lp_set_cmdline(torture->lp_ctx, "nt status support", "no")) {
361                 printf("Could not set 'nt status support = yes'\n");
362                 goto fail;
363         }
364
365         if (!torture_open_connection(&cli_dos, torture, 1)) {
366                 goto fail;
367         }
368
369         if (!lp_set_cmdline(torture->lp_ctx, "nt status support",
370                             nt_status_support ? "yes":"no")) {
371                 printf("Could not reset 'nt status support = yes'");
372                 goto fail;
373         }
374
375         smbcli_deltree(cli_nt->tree, dirname);
376
377         status = smbcli_mkdir(cli_nt->tree, dirname);
378         if (!NT_STATUS_IS_OK(status)) {
379                 d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status));
380                 ret = false;
381                 goto done;
382         }
383
384         status = smbcli_chkpath(cli_nt->tree, dirname);
385         CHECK_STATUS(status, NT_STATUS_OK);
386
387         status = smbcli_chkpath(cli_nt->tree,
388                                 talloc_asprintf(mem_ctx, "%s\\bla", dirname));
389         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
390
391         status = smbcli_chkpath(cli_dos->tree,
392                                 talloc_asprintf(mem_ctx, "%s\\bla", dirname));
393         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
394
395         status = smbcli_chkpath(cli_nt->tree,
396                                 talloc_asprintf(mem_ctx, "%s\\bla\\blub",
397                                                 dirname));
398         CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND);
399         status = smbcli_chkpath(cli_dos->tree,
400                                 talloc_asprintf(mem_ctx, "%s\\bla\\blub",
401                                                 dirname));
402         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
403
404         if (!(fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname))) {
405                 goto fail;
406         }
407         fnum = smbcli_open(cli_nt->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
408         if (fnum == -1) {
409                 d_printf("Could not create file %s: %s\n", fpath,
410                          smbcli_errstr(cli_nt->tree));
411                 goto fail;
412         }
413         smbcli_close(cli_nt->tree, fnum);
414
415         if (!(fpath1 = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname1))) {
416                 goto fail;
417         }
418         fnum = smbcli_open(cli_nt->tree, fpath1, O_RDWR | O_CREAT, DENY_NONE);
419         if (fnum == -1) {
420                 d_printf("Could not create file %s: %s\n", fpath1,
421                          smbcli_errstr(cli_nt->tree));
422                 goto fail;
423         }
424         smbcli_close(cli_nt->tree, fnum);
425
426         /*
427          * Do a whole bunch of error code checks on chkpath
428          */
429
430         status = smbcli_chkpath(cli_nt->tree, fpath);
431         CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
432         status = smbcli_chkpath(cli_dos->tree, fpath);
433         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
434
435         status = smbcli_chkpath(cli_nt->tree, "..");
436         CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
437         status = smbcli_chkpath(cli_dos->tree, "..");
438         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
439
440         status = smbcli_chkpath(cli_nt->tree, ".");
441         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
442         status = smbcli_chkpath(cli_dos->tree, ".");
443         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
444
445         status = smbcli_chkpath(cli_nt->tree, "\t");
446         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
447         status = smbcli_chkpath(cli_dos->tree, "\t");
448         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
449
450         status = smbcli_chkpath(cli_nt->tree, "\t\\bla");
451         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
452         status = smbcli_chkpath(cli_dos->tree, "\t\\bla");
453         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
454
455         status = smbcli_chkpath(cli_nt->tree, "<");
456         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
457         status = smbcli_chkpath(cli_dos->tree, "<");
458         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
459
460         status = smbcli_chkpath(cli_nt->tree, "<\\bla");
461         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
462         status = smbcli_chkpath(cli_dos->tree, "<\\bla");
463         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
464
465         /*
466          * .... And the same gang against getatr. Note that the DOS error codes
467          * differ....
468          */
469
470         status = smbcli_getatr(cli_nt->tree, fpath, NULL, NULL, NULL);
471         CHECK_STATUS(status, NT_STATUS_OK);
472         status = smbcli_getatr(cli_dos->tree, fpath, NULL, NULL, NULL);
473         CHECK_STATUS(status, NT_STATUS_OK);
474
475         status = smbcli_getatr(cli_nt->tree, "..", NULL, NULL, NULL);
476         CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
477         status = smbcli_getatr(cli_dos->tree, "..", NULL, NULL, NULL);
478         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
479
480         status = smbcli_getatr(cli_nt->tree, ".", NULL, NULL, NULL);
481         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
482         status = smbcli_getatr(cli_dos->tree, ".", NULL, NULL, NULL);
483         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
484
485         status = smbcli_getatr(cli_nt->tree, "\t", NULL, NULL, NULL);
486         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
487         status = smbcli_getatr(cli_dos->tree, "\t", NULL, NULL, NULL);
488         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
489
490         status = smbcli_getatr(cli_nt->tree, "\t\\bla", NULL, NULL, NULL);
491         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
492         status = smbcli_getatr(cli_dos->tree, "\t\\bla", NULL, NULL, NULL);
493         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
494
495         status = smbcli_getatr(cli_nt->tree, "<", NULL, NULL, NULL);
496         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
497         status = smbcli_getatr(cli_dos->tree, "<", NULL, NULL, NULL);
498         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
499
500         status = smbcli_getatr(cli_nt->tree, "<\\bla", NULL, NULL, NULL);
501         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
502         status = smbcli_getatr(cli_dos->tree, "<\\bla", NULL, NULL, NULL);
503         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
504
505         /* Try the same set with openX. */
506
507         status = raw_smbcli_open(cli_nt->tree, "..", O_RDONLY, DENY_NONE, NULL);
508         CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
509         status = raw_smbcli_open(cli_dos->tree, "..", O_RDONLY, DENY_NONE, NULL);
510         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
511
512         status = raw_smbcli_open(cli_nt->tree, ".", O_RDONLY, DENY_NONE, NULL);
513         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
514         status = raw_smbcli_open(cli_dos->tree, ".", O_RDONLY, DENY_NONE, NULL);
515         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
516
517         status = raw_smbcli_open(cli_nt->tree, "\t", O_RDONLY, DENY_NONE, NULL);
518         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
519         status = raw_smbcli_open(cli_dos->tree, "\t", O_RDONLY, DENY_NONE, NULL);
520         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
521
522         status = raw_smbcli_open(cli_nt->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL);
523         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
524         status = raw_smbcli_open(cli_dos->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL);
525         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
526
527         status = raw_smbcli_open(cli_nt->tree, "<", O_RDONLY, DENY_NONE, NULL);
528         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
529         status = raw_smbcli_open(cli_dos->tree, "<", O_RDONLY, DENY_NONE, NULL);
530         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
531
532         status = raw_smbcli_open(cli_nt->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL);
533         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
534         status = raw_smbcli_open(cli_dos->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL);
535         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
536
537         /* Let's test EEXIST error code mapping. */
538         status = raw_smbcli_open(cli_nt->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
539         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
540         status = raw_smbcli_open(cli_dos->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
541         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRfilexists));
542
543         status = raw_smbcli_t2open(cli_nt->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
544         if (!NT_STATUS_EQUAL(status, NT_STATUS_EAS_NOT_SUPPORTED)
545             || !torture_setting_bool(torture, "samba3", false)) {
546                 /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */
547                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
548         }
549         status = raw_smbcli_t2open(cli_dos->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
550         if (!NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS,ERReasnotsupported))
551             || !torture_setting_bool(torture, "samba3", false)) {
552                 /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */
553                 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRfilexists));
554         }
555
556         status = raw_smbcli_ntcreate(cli_nt->tree, fpath, NULL);
557         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
558         status = raw_smbcli_ntcreate(cli_dos->tree, fpath, NULL);
559         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRfilexists));
560
561         /* Try the rename test. */
562         {
563                 union smb_rename io;
564                 memset(&io, '\0', sizeof(io));
565                 io.rename.in.pattern1 = fpath1;
566                 io.rename.in.pattern2 = fpath;
567
568                 /* Try with SMBmv rename. */
569                 status = smb_raw_rename(cli_nt->tree, &io);
570                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
571                 status = smb_raw_rename(cli_dos->tree, &io);
572                 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRrename));
573
574                 /* Try with NT rename. */
575                 io.generic.level = RAW_RENAME_NTRENAME;
576                 io.ntrename.in.old_name = fpath1;
577                 io.ntrename.in.new_name = fpath;
578                 io.ntrename.in.attrib = 0;
579                 io.ntrename.in.cluster_size = 0;
580                 io.ntrename.in.flags = RENAME_FLAG_RENAME;
581
582                 status = smb_raw_rename(cli_nt->tree, &io);
583                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
584                 status = smb_raw_rename(cli_dos->tree, &io);
585                 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRrename));
586         }
587
588         goto done;
589
590  fail:
591         ret = false;
592
593  done:
594         if (cli_nt != NULL) {
595                 smbcli_deltree(cli_nt->tree, dirname);
596                 torture_close_connection(cli_nt);
597         }
598         if (cli_dos != NULL) {
599                 torture_close_connection(cli_dos);
600         }
601         talloc_free(mem_ctx);
602
603         return ret;
604 }
605
606 static void count_fn(struct clilist_file_info *info, const char *name,
607                      void *private_data)
608 {
609         int *counter = (int *)private_data;
610         *counter += 1;
611 }
612
613 bool torture_samba3_caseinsensitive(struct torture_context *torture)
614 {
615         struct smbcli_state *cli;
616         TALLOC_CTX *mem_ctx;
617         NTSTATUS status;
618         const char *dirname = "insensitive";
619         const char *ucase_dirname = "InSeNsItIvE";
620         const char *fname = "foo";
621         char *fpath;
622         int fnum;
623         int counter = 0;
624         bool ret = true;
625
626         if (!(mem_ctx = talloc_init("torture_samba3_caseinsensitive"))) {
627                 d_printf("talloc_init failed\n");
628                 return false;
629         }
630
631         if (!torture_open_connection(&cli, torture, 0)) {
632                 goto done;
633         }
634
635         smbcli_deltree(cli->tree, dirname);
636
637         status = smbcli_mkdir(cli->tree, dirname);
638         if (!NT_STATUS_IS_OK(status)) {
639                 d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status));
640                 goto done;
641         }
642
643         if (!(fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname))) {
644                 goto done;
645         }
646         fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
647         if (fnum == -1) {
648                 d_printf("Could not create file %s: %s\n", fpath,
649                          smbcli_errstr(cli->tree));
650                 goto done;
651         }
652         smbcli_close(cli->tree, fnum);
653
654         smbcli_list(cli->tree, talloc_asprintf(
655                             mem_ctx, "%s\\*", ucase_dirname),
656                     FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN
657                     |FILE_ATTRIBUTE_SYSTEM,
658                     count_fn, (void *)&counter);
659
660         if (counter == 3) {
661                 ret = true;
662         }
663         else {
664                 d_fprintf(stderr, "expected 3 entries, got %d\n", counter);
665                 ret = false;
666         }
667
668  done:
669         talloc_free(mem_ctx);
670         return ret;
671 }
672
673 static void close_locked_file(struct tevent_context *ev,
674                               struct tevent_timer *te,
675                               struct timeval now,
676                               void *private_data)
677 {
678         int *pfd = (int *)private_data;
679
680         TALLOC_FREE(te);
681
682         if (*pfd != -1) {
683                 close(*pfd);
684                 *pfd = -1;
685         }
686 }
687
688 struct lock_result_state {
689         NTSTATUS status;
690         bool done;
691 };
692
693 static void receive_lock_result(struct smbcli_request *req)
694 {
695         struct lock_result_state *state =
696                 (struct lock_result_state *)req->async.private_data;
697
698         state->status = smbcli_request_simple_recv(req);
699         state->done = true;
700 }
701
702 /*
703  * Check that Samba3 correctly deals with conflicting posix byte range locks
704  * on an underlying file
705  *
706  * Note: This test depends on "posix locking = yes".
707  * Note: To run this test, use "--option=torture:localdir=<LOCALDIR>"
708  */
709
710 bool torture_samba3_posixtimedlock(struct torture_context *tctx)
711 {
712         struct smbcli_state *cli;
713         NTSTATUS status;
714         bool ret = true;
715         const char *dirname = "posixlock";
716         const char *fname = "locked";
717         const char *fpath;
718         const char *localdir;
719         const char *localname;
720         int fnum = -1;
721
722         int fd = -1;
723         struct flock posix_lock;
724
725         union smb_lock io;
726         struct smb_lock_entry lock_entry;
727         struct smbcli_request *req;
728         struct lock_result_state lock_result;
729
730         struct tevent_timer *te;
731
732         if (!torture_open_connection(&cli, tctx, 0)) {
733                 ret = false;
734                 goto done;
735         }
736
737         smbcli_deltree(cli->tree, dirname);
738
739         status = smbcli_mkdir(cli->tree, dirname);
740         if (!NT_STATUS_IS_OK(status)) {
741                 torture_warning(tctx, "smbcli_mkdir failed: %s\n",
742                                 nt_errstr(status));
743                 ret = false;
744                 goto done;
745         }
746
747         if (!(fpath = talloc_asprintf(tctx, "%s\\%s", dirname, fname))) {
748                 torture_warning(tctx, "talloc failed\n");
749                 ret = false;
750                 goto done;
751         }
752         fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
753         if (fnum == -1) {
754                 torture_warning(tctx, "Could not create file %s: %s\n", fpath,
755                                 smbcli_errstr(cli->tree));
756                 ret = false;
757                 goto done;
758         }
759
760         if (!(localdir = torture_setting_string(tctx, "localdir", NULL))) {
761                 torture_warning(tctx, "Need 'localdir' setting\n");
762                 ret = false;
763                 goto done;
764         }
765
766         if (!(localname = talloc_asprintf(tctx, "%s/%s/%s", localdir, dirname,
767                                           fname))) {
768                 torture_warning(tctx, "talloc failed\n");
769                 ret = false;
770                 goto done;
771         }
772
773         /*
774          * Lock a byte range from posix
775          */
776
777         fd = open(localname, O_RDWR);
778         if (fd == -1) {
779                 torture_warning(tctx, "open(%s) failed: %s\n",
780                                 localname, strerror(errno));
781                 goto done;
782         }
783
784         posix_lock.l_type = F_WRLCK;
785         posix_lock.l_whence = SEEK_SET;
786         posix_lock.l_start = 0;
787         posix_lock.l_len = 1;
788
789         if (fcntl(fd, F_SETLK, &posix_lock) == -1) {
790                 torture_warning(tctx, "fcntl failed: %s\n", strerror(errno));
791                 ret = false;
792                 goto done;
793         }
794
795         /*
796          * Try a cifs brlock without timeout to see if posix locking = yes
797          */
798
799         io.lockx.in.ulock_cnt = 0;
800         io.lockx.in.lock_cnt = 1;
801
802         lock_entry.count = 1;
803         lock_entry.offset = 0;
804         lock_entry.pid = cli->tree->session->pid;
805
806         io.lockx.level = RAW_LOCK_LOCKX;
807         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
808         io.lockx.in.timeout = 0;
809         io.lockx.in.locks = &lock_entry;
810         io.lockx.in.file.fnum = fnum;
811
812         status = smb_raw_lock(cli->tree, &io);
813
814         ret = true;
815         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
816
817         if (!ret) {
818                 goto done;
819         }
820
821         /*
822          * Now fire off a timed brlock, unlock the posix lock and see if the
823          * timed lock gets through.
824          */
825
826         io.lockx.in.timeout = 5000;
827
828         req = smb_raw_lock_send(cli->tree, &io);
829         if (req == NULL) {
830                 torture_warning(tctx, "smb_raw_lock_send failed\n");
831                 ret = false;
832                 goto done;
833         }
834
835         lock_result.done = false;
836         req->async.fn = receive_lock_result;
837         req->async.private_data = &lock_result;
838
839         te = tevent_add_timer(req->transport->socket->event.ctx,
840                               tctx, timeval_current_ofs(1, 0),
841                               close_locked_file, &fd);
842         if (te == NULL) {
843                 torture_warning(tctx, "tevent_add_timer failed\n");
844                 ret = false;
845                 goto done;
846         }
847
848         while ((fd != -1) || (!lock_result.done)) {
849                 if (tevent_loop_once(req->transport->socket->event.ctx)
850                     == -1) {
851                         torture_warning(tctx, "tevent_loop_once failed: %s\n",
852                                         strerror(errno));
853                         ret = false;
854                         goto done;
855                 }
856         }
857
858         CHECK_STATUS(lock_result.status, NT_STATUS_OK);
859
860  done:
861         if (fnum != -1) {
862                 smbcli_close(cli->tree, fnum);
863         }
864         if (fd != -1) {
865                 close(fd);
866         }
867         smbcli_deltree(cli->tree, dirname);
868         return ret;
869 }
870
871 bool torture_samba3_rootdirfid(struct torture_context *tctx)
872 {
873         struct smbcli_state *cli;
874         NTSTATUS status;
875         uint16_t dnum;
876         union smb_open io;
877         const char *fname = "testfile";
878         bool ret = false;
879
880         if (!torture_open_connection(&cli, tctx, 0)) {
881                 ret = false;
882                 goto done;
883         }
884
885         smbcli_unlink(cli->tree, fname);
886
887         ZERO_STRUCT(io);
888         io.generic.level = RAW_OPEN_NTCREATEX;
889         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
890         io.ntcreatex.in.root_fid = 0;
891         io.ntcreatex.in.security_flags = 0;
892         io.ntcreatex.in.access_mask =
893                 SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE;
894         io.ntcreatex.in.alloc_size = 0;
895         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
896         io.ntcreatex.in.share_access =
897                 NTCREATEX_SHARE_ACCESS_READ
898                 | NTCREATEX_SHARE_ACCESS_READ;
899         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
900         io.ntcreatex.in.create_options = 0;
901         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
902         io.ntcreatex.in.fname = "\\";
903         status = smb_raw_open(cli->tree, tctx, &io);
904         if (!NT_STATUS_IS_OK(status)) {
905                 d_printf("smb_open on the directory failed: %s\n",
906                          nt_errstr(status));
907                 ret = false;
908                 goto done;
909         }
910         dnum = io.ntcreatex.out.file.fnum;
911
912         io.ntcreatex.in.flags =
913                 NTCREATEX_FLAGS_REQUEST_OPLOCK
914                 | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
915         io.ntcreatex.in.root_fid = dnum;
916         io.ntcreatex.in.security_flags = 0;
917         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
918         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
919         io.ntcreatex.in.alloc_size = 0;
920         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
921         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
922         io.ntcreatex.in.create_options = 0;
923         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
924         io.ntcreatex.in.fname = fname;
925
926         status = smb_raw_open(cli->tree, tctx, &io);
927         if (!NT_STATUS_IS_OK(status)) {
928                 d_printf("smb_open on the file %s failed: %s\n",
929                          fname, nt_errstr(status));
930                 ret = false;
931                 goto done;
932         }
933
934         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
935         smbcli_close(cli->tree, dnum);
936         smbcli_unlink(cli->tree, fname);
937
938         ret = true;
939  done:
940         return ret;
941 }
942
943 bool torture_samba3_oplock_logoff(struct torture_context *tctx)
944 {
945         struct smbcli_state *cli;
946         NTSTATUS status;
947         uint16_t fnum1;
948         union smb_open io;
949         const char *fname = "testfile";
950         bool ret = false;
951         struct smbcli_request *req;
952         struct smb_echo echo_req;
953
954         if (!torture_open_connection(&cli, tctx, 0)) {
955                 ret = false;
956                 goto done;
957         }
958
959         smbcli_unlink(cli->tree, fname);
960
961         ZERO_STRUCT(io);
962         io.generic.level = RAW_OPEN_NTCREATEX;
963         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
964         io.ntcreatex.in.root_fid = 0;
965         io.ntcreatex.in.security_flags = 0;
966         io.ntcreatex.in.access_mask =
967                 SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE;
968         io.ntcreatex.in.alloc_size = 0;
969         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
970         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
971         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
972         io.ntcreatex.in.create_options = 0;
973         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
974         io.ntcreatex.in.fname = "testfile";
975         status = smb_raw_open(cli->tree, tctx, &io);
976         if (!NT_STATUS_IS_OK(status)) {
977                 d_printf("first smb_open failed: %s\n", nt_errstr(status));
978                 ret = false;
979                 goto done;
980         }
981         fnum1 = io.ntcreatex.out.file.fnum;
982
983         /*
984          * Create a conflicting open, causing the one-second delay
985          */
986
987         req = smb_raw_open_send(cli->tree, &io);
988         if (req == NULL) {
989                 d_printf("smb_raw_open_send failed\n");
990                 ret = false;
991                 goto done;
992         }
993
994         /*
995          * Pull the VUID from under that request. As of Nov 3, 2008 all Samba3
996          * versions (3.0, 3.2 and master) would spin sending ERRinvuid errors
997          * as long as the client is still connected.
998          */
999
1000         status = smb_raw_ulogoff(cli->session);
1001
1002         if (!NT_STATUS_IS_OK(status)) {
1003                 d_printf("ulogoff failed: %s\n", nt_errstr(status));
1004                 ret = false;
1005                 goto done;
1006         }
1007
1008         echo_req.in.repeat_count = 1;
1009         echo_req.in.size = 1;
1010         echo_req.in.data = (uint8_t *)"";
1011
1012         status = smb_raw_echo(cli->session->transport, &echo_req);
1013         if (!NT_STATUS_IS_OK(status)) {
1014                 d_printf("smb_raw_echo returned %s\n",
1015                          nt_errstr(status));
1016                 ret = false;
1017                 goto done;
1018         }
1019
1020         ret = true;
1021  done:
1022         return ret;
1023 }