a093f899ae1bfee94648804a22aa4e05e70d482d
[metze/samba/wip.git] / source4 / torture / smb2 / resilient_open.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    test suite for SMB2 resilient opens
5
6    Copyright (C) Stefan Metzmacher 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
28 #define CHECK_VAL(v, correct) do { \
29         if ((v) != (correct)) { \
30                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
31                                 __location__, #v, (int)v, (int)correct); \
32                 ret = false; \
33         }} while (0)
34
35 #define CHECK_STATUS(status, correct) do { \
36         if (!NT_STATUS_EQUAL(status, correct)) { \
37                 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
38                        nt_errstr(status), nt_errstr(correct)); \
39                 ret = false; \
40                 goto done; \
41         }} while (0)
42
43 #define CHECK_CREATED(__io, __created, __attribute)                     \
44         do {                                                            \
45                 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
46                 CHECK_VAL((__io)->out.alloc_size, 0);                   \
47                 CHECK_VAL((__io)->out.size, 0);                         \
48                 CHECK_VAL((__io)->out.file_attr, (__attribute));        \
49                 CHECK_VAL((__io)->out.reserved2, 0);                    \
50         } while(0)
51
52
53 static inline uint32_t map_lease(const char *ls)
54 {
55         uint32_t val = 0;
56         int i;
57
58         for (i = 0; i < strlen(ls); i++) {
59                 switch (ls[i]) {
60                 case 'R':
61                         val |= SMB2_LEASE_READ;
62                         break;
63                 case 'H':
64                         val |= SMB2_LEASE_HANDLE;
65                         break;
66                 case 'W':
67                         val |= SMB2_LEASE_WRITE;
68                         break;
69                 }
70         }
71
72         return val;
73 }
74
75 static inline uint32_t map_sharemode(const char *sharemode)
76 {
77         uint32_t val = NTCREATEX_SHARE_ACCESS_NONE; /* 0 */
78         int i;
79
80         for (i = 0; i < strlen(sharemode); i++) {
81                 switch(sharemode[i]) {
82                 case 'R':
83                         val |= NTCREATEX_SHARE_ACCESS_READ;
84                         break;
85                 case 'W':
86                         val |= NTCREATEX_SHARE_ACCESS_WRITE;
87                         break;
88                 case 'D':
89                         val |= NTCREATEX_SHARE_ACCESS_DELETE;
90                         break;
91                 }
92         }
93
94         return val;
95 }
96
97 /**
98  * basic durable_open test.
99  * durable state should only be granted when requested
100  * along with a batch oplock or a handle lease.
101  *
102  * This test tests durable open with all possible oplock types.
103  */
104
105 bool test_resilient_open_open1(struct torture_context *tctx,
106                                struct smb2_tree *tree)
107 {
108         TALLOC_CTX *mem_ctx = talloc_new(tctx);
109         struct smb2_create cr;
110         struct smb2_ioctl io;
111         char fname[256];
112         bool ret = true;
113         int i;
114         NTSTATUS status;
115         struct smb2_handle _h;
116         struct smb2_handle *h = NULL;
117         uint8_t resiliency[8];
118         struct smb2_lease ls;
119
120         /* Choose a random name in case the state is left a little funky. */
121         snprintf(fname, 256, "resilient_open_open1_%s.dat",
122                  generate_random_str(tctx, 8));
123
124         smb2_util_unlink(tree, fname);
125
126         ZERO_STRUCT(ls);
127         memset(&ls.lease_key, 0xef, sizeof(ls.lease_key));
128         ls.lease_state = SMB2_LEASE_READ|SMB2_LEASE_WRITE|SMB2_LEASE_HANDLE;
129
130         ZERO_STRUCT(cr);
131         cr.in.security_flags            = 0x00;
132         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
133         cr.in.create_flags              = 0x00000000;
134         cr.in.reserved                  = 0x00000000;
135         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
136         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
137         cr.in.create_disposition        = NTCREATEX_DISP_CREATE;
138         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
139                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
140                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
141                                           0x00200000 |
142                                           NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
143         cr.in.durable_open              = false;
144         cr.in.fname                     = fname;
145         cr.in.share_access              = map_sharemode("RWD");
146         cr.in.oplock_level              = SMB2_OPLOCK_LEVEL_LEASE;
147         cr.in.lease_request             = &ls;
148
149         status = smb2_create(tree, mem_ctx, &cr);
150         CHECK_STATUS(status, NT_STATUS_OK);
151         _h = cr.out.file.handle;
152         h = &_h;
153         CHECK_CREATED(&cr, CREATED, FILE_ATTRIBUTE_ARCHIVE);
154         CHECK_VAL(cr.out.durable_open, false);
155         CHECK_VAL(cr.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
156
157         SIVAL(resiliency, 0, 60*1000);
158         SIVAL(resiliency, 4, 0);
159
160         ZERO_STRUCT(io);
161         io.level = RAW_IOCTL_SMB2;
162         io.in.file.handle = *h;
163         io.in.function = FSCTL_LMR_REQ_RESILIENCY;
164         io.in.max_response_size = 0;
165         io.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
166         io.in.in = data_blob_const(resiliency, ARRAY_SIZE(resiliency));
167         io.in.out = data_blob_const(resiliency, ARRAY_SIZE(resiliency));
168
169         status = smb2_ioctl(tree, mem_ctx, &io);
170         CHECK_STATUS(status, NT_STATUS_OK);
171
172 done:
173         if (h != NULL) {
174                 smb2_util_close(tree, *h);
175         }
176         talloc_free(mem_ctx);
177
178         return ret;
179 }
180
181 struct torture_suite *torture_smb2_resilient_open_init(void)
182 {
183         struct torture_suite *suite =
184             torture_suite_create(talloc_autofree_context(), "resilient-open");
185
186         torture_suite_add_1smb2_test(suite, "open1", test_resilient_open_open1);
187
188         suite->description = talloc_strdup(suite, "SMB2-RESILIENT-OPEN tests");
189
190         return suite;
191 }