1 | /*
|
---|
2 | Unix SMB/CIFS implementation.
|
---|
3 |
|
---|
4 | test alternate data streams
|
---|
5 |
|
---|
6 | Copyright (C) Andrew Tridgell 2004
|
---|
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 |
|
---|
26 | #include "torture/torture.h"
|
---|
27 | #include "torture/smb2/proto.h"
|
---|
28 |
|
---|
29 | #include "system/filesys.h"
|
---|
30 | #include "system/locale.h"
|
---|
31 | #include "lib/util/tsort.h"
|
---|
32 |
|
---|
33 | #define DNAME "teststreams"
|
---|
34 |
|
---|
35 | #define CHECK_STATUS(status, correct) do { \
|
---|
36 | if (!NT_STATUS_EQUAL(status, correct)) { \
|
---|
37 | torture_result(tctx, TORTURE_FAIL, \
|
---|
38 | "(%s) Incorrect status %s - should be %s\n", \
|
---|
39 | __location__, nt_errstr(status), nt_errstr(correct)); \
|
---|
40 | ret = false; \
|
---|
41 | goto done; \
|
---|
42 | }} while (0)
|
---|
43 |
|
---|
44 | #define CHECK_VALUE(v, correct) do { \
|
---|
45 | if ((v) != (correct)) { \
|
---|
46 | torture_result(tctx, TORTURE_FAIL, \
|
---|
47 | "(%s) Incorrect value %s=%d - should be %d\n", \
|
---|
48 | __location__, #v, (int)v, (int)correct); \
|
---|
49 | ret = false; \
|
---|
50 | }} while (0)
|
---|
51 |
|
---|
52 | #define CHECK_NTTIME(v, correct) do { \
|
---|
53 | if ((v) != (correct)) { \
|
---|
54 | torture_result(tctx, TORTURE_FAIL, \
|
---|
55 | "(%s) Incorrect value %s=%llu - should be %llu\n", \
|
---|
56 | __location__, #v, (unsigned long long)v, \
|
---|
57 | (unsigned long long)correct); \
|
---|
58 | ret = false; \
|
---|
59 | }} while (0)
|
---|
60 |
|
---|
61 | #define CHECK_STR(v, correct) do { \
|
---|
62 | bool ok; \
|
---|
63 | if ((v) && !(correct)) { \
|
---|
64 | ok = false; \
|
---|
65 | } else if (!(v) && (correct)) { \
|
---|
66 | ok = false; \
|
---|
67 | } else if (!(v) && !(correct)) { \
|
---|
68 | ok = true; \
|
---|
69 | } else if (strcmp((v), (correct)) == 0) { \
|
---|
70 | ok = true; \
|
---|
71 | } else { \
|
---|
72 | ok = false; \
|
---|
73 | } \
|
---|
74 | if (!ok) { \
|
---|
75 | torture_comment(tctx,"(%s) Incorrect value %s='%s' - " \
|
---|
76 | "should be '%s'\n", \
|
---|
77 | __location__, #v, (v)?(v):"NULL", \
|
---|
78 | (correct)?(correct):"NULL"); \
|
---|
79 | ret = false; \
|
---|
80 | }} while (0)
|
---|
81 |
|
---|
82 |
|
---|
83 | static int qsort_string(char * const *s1, char * const *s2)
|
---|
84 | {
|
---|
85 | return strcmp(*s1, *s2);
|
---|
86 | }
|
---|
87 |
|
---|
88 | static int qsort_stream(const struct stream_struct * s1, const struct stream_struct *s2)
|
---|
89 | {
|
---|
90 | return strcmp(s1->stream_name.s, s2->stream_name.s);
|
---|
91 | }
|
---|
92 |
|
---|
93 | static bool check_stream(struct smb2_tree *tree,
|
---|
94 | const char *location,
|
---|
95 | TALLOC_CTX *mem_ctx,
|
---|
96 | const char *fname,
|
---|
97 | const char *sname,
|
---|
98 | const char *value)
|
---|
99 | {
|
---|
100 | struct smb2_handle handle;
|
---|
101 | struct smb2_create create;
|
---|
102 | struct smb2_read r;
|
---|
103 | NTSTATUS status;
|
---|
104 | const char *full_name;
|
---|
105 |
|
---|
106 | full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
|
---|
107 |
|
---|
108 | ZERO_STRUCT(create);
|
---|
109 | create.in.desired_access = SEC_RIGHTS_FILE_ALL;
|
---|
110 | create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
|
---|
111 | create.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
112 | create.in.fname = full_name;
|
---|
113 |
|
---|
114 | status = smb2_create(tree, mem_ctx, &create);
|
---|
115 | if (!NT_STATUS_IS_OK(status)) {
|
---|
116 | if (value == NULL) {
|
---|
117 | return true;
|
---|
118 | } else {
|
---|
119 | torture_comment(mem_ctx, "Unable to open stream %s\n",
|
---|
120 | full_name);
|
---|
121 | return false;
|
---|
122 | }
|
---|
123 | }
|
---|
124 |
|
---|
125 | handle = create.out.file.handle;
|
---|
126 | if (value == NULL) {
|
---|
127 | return true;
|
---|
128 | }
|
---|
129 |
|
---|
130 |
|
---|
131 | ZERO_STRUCT(r);
|
---|
132 | r.in.file.handle = handle;
|
---|
133 | r.in.length = strlen(value)+11;
|
---|
134 | r.in.offset = 0;
|
---|
135 |
|
---|
136 | status = smb2_read(tree, tree, &r);
|
---|
137 |
|
---|
138 | if (!NT_STATUS_IS_OK(status)) {
|
---|
139 | torture_comment(mem_ctx, "(%s) Failed to read %lu bytes from "
|
---|
140 | "stream '%s'\n", location, (long)strlen(value), full_name);
|
---|
141 | return false;
|
---|
142 | }
|
---|
143 |
|
---|
144 | if (memcmp(r.out.data.data, value, strlen(value)) != 0) {
|
---|
145 | torture_comment(mem_ctx, "(%s) Bad data in stream\n", location);
|
---|
146 | return false;
|
---|
147 | }
|
---|
148 |
|
---|
149 | smb2_util_close(tree, handle);
|
---|
150 | return true;
|
---|
151 | }
|
---|
152 |
|
---|
153 | static bool check_stream_list(struct smb2_tree *tree,
|
---|
154 | struct torture_context *tctx,
|
---|
155 | const char *fname,
|
---|
156 | int num_exp,
|
---|
157 | const char **exp,
|
---|
158 | struct smb2_handle h)
|
---|
159 | {
|
---|
160 | union smb_fileinfo finfo;
|
---|
161 | NTSTATUS status;
|
---|
162 | int i;
|
---|
163 | TALLOC_CTX *tmp_ctx = talloc_new(tctx);
|
---|
164 | char **exp_sort;
|
---|
165 | struct stream_struct *stream_sort;
|
---|
166 | bool ret = false;
|
---|
167 |
|
---|
168 | finfo.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
|
---|
169 | finfo.generic.in.file.handle = h;
|
---|
170 |
|
---|
171 | status = smb2_getinfo_file(tree, tctx, &finfo);
|
---|
172 | if (!NT_STATUS_IS_OK(status)) {
|
---|
173 | torture_comment(tctx, "(%s) smb_raw_pathinfo failed: %s\n",
|
---|
174 | __location__, nt_errstr(status));
|
---|
175 | goto fail;
|
---|
176 | }
|
---|
177 |
|
---|
178 | if (finfo.stream_info.out.num_streams != num_exp) {
|
---|
179 | torture_comment(tctx, "(%s) expected %d streams, got %d\n",
|
---|
180 | __location__, num_exp, finfo.stream_info.out.num_streams);
|
---|
181 | goto fail;
|
---|
182 | }
|
---|
183 |
|
---|
184 | if (num_exp == 0) {
|
---|
185 | ret = true;
|
---|
186 | goto fail;
|
---|
187 | }
|
---|
188 |
|
---|
189 | exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
|
---|
190 |
|
---|
191 | if (exp_sort == NULL) {
|
---|
192 | goto fail;
|
---|
193 | }
|
---|
194 |
|
---|
195 | TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
|
---|
196 |
|
---|
197 | stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams,
|
---|
198 | finfo.stream_info.out.num_streams *
|
---|
199 | sizeof(*stream_sort));
|
---|
200 |
|
---|
201 | if (stream_sort == NULL) {
|
---|
202 | goto fail;
|
---|
203 | }
|
---|
204 |
|
---|
205 | TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
|
---|
206 |
|
---|
207 | for (i=0; i<num_exp; i++) {
|
---|
208 | if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
|
---|
209 | torture_comment(tctx,
|
---|
210 | "(%s) expected stream name %s, got %s\n",
|
---|
211 | __location__, exp_sort[i],
|
---|
212 | stream_sort[i].stream_name.s);
|
---|
213 | goto fail;
|
---|
214 | }
|
---|
215 | }
|
---|
216 |
|
---|
217 | ret = true;
|
---|
218 | fail:
|
---|
219 | talloc_free(tmp_ctx);
|
---|
220 | return ret;
|
---|
221 | }
|
---|
222 |
|
---|
223 |
|
---|
224 | static bool test_stream_dir(struct torture_context *tctx,
|
---|
225 | struct smb2_tree *tree)
|
---|
226 | {
|
---|
227 | TALLOC_CTX *mem_ctx = talloc_new(tctx);
|
---|
228 | NTSTATUS status;
|
---|
229 | union smb_open io;
|
---|
230 | const char *fname = DNAME "\\stream.txt";
|
---|
231 | const char *sname1;
|
---|
232 | bool ret = true;
|
---|
233 | const char *basedir_data;
|
---|
234 | struct smb2_handle h;
|
---|
235 |
|
---|
236 | smb2_util_unlink(tree, fname);
|
---|
237 | smb2_deltree(tree, DNAME);
|
---|
238 |
|
---|
239 | status = torture_smb2_testdir(tree, DNAME, &h);
|
---|
240 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
241 |
|
---|
242 | basedir_data = talloc_asprintf(mem_ctx, "%s::$DATA", DNAME);
|
---|
243 | sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
|
---|
244 | torture_comment(tctx, "%s\n", sname1);
|
---|
245 |
|
---|
246 | torture_comment(tctx, "(%s) opening non-existant directory stream\n",
|
---|
247 | __location__);
|
---|
248 | ZERO_STRUCT(io.smb2);
|
---|
249 | io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
|
---|
250 | io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
|
---|
251 | io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
|
---|
252 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
253 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
254 | io.smb2.in.share_access = 0;
|
---|
255 | io.smb2.in.alloc_size = 0;
|
---|
256 | io.smb2.in.security_flags = 0;
|
---|
257 | io.smb2.in.fname = sname1;
|
---|
258 | io.smb2.in.create_flags = 0;
|
---|
259 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
260 | CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
|
---|
261 |
|
---|
262 | torture_comment(tctx, "(%s) opening basedir stream\n", __location__);
|
---|
263 | ZERO_STRUCT(io.smb2);
|
---|
264 | io.smb2.in.create_flags = 0;
|
---|
265 | io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
|
---|
266 | io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
|
---|
267 | io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
|
---|
268 | io.smb2.in.share_access = 0;
|
---|
269 | io.smb2.in.alloc_size = 0;
|
---|
270 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
271 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
272 | io.smb2.in.security_flags = 0;
|
---|
273 | io.smb2.in.fname = basedir_data;
|
---|
274 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
275 | CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
|
---|
276 |
|
---|
277 | torture_comment(tctx, "(%s) opening basedir ::$DATA stream\n",
|
---|
278 | __location__);
|
---|
279 | ZERO_STRUCT(io.smb2);
|
---|
280 | io.smb2.in.create_flags = 0x10;
|
---|
281 | io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
|
---|
282 | io.smb2.in.create_options = 0;
|
---|
283 | io.smb2.in.file_attributes = 0;
|
---|
284 | io.smb2.in.share_access = 0;
|
---|
285 | io.smb2.in.alloc_size = 0;
|
---|
286 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
287 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
288 | io.smb2.in.security_flags = 0;
|
---|
289 | io.smb2.in.fname = basedir_data;
|
---|
290 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
291 | CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
|
---|
292 |
|
---|
293 | torture_comment(tctx, "(%s) list the streams on the basedir\n",
|
---|
294 | __location__);
|
---|
295 | ret &= check_stream_list(tree, mem_ctx, DNAME, 0, NULL, h);
|
---|
296 | done:
|
---|
297 | smb2_util_unlink(tree, fname);
|
---|
298 | smb2_deltree(tree, DNAME);
|
---|
299 | talloc_free(mem_ctx);
|
---|
300 |
|
---|
301 | return ret;
|
---|
302 | }
|
---|
303 |
|
---|
304 | static bool test_stream_io(struct torture_context *tctx,
|
---|
305 | struct smb2_tree *tree)
|
---|
306 | {
|
---|
307 | TALLOC_CTX *mem_ctx = talloc_new(tctx);
|
---|
308 | NTSTATUS status;
|
---|
309 | union smb_open io;
|
---|
310 | const char *fname = DNAME "\\stream.txt";
|
---|
311 | const char *sname1, *sname2;
|
---|
312 | bool ret = true;
|
---|
313 | struct smb2_handle h, h2;
|
---|
314 |
|
---|
315 | const char *one[] = { "::$DATA" };
|
---|
316 | const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
|
---|
317 | const char *three[] = { "::$DATA", ":Stream One:$DATA",
|
---|
318 | ":Second Stream:$DATA" };
|
---|
319 |
|
---|
320 | sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
|
---|
321 | sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
|
---|
322 | "Second Stream");
|
---|
323 |
|
---|
324 | smb2_util_unlink(tree, fname);
|
---|
325 | smb2_deltree(tree, DNAME);
|
---|
326 |
|
---|
327 | status = torture_smb2_testdir(tree, DNAME, &h);
|
---|
328 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
329 |
|
---|
330 | torture_comment(tctx, "(%s) creating a stream on a non-existant file\n",
|
---|
331 | __location__);
|
---|
332 |
|
---|
333 | ZERO_STRUCT(io.smb2);
|
---|
334 | io.smb2.in.create_flags = 0;
|
---|
335 | io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
|
---|
336 | io.smb2.in.create_options = 0;
|
---|
337 | io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
|
---|
338 | io.smb2.in.share_access = 0;
|
---|
339 | io.smb2.in.alloc_size = 0;
|
---|
340 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
341 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
342 | io.smb2.in.security_flags = 0;
|
---|
343 | io.smb2.in.fname = sname1;
|
---|
344 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
345 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
346 | h2 = io.smb2.out.file.handle;
|
---|
347 |
|
---|
348 | ret &= check_stream(tree, __location__, mem_ctx, fname,
|
---|
349 | "Stream One", NULL);
|
---|
350 |
|
---|
351 | torture_comment(tctx, "(%s) check that open of base file is allowed\n", __location__);
|
---|
352 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
353 | io.smb2.in.fname = fname;
|
---|
354 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
355 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
356 | smb2_util_close(tree, io.smb2.out.file.handle);
|
---|
357 |
|
---|
358 | torture_comment(tctx, "(%s) writing to stream\n", __location__);
|
---|
359 | status = smb2_util_write(tree, h2, "test data", 0, 9);
|
---|
360 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
361 |
|
---|
362 | smb2_util_close(tree, h2);
|
---|
363 |
|
---|
364 | ret &= check_stream(tree, __location__, mem_ctx, fname,
|
---|
365 | "Stream One", "test data");
|
---|
366 |
|
---|
367 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
368 | io.smb2.in.fname = sname1;
|
---|
369 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
370 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
371 | h2 = io.smb2.out.file.handle;
|
---|
372 |
|
---|
373 | torture_comment(tctx, "(%s) modifying stream\n", __location__);
|
---|
374 | status = smb2_util_write(tree, h2, "MORE DATA ", 5, 10);
|
---|
375 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
376 |
|
---|
377 | smb2_util_close(tree, h2);
|
---|
378 |
|
---|
379 | ret &= check_stream(tree, __location__, mem_ctx, fname,
|
---|
380 | "Stream One:$FOO", NULL);
|
---|
381 |
|
---|
382 | torture_comment(tctx, "(%s) creating a stream2 on a existing file\n",
|
---|
383 | __location__);
|
---|
384 | io.smb2.in.fname = sname2;
|
---|
385 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
|
---|
386 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
387 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
388 | h2 = io.smb2.out.file.handle;
|
---|
389 |
|
---|
390 | torture_comment(tctx, "(%s) modifying stream\n", __location__);
|
---|
391 | status= smb2_util_write(tree, h2, "SECOND STREAM", 0, 13);
|
---|
392 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
393 | smb2_util_close(tree, h2);
|
---|
394 |
|
---|
395 | ret &= check_stream(tree, __location__, mem_ctx, fname,
|
---|
396 | "Stream One", "test MORE DATA ");
|
---|
397 |
|
---|
398 | ret &= check_stream(tree, __location__, mem_ctx, fname,
|
---|
399 | "Stream One:$DATA", "test MORE DATA ");
|
---|
400 |
|
---|
401 | ret &= check_stream(tree, __location__, mem_ctx, fname,
|
---|
402 | "Stream One:", NULL);
|
---|
403 |
|
---|
404 | ret &= check_stream(tree, __location__, mem_ctx, fname,
|
---|
405 | "Second Stream", "SECOND STREAM");
|
---|
406 |
|
---|
407 | ret &= check_stream(tree, __location__, mem_ctx, fname,
|
---|
408 | "SECOND STREAM:$DATA", "SECOND STREAM");
|
---|
409 | ret &= check_stream(tree, __location__, mem_ctx, fname,
|
---|
410 | "Second Stream:$DATA", "SECOND STREAM");
|
---|
411 |
|
---|
412 | ret &= check_stream(tree, __location__, mem_ctx, fname,
|
---|
413 | "Second Stream:", NULL);
|
---|
414 |
|
---|
415 | ret &= check_stream(tree, __location__, mem_ctx, fname,
|
---|
416 | "Second Stream:$FOO", NULL);
|
---|
417 |
|
---|
418 | io.smb2.in.fname = sname2;
|
---|
419 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
|
---|
420 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
421 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
422 | h2 = io.smb2.out.file.handle;
|
---|
423 | check_stream_list(tree, tctx, fname, 3, three, h2);
|
---|
424 |
|
---|
425 | smb2_util_close(tree, h2);
|
---|
426 |
|
---|
427 | torture_comment(tctx, "(%s) deleting stream\n", __location__);
|
---|
428 | status = smb2_util_unlink(tree, sname1);
|
---|
429 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
430 |
|
---|
431 | io.smb2.in.fname = sname2;
|
---|
432 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
|
---|
433 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
434 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
435 | h2 = io.smb2.out.file.handle;
|
---|
436 | check_stream_list(tree, tctx, fname, 2, two, h2);
|
---|
437 | smb2_util_close(tree, h2);
|
---|
438 |
|
---|
439 | torture_comment(tctx, "(%s) delete a stream via delete-on-close\n",
|
---|
440 | __location__);
|
---|
441 | io.smb2.in.fname = sname2;
|
---|
442 | io.smb2.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
|
---|
443 | io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
|
---|
444 | io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
|
---|
445 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
446 |
|
---|
447 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
448 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
449 | h2 = io.smb2.out.file.handle;
|
---|
450 |
|
---|
451 | smb2_util_close(tree, h2);
|
---|
452 | status = smb2_util_unlink(tree, sname2);
|
---|
453 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
---|
454 |
|
---|
455 | io.smb2.in.fname = fname;
|
---|
456 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
457 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
458 | h2 = io.smb2.out.file.handle;
|
---|
459 | check_stream_list(tree,tctx, fname, 1, one, h2);
|
---|
460 | smb2_util_close(tree, h2);
|
---|
461 |
|
---|
462 | if (!torture_setting_bool(tctx, "samba4", false)) {
|
---|
463 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
464 | io.smb2.in.fname = sname1;
|
---|
465 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
466 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
467 | smb2_util_close(tree, io.ntcreatex.out.file.handle);
|
---|
468 | io.smb2.in.fname = sname2;
|
---|
469 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
470 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
471 | smb2_util_close(tree, io.ntcreatex.out.file.handle);
|
---|
472 | torture_comment(tctx, "(%s) deleting file\n", __location__);
|
---|
473 | status = smb2_util_unlink(tree, fname);
|
---|
474 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
475 | }
|
---|
476 |
|
---|
477 |
|
---|
478 | done:
|
---|
479 | smb2_util_close(tree, h2);
|
---|
480 | smb2_deltree(tree, DNAME);
|
---|
481 | talloc_free(mem_ctx);
|
---|
482 |
|
---|
483 | return ret;
|
---|
484 | }
|
---|
485 |
|
---|
486 | /*
|
---|
487 | test stream sharemodes
|
---|
488 | */
|
---|
489 | static bool test_stream_sharemodes(struct torture_context *tctx,
|
---|
490 | struct smb2_tree *tree)
|
---|
491 | {
|
---|
492 | TALLOC_CTX *mem_ctx = talloc_new(tctx);
|
---|
493 | NTSTATUS status;
|
---|
494 | union smb_open io;
|
---|
495 | const char *fname = DNAME "\\stream_share.txt";
|
---|
496 | const char *sname1, *sname2;
|
---|
497 | bool ret = true;
|
---|
498 | struct smb2_handle h, h1, h2;
|
---|
499 |
|
---|
500 | sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
|
---|
501 | sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
|
---|
502 | "Second Stream");
|
---|
503 |
|
---|
504 | smb2_util_unlink(tree, fname);
|
---|
505 | smb2_deltree(tree, DNAME);
|
---|
506 |
|
---|
507 | status = torture_smb2_testdir(tree, DNAME, &h);
|
---|
508 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
509 |
|
---|
510 | torture_comment(tctx, "(%s) Testing stream share mode conflicts\n",
|
---|
511 | __location__);
|
---|
512 | ZERO_STRUCT(io.smb2);
|
---|
513 | io.generic.level = RAW_OPEN_SMB2;
|
---|
514 | io.smb2.in.create_flags = 0;
|
---|
515 | io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
|
---|
516 | io.smb2.in.create_options = 0;
|
---|
517 | io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
|
---|
518 | io.smb2.in.share_access = 0;
|
---|
519 | io.smb2.in.alloc_size = 0;
|
---|
520 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
521 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
522 | io.smb2.in.security_flags = 0;
|
---|
523 | io.smb2.in.fname = sname1;
|
---|
524 |
|
---|
525 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
526 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
527 | h1 = io.smb2.out.file.handle;
|
---|
528 |
|
---|
529 | /*
|
---|
530 | * A different stream does not give a sharing violation
|
---|
531 | */
|
---|
532 |
|
---|
533 | io.smb2.in.fname = sname2;
|
---|
534 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
535 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
536 | h2 = io.smb2.out.file.handle;
|
---|
537 |
|
---|
538 | /*
|
---|
539 | * ... whereas the same stream does with unchanged access/share_access
|
---|
540 | * flags
|
---|
541 | */
|
---|
542 |
|
---|
543 | io.smb2.in.fname = sname1;
|
---|
544 | io.smb2.in.create_disposition = 0;
|
---|
545 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
546 | CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
---|
547 |
|
---|
548 | io.smb2.in.fname = sname2;
|
---|
549 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
550 | CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
---|
551 |
|
---|
552 | done:
|
---|
553 | smb2_util_close(tree, h1);
|
---|
554 | smb2_util_close(tree, h2);
|
---|
555 | status = smb2_util_unlink(tree, fname);
|
---|
556 | smb2_deltree(tree, DNAME);
|
---|
557 | talloc_free(mem_ctx);
|
---|
558 |
|
---|
559 | return ret;
|
---|
560 | }
|
---|
561 |
|
---|
562 | /*
|
---|
563 | * Test FILE_SHARE_DELETE on streams
|
---|
564 | *
|
---|
565 | * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
|
---|
566 | * with SEC_STD_DELETE.
|
---|
567 | *
|
---|
568 | * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
|
---|
569 | * be opened with SEC_STD_DELETE.
|
---|
570 | *
|
---|
571 | * A stream held open with FILE_SHARE_DELETE allows the file to be
|
---|
572 | * deleted. After the main file is deleted, access to the open file descriptor
|
---|
573 | * still works, but all name-based access to both the main file as well as the
|
---|
574 | * stream is denied with DELETE pending.
|
---|
575 | *
|
---|
576 | * This means, an open of the main file with SEC_STD_DELETE should walk all
|
---|
577 | * streams and also open them with SEC_STD_DELETE. If any of these opens gives
|
---|
578 | * SHARING_VIOLATION, the main open fails.
|
---|
579 | *
|
---|
580 | * Closing the main file after delete_on_close has been set does not really
|
---|
581 | * unlink it but leaves the corresponding share mode entry with
|
---|
582 | * delete_on_close being set around until all streams are closed.
|
---|
583 | *
|
---|
584 | * Opening a stream must also look at the main file's share mode entry, look
|
---|
585 | * at the delete_on_close bit and potentially return DELETE_PENDING.
|
---|
586 | */
|
---|
587 |
|
---|
588 | static bool test_stream_delete(struct torture_context *tctx,
|
---|
589 | struct smb2_tree *tree)
|
---|
590 | {
|
---|
591 | TALLOC_CTX *mem_ctx = talloc_new(tctx);
|
---|
592 | NTSTATUS status;
|
---|
593 | union smb_open io;
|
---|
594 | const char *fname = DNAME "\\stream_delete.txt";
|
---|
595 | const char *sname1;
|
---|
596 | bool ret = true;
|
---|
597 | struct smb2_handle h, h1;
|
---|
598 | struct smb2_read r;
|
---|
599 |
|
---|
600 | if (torture_setting_bool(tctx, "samba4", false)) {
|
---|
601 | torture_comment(tctx, "Skipping test as samba4 is enabled\n");
|
---|
602 | goto done;
|
---|
603 | }
|
---|
604 |
|
---|
605 | sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
|
---|
606 |
|
---|
607 | /* clean slate .. */
|
---|
608 | smb2_util_unlink(tree, fname);
|
---|
609 | smb2_deltree(tree, fname);
|
---|
610 | smb2_deltree(tree, DNAME);
|
---|
611 |
|
---|
612 | status = torture_smb2_testdir(tree, DNAME, &h);
|
---|
613 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
614 |
|
---|
615 | torture_comment(tctx, "(%s) opening non-existant file stream\n",
|
---|
616 | __location__);
|
---|
617 | ZERO_STRUCT(io.smb2);
|
---|
618 | io.smb2.in.create_flags = 0;
|
---|
619 | io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
|
---|
620 | io.smb2.in.create_options = 0;
|
---|
621 | io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
|
---|
622 | io.smb2.in.share_access = 0;
|
---|
623 | io.smb2.in.alloc_size = 0;
|
---|
624 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
625 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
626 | io.smb2.in.security_flags = 0;
|
---|
627 | io.smb2.in.fname = sname1;
|
---|
628 |
|
---|
629 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
630 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
631 | h1 = io.smb2.out.file.handle;
|
---|
632 |
|
---|
633 | status = smb2_util_write(tree, h1, "test data", 0, 9);
|
---|
634 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
635 |
|
---|
636 | /*
|
---|
637 | * One stream opened without FILE_SHARE_DELETE prevents the main file
|
---|
638 | * to be deleted or even opened with DELETE access
|
---|
639 | */
|
---|
640 |
|
---|
641 | status = smb2_util_unlink(tree, fname);
|
---|
642 | CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
---|
643 |
|
---|
644 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
645 | io.smb2.in.fname = fname;
|
---|
646 | io.smb2.in.desired_access = SEC_STD_DELETE;
|
---|
647 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
648 | CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
---|
649 |
|
---|
650 | smb2_util_close(tree, h1);
|
---|
651 |
|
---|
652 | /*
|
---|
653 | * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
|
---|
654 | */
|
---|
655 |
|
---|
656 | io.smb2.in.fname = sname1;
|
---|
657 | io.smb2.in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
|
---|
658 | io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
|
---|
659 | NTCREATEX_SHARE_ACCESS_READ |
|
---|
660 | NTCREATEX_SHARE_ACCESS_WRITE;
|
---|
661 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
662 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
663 | h1 = io.smb2.out.file.handle;
|
---|
664 |
|
---|
665 | status = smb2_util_unlink(tree, fname);
|
---|
666 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
667 |
|
---|
668 | /*
|
---|
669 | * file access still works on the stream while the main file is closed
|
---|
670 | */
|
---|
671 | ZERO_STRUCT(r);
|
---|
672 | r.in.file.handle = h1;
|
---|
673 | r.in.length = 9;
|
---|
674 | r.in.offset = 0;
|
---|
675 |
|
---|
676 | status = smb2_read(tree, tree, &r);
|
---|
677 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
678 |
|
---|
679 | /*
|
---|
680 | * name-based access to both the main file and the stream does not
|
---|
681 | * work anymore but gives DELETE_PENDING
|
---|
682 | */
|
---|
683 |
|
---|
684 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
|
---|
685 | io.smb2.in.fname = fname;
|
---|
686 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
687 | CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
|
---|
688 |
|
---|
689 | /*
|
---|
690 | * older S3 doesn't do this
|
---|
691 | */
|
---|
692 |
|
---|
693 | io.smb2.in.fname = sname1;
|
---|
694 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
695 | CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
|
---|
696 |
|
---|
697 | smb2_util_close(tree, h1);
|
---|
698 |
|
---|
699 | /*
|
---|
700 | * After closing the stream the file is really gone.
|
---|
701 | */
|
---|
702 |
|
---|
703 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
704 | io.smb2.in.fname = fname;
|
---|
705 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
706 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
---|
707 |
|
---|
708 | done:
|
---|
709 | smb2_util_close(tree, h1);
|
---|
710 | smb2_util_unlink(tree, fname);
|
---|
711 | smb2_deltree(tree, DNAME);
|
---|
712 | talloc_free(mem_ctx);
|
---|
713 |
|
---|
714 | return ret;
|
---|
715 | }
|
---|
716 |
|
---|
717 | /*
|
---|
718 | test stream names
|
---|
719 | */
|
---|
720 | static bool test_stream_names(struct torture_context *tctx,
|
---|
721 | struct smb2_tree *tree)
|
---|
722 | {
|
---|
723 | TALLOC_CTX *mem_ctx = talloc_new(tctx);
|
---|
724 | NTSTATUS status;
|
---|
725 | union smb_open io;
|
---|
726 | union smb_fileinfo finfo;
|
---|
727 | union smb_fileinfo stinfo;
|
---|
728 | union smb_setfileinfo sinfo;
|
---|
729 | const char *fname = DNAME "\\stream_names.txt";
|
---|
730 | const char *sname1, *sname1b, *sname1c, *sname1d;
|
---|
731 | const char *sname2, *snamew, *snamew2;
|
---|
732 | const char *snamer1, *snamer2;
|
---|
733 | bool ret = true;
|
---|
734 | struct smb2_handle h, h1, h2, h3;
|
---|
735 | int i;
|
---|
736 | const char *four[4] = {
|
---|
737 | "::$DATA",
|
---|
738 | ":\x05Stream\n One:$DATA",
|
---|
739 | ":MStream Two:$DATA",
|
---|
740 | ":?Stream*:$DATA"
|
---|
741 | };
|
---|
742 | const char *five1[5] = {
|
---|
743 | "::$DATA",
|
---|
744 | ":\x05Stream\n One:$DATA",
|
---|
745 | ":BeforeRename:$DATA",
|
---|
746 | ":MStream Two:$DATA",
|
---|
747 | ":?Stream*:$DATA"
|
---|
748 | };
|
---|
749 | const char *five2[5] = {
|
---|
750 | "::$DATA",
|
---|
751 | ":\x05Stream\n One:$DATA",
|
---|
752 | ":AfterRename:$DATA",
|
---|
753 | ":MStream Two:$DATA",
|
---|
754 | ":?Stream*:$DATA"
|
---|
755 | };
|
---|
756 |
|
---|
757 | sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "\x05Stream\n One");
|
---|
758 | sname1b = talloc_asprintf(mem_ctx, "%s:", sname1);
|
---|
759 | sname1c = talloc_asprintf(mem_ctx, "%s:$FOO", sname1);
|
---|
760 | sname1d = talloc_asprintf(mem_ctx, "%s:?D*a", sname1);
|
---|
761 | sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "MStream Two");
|
---|
762 | snamew = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "?Stream*");
|
---|
763 | snamew2 = talloc_asprintf(mem_ctx, "%s\\stream*:%s:$DATA", DNAME,
|
---|
764 | "?Stream*");
|
---|
765 | snamer1 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname,
|
---|
766 | "BeforeRename");
|
---|
767 | snamer2 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "AfterRename");
|
---|
768 |
|
---|
769 | /* clean slate ...*/
|
---|
770 | smb2_util_unlink(tree, fname);
|
---|
771 | smb2_deltree(tree, fname);
|
---|
772 | smb2_deltree(tree, DNAME);
|
---|
773 |
|
---|
774 | status = torture_smb2_testdir(tree, DNAME, &h);
|
---|
775 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
776 |
|
---|
777 | torture_comment(tctx, "(%s) testing stream names\n", __location__);
|
---|
778 | ZERO_STRUCT(io.smb2);
|
---|
779 | io.smb2.in.create_flags = 0;
|
---|
780 | io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
|
---|
781 | io.smb2.in.create_options = 0;
|
---|
782 | io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
|
---|
783 | io.smb2.in.share_access = 0;
|
---|
784 | io.smb2.in.alloc_size = 0;
|
---|
785 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
786 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
787 | io.smb2.in.security_flags = 0;
|
---|
788 | io.smb2.in.fname = sname1;
|
---|
789 |
|
---|
790 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
791 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
792 | h1 = io.smb2.out.file.handle;
|
---|
793 |
|
---|
794 | /*
|
---|
795 | * A different stream does not give a sharing violation
|
---|
796 | */
|
---|
797 |
|
---|
798 | io.smb2.in.fname = sname2;
|
---|
799 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
|
---|
800 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
801 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
802 | h2 = io.smb2.out.file.handle;
|
---|
803 |
|
---|
804 | /*
|
---|
805 | * ... whereas the same stream does with unchanged access/share_access
|
---|
806 | * flags
|
---|
807 | */
|
---|
808 |
|
---|
809 | io.smb2.in.fname = sname1;
|
---|
810 | io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
|
---|
811 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
812 | CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
---|
813 |
|
---|
814 | io.smb2.in.fname = sname1b;
|
---|
815 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
816 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
---|
817 |
|
---|
818 | io.smb2.in.fname = sname1c;
|
---|
819 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
820 | if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
|
---|
821 | /* w2k returns INVALID_PARAMETER */
|
---|
822 | CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
|
---|
823 | } else {
|
---|
824 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
---|
825 | }
|
---|
826 |
|
---|
827 | io.smb2.in.fname = sname1d;
|
---|
828 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
829 | if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
|
---|
830 | /* w2k returns INVALID_PARAMETER */
|
---|
831 | CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
|
---|
832 | } else {
|
---|
833 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
---|
834 | }
|
---|
835 |
|
---|
836 | io.smb2.in.fname = sname2;
|
---|
837 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
838 | CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
---|
839 |
|
---|
840 | io.smb2.in.fname = snamew;
|
---|
841 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
842 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
843 | h3 = io.smb2.out.file.handle;
|
---|
844 |
|
---|
845 | io.smb2.in.fname = snamew2;
|
---|
846 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
847 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
---|
848 |
|
---|
849 | io.smb2.in.fname = fname;
|
---|
850 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
851 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
852 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
853 | ret &= check_stream_list(tree, tctx, fname, 4, four,
|
---|
854 | io.smb2.out.file.handle);
|
---|
855 |
|
---|
856 | smb2_util_close(tree, h1);
|
---|
857 | smb2_util_close(tree, h2);
|
---|
858 | smb2_util_close(tree, h3);
|
---|
859 |
|
---|
860 | if (torture_setting_bool(tctx, "samba4", true)) {
|
---|
861 | goto done;
|
---|
862 | }
|
---|
863 |
|
---|
864 | finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
|
---|
865 | finfo.generic.in.file.handle = io.smb2.out.file.handle;
|
---|
866 | status = smb2_getinfo_file(tree, mem_ctx, &finfo);
|
---|
867 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
868 | ret &= check_stream_list(tree, tctx, fname, 4, four,
|
---|
869 | io.smb2.out.file.handle);
|
---|
870 |
|
---|
871 | for (i=0; i < 4; i++) {
|
---|
872 | NTTIME write_time;
|
---|
873 | uint64_t stream_size;
|
---|
874 | char *path = talloc_asprintf(tctx, "%s%s",
|
---|
875 | fname, four[i]);
|
---|
876 |
|
---|
877 | char *rpath = talloc_strdup(path, path);
|
---|
878 | char *p = strrchr(rpath, ':');
|
---|
879 | /* eat :$DATA */
|
---|
880 | *p = 0;
|
---|
881 | p--;
|
---|
882 | if (*p == ':') {
|
---|
883 | /* eat ::$DATA */
|
---|
884 | *p = 0;
|
---|
885 | }
|
---|
886 | torture_comment(tctx, "(%s): i[%u][%s]\n",
|
---|
887 | __location__, i,path);
|
---|
888 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
889 | io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
|
---|
890 | SEC_FILE_WRITE_ATTRIBUTE |
|
---|
891 | SEC_RIGHTS_FILE_ALL;
|
---|
892 | io.smb2.in.fname = path;
|
---|
893 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
894 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
895 | h1 = io.smb2.out.file.handle;
|
---|
896 |
|
---|
897 | finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
|
---|
898 | finfo.generic.in.file.path = fname;
|
---|
899 | status = smb2_getinfo_file(tree, mem_ctx, &finfo);
|
---|
900 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
901 |
|
---|
902 | stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
|
---|
903 | stinfo.generic.in.file.handle = h1;
|
---|
904 | status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
|
---|
905 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
906 | if (!torture_setting_bool(tctx, "samba3", false)) {
|
---|
907 | CHECK_NTTIME(stinfo.all_info.out.create_time,
|
---|
908 | finfo.all_info.out.create_time);
|
---|
909 | CHECK_NTTIME(stinfo.all_info.out.access_time,
|
---|
910 | finfo.all_info.out.access_time);
|
---|
911 | CHECK_NTTIME(stinfo.all_info.out.write_time,
|
---|
912 | finfo.all_info.out.write_time);
|
---|
913 | CHECK_NTTIME(stinfo.all_info.out.change_time,
|
---|
914 | finfo.all_info.out.change_time);
|
---|
915 | }
|
---|
916 | CHECK_VALUE(stinfo.all_info.out.attrib,
|
---|
917 | finfo.all_info.out.attrib);
|
---|
918 | CHECK_VALUE(stinfo.all_info.out.size,
|
---|
919 | finfo.all_info.out.size);
|
---|
920 | CHECK_VALUE(stinfo.all_info.out.delete_pending,
|
---|
921 | finfo.all_info.out.delete_pending);
|
---|
922 | CHECK_VALUE(stinfo.all_info.out.directory,
|
---|
923 | finfo.all_info.out.directory);
|
---|
924 | CHECK_VALUE(stinfo.all_info.out.ea_size,
|
---|
925 | finfo.all_info.out.ea_size);
|
---|
926 |
|
---|
927 | stinfo.generic.level = RAW_FILEINFO_NAME_INFORMATION;
|
---|
928 | stinfo.generic.in.file.handle = h1;
|
---|
929 | status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
|
---|
930 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
931 | if (!torture_setting_bool(tctx, "samba3", false)) {
|
---|
932 | CHECK_STR(rpath, stinfo.name_info.out.fname.s);
|
---|
933 | }
|
---|
934 |
|
---|
935 | write_time = finfo.all_info.out.write_time;
|
---|
936 | write_time += i*1000000;
|
---|
937 | write_time /= 1000000;
|
---|
938 | write_time *= 1000000;
|
---|
939 |
|
---|
940 | ZERO_STRUCT(sinfo);
|
---|
941 | sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
|
---|
942 | sinfo.basic_info.in.file.handle = h1;
|
---|
943 | sinfo.basic_info.in.write_time = write_time;
|
---|
944 | sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
|
---|
945 | status = smb2_setinfo_file(tree, &sinfo);
|
---|
946 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
947 |
|
---|
948 | stream_size = i*8192;
|
---|
949 |
|
---|
950 | ZERO_STRUCT(sinfo);
|
---|
951 | sinfo.end_of_file_info.level =
|
---|
952 | RAW_SFILEINFO_END_OF_FILE_INFORMATION;
|
---|
953 | sinfo.end_of_file_info.in.file.handle = h1;
|
---|
954 | sinfo.end_of_file_info.in.size = stream_size;
|
---|
955 | status = smb2_setinfo_file(tree, &sinfo);
|
---|
956 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
957 |
|
---|
958 | stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
|
---|
959 | stinfo.generic.in.file.handle = h1;
|
---|
960 | status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
|
---|
961 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
962 | if (!torture_setting_bool(tctx, "samba3", false)) {
|
---|
963 | CHECK_NTTIME(stinfo.all_info.out.write_time,
|
---|
964 | write_time);
|
---|
965 | CHECK_VALUE(stinfo.all_info.out.attrib,
|
---|
966 | finfo.all_info.out.attrib);
|
---|
967 | }
|
---|
968 | CHECK_VALUE(stinfo.all_info.out.size,
|
---|
969 | stream_size);
|
---|
970 | CHECK_VALUE(stinfo.all_info.out.delete_pending,
|
---|
971 | finfo.all_info.out.delete_pending);
|
---|
972 | CHECK_VALUE(stinfo.all_info.out.directory,
|
---|
973 | finfo.all_info.out.directory);
|
---|
974 | CHECK_VALUE(stinfo.all_info.out.ea_size,
|
---|
975 | finfo.all_info.out.ea_size);
|
---|
976 |
|
---|
977 | io.smb2.in.fname = fname;
|
---|
978 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
979 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
980 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
981 | ret &= check_stream_list(tree, tctx, fname, 4, four,
|
---|
982 | io.smb2.out.file.handle);
|
---|
983 |
|
---|
984 | smb2_util_close(tree, h1);
|
---|
985 | talloc_free(path);
|
---|
986 | }
|
---|
987 |
|
---|
988 | torture_comment(tctx, "(%s): testing stream renames\n", __location__);
|
---|
989 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
990 | io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
|
---|
991 | SEC_FILE_WRITE_ATTRIBUTE |
|
---|
992 | SEC_RIGHTS_FILE_ALL;
|
---|
993 | io.smb2.in.fname = snamer1;
|
---|
994 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
995 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
996 | h1 = io.smb2.out.file.handle;
|
---|
997 | ret &= check_stream_list(tree,tctx, fname, 5, five1,
|
---|
998 | io.smb2.out.file.handle);
|
---|
999 |
|
---|
1000 | ZERO_STRUCT(sinfo);
|
---|
1001 | sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
|
---|
1002 | sinfo.rename_information.in.file.handle = h1;
|
---|
1003 | sinfo.rename_information.in.overwrite = true;
|
---|
1004 | sinfo.rename_information.in.root_fid = 0;
|
---|
1005 | sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
|
---|
1006 | status = smb2_setinfo_file(tree, &sinfo);
|
---|
1007 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1008 |
|
---|
1009 | ret &= check_stream_list(tree,tctx, fname, 5, five2,
|
---|
1010 | io.smb2.out.file.handle);
|
---|
1011 |
|
---|
1012 | ZERO_STRUCT(sinfo);
|
---|
1013 | sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
|
---|
1014 | sinfo.rename_information.in.file.handle = h1;
|
---|
1015 | sinfo.rename_information.in.overwrite = false;
|
---|
1016 | sinfo.rename_information.in.root_fid = 0;
|
---|
1017 | sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
|
---|
1018 | status = smb2_setinfo_file(tree, &sinfo);
|
---|
1019 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
|
---|
1020 |
|
---|
1021 | ret &= check_stream_list(tree,tctx, fname, 5, five2,
|
---|
1022 | io.smb2.out.file.handle);
|
---|
1023 |
|
---|
1024 | ZERO_STRUCT(sinfo);
|
---|
1025 | sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
|
---|
1026 | sinfo.rename_information.in.file.handle = h1;
|
---|
1027 | sinfo.rename_information.in.overwrite = true;
|
---|
1028 | sinfo.rename_information.in.root_fid = 0;
|
---|
1029 | sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
|
---|
1030 | status = smb2_setinfo_file(tree, &sinfo);
|
---|
1031 | CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
|
---|
1032 |
|
---|
1033 | ret &= check_stream_list(tree,tctx, fname, 5, five2,
|
---|
1034 | io.smb2.out.file.handle);
|
---|
1035 |
|
---|
1036 | /* TODO: we need to test more rename combinations */
|
---|
1037 |
|
---|
1038 | done:
|
---|
1039 | smb2_util_close(tree, h1);
|
---|
1040 | status = smb2_util_unlink(tree, fname);
|
---|
1041 | smb2_deltree(tree, DNAME);
|
---|
1042 | talloc_free(mem_ctx);
|
---|
1043 |
|
---|
1044 | return ret;
|
---|
1045 | }
|
---|
1046 |
|
---|
1047 | /*
|
---|
1048 | test stream names
|
---|
1049 | */
|
---|
1050 | static bool test_stream_names2(struct torture_context *tctx,
|
---|
1051 | struct smb2_tree *tree)
|
---|
1052 | {
|
---|
1053 | TALLOC_CTX *mem_ctx = talloc_new(tctx);
|
---|
1054 | NTSTATUS status;
|
---|
1055 | union smb_open io;
|
---|
1056 | const char *fname = DNAME "\\stream_names2.txt";
|
---|
1057 | bool ret = true;
|
---|
1058 | struct smb2_handle h, h1;
|
---|
1059 | uint8_t i;
|
---|
1060 |
|
---|
1061 | smb2_util_unlink(tree, fname);
|
---|
1062 | smb2_deltree(tree, DNAME);
|
---|
1063 |
|
---|
1064 | status = torture_smb2_testdir(tree, DNAME, &h);
|
---|
1065 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1066 |
|
---|
1067 | torture_comment(tctx, "(%s) testing stream names\n", __location__);
|
---|
1068 | ZERO_STRUCT(io.smb2);
|
---|
1069 | io.smb2.in.create_flags = 0;
|
---|
1070 | io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
|
---|
1071 | io.smb2.in.create_options = 0;
|
---|
1072 | io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
|
---|
1073 | io.smb2.in.share_access = 0;
|
---|
1074 | io.smb2.in.alloc_size = 0;
|
---|
1075 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
1076 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
1077 | io.smb2.in.security_flags = 0;
|
---|
1078 | io.smb2.in.fname = fname;
|
---|
1079 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1080 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1081 | h1 = io.smb2.out.file.handle;
|
---|
1082 |
|
---|
1083 | for (i=0x01; i < 0x7F; i++) {
|
---|
1084 | char *path = talloc_asprintf(mem_ctx, "%s:Stream%c0x%02X:$DATA",
|
---|
1085 | fname, i, i);
|
---|
1086 | NTSTATUS expected;
|
---|
1087 |
|
---|
1088 | switch (i) {
|
---|
1089 | case '/':/*0x2F*/
|
---|
1090 | case ':':/*0x3A*/
|
---|
1091 | case '\\':/*0x5C*/
|
---|
1092 | expected = NT_STATUS_OBJECT_NAME_INVALID;
|
---|
1093 | break;
|
---|
1094 | default:
|
---|
1095 | expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
|
---|
1096 | break;
|
---|
1097 | }
|
---|
1098 |
|
---|
1099 |
|
---|
1100 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
1101 | io.smb2.in.fname = path;
|
---|
1102 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1103 | if (!NT_STATUS_EQUAL(status, expected)) {
|
---|
1104 | torture_comment(tctx,
|
---|
1105 | "(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
|
---|
1106 | __location__, fname, isprint(i)?(char)i:' ', i,
|
---|
1107 | isprint(i)?"":" (not printable)",
|
---|
1108 | nt_errstr(expected));
|
---|
1109 | }
|
---|
1110 | CHECK_STATUS(status, expected);
|
---|
1111 |
|
---|
1112 | talloc_free(path);
|
---|
1113 | }
|
---|
1114 |
|
---|
1115 | done:
|
---|
1116 | smb2_util_close(tree, h1);
|
---|
1117 | status = smb2_util_unlink(tree, fname);
|
---|
1118 | smb2_deltree(tree, DNAME);
|
---|
1119 | talloc_free(mem_ctx);
|
---|
1120 |
|
---|
1121 | return ret;
|
---|
1122 | }
|
---|
1123 |
|
---|
1124 | #define CHECK_CALL_HANDLE(call, rightstatus) do { \
|
---|
1125 | check_handle = true; \
|
---|
1126 | call_name = #call; \
|
---|
1127 | sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
|
---|
1128 | sfinfo.generic.in.file.handle = h1; \
|
---|
1129 | status = smb2_setinfo_file(tree, &sfinfo); \
|
---|
1130 | if (!NT_STATUS_EQUAL(status, rightstatus)) { \
|
---|
1131 | torture_comment(tctx,"(%s) %s - %s (should be %s)\n", \
|
---|
1132 | __location__, #call, \
|
---|
1133 | nt_errstr(status), nt_errstr(rightstatus)); \
|
---|
1134 | ret = false; \
|
---|
1135 | } \
|
---|
1136 | finfo1.generic.level = RAW_FILEINFO_ALL_INFORMATION; \
|
---|
1137 | finfo1.generic.in.file.handle = h1; \
|
---|
1138 | status2 = smb2_getinfo_file(tree, tctx, &finfo1); \
|
---|
1139 | if (!NT_STATUS_IS_OK(status2)) { \
|
---|
1140 | torture_comment(tctx,"(%s) %s pathinfo - %s\n", \
|
---|
1141 | __location__, #call, nt_errstr(status)); \
|
---|
1142 | ret = false; \
|
---|
1143 | }} while (0)
|
---|
1144 |
|
---|
1145 | /*
|
---|
1146 | test stream renames
|
---|
1147 | */
|
---|
1148 | static bool test_stream_rename(struct torture_context *tctx,
|
---|
1149 | struct smb2_tree *tree)
|
---|
1150 | {
|
---|
1151 | TALLOC_CTX *mem_ctx = talloc_new(tctx);
|
---|
1152 | NTSTATUS status, status2;
|
---|
1153 | union smb_open io;
|
---|
1154 | const char *fname = DNAME "\\stream_rename.txt";
|
---|
1155 | const char *sname1, *sname2;
|
---|
1156 | union smb_fileinfo finfo1;
|
---|
1157 | union smb_setfileinfo sfinfo;
|
---|
1158 | bool ret = true;
|
---|
1159 | struct smb2_handle h, h1;
|
---|
1160 | bool check_handle;
|
---|
1161 | const char *call_name;
|
---|
1162 |
|
---|
1163 | sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
|
---|
1164 | sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
|
---|
1165 | "Second Stream");
|
---|
1166 |
|
---|
1167 | smb2_util_unlink(tree, fname);
|
---|
1168 | smb2_deltree(tree, DNAME);
|
---|
1169 |
|
---|
1170 | status = torture_smb2_testdir(tree, DNAME, &h);
|
---|
1171 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1172 |
|
---|
1173 | torture_comment(tctx, "(%s) testing stream renames\n", __location__);
|
---|
1174 | ZERO_STRUCT(io.smb2);
|
---|
1175 | io.smb2.in.create_flags = 0;
|
---|
1176 | io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
|
---|
1177 | SEC_FILE_WRITE_ATTRIBUTE |
|
---|
1178 | SEC_RIGHTS_FILE_ALL;
|
---|
1179 | io.smb2.in.create_options = 0;
|
---|
1180 | io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
|
---|
1181 | io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
|
---|
1182 | NTCREATEX_SHARE_ACCESS_WRITE |
|
---|
1183 | NTCREATEX_SHARE_ACCESS_DELETE;
|
---|
1184 | io.smb2.in.alloc_size = 0;
|
---|
1185 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
1186 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
1187 | io.smb2.in.security_flags = 0;
|
---|
1188 | io.smb2.in.fname = sname1;
|
---|
1189 |
|
---|
1190 | /* Create two streams. */
|
---|
1191 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1192 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1193 | h1 = io.smb2.out.file.handle;
|
---|
1194 | smb2_util_close(tree, h1);
|
---|
1195 |
|
---|
1196 | io.smb2.in.fname = sname2;
|
---|
1197 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1198 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1199 | h1 = io.smb2.out.file.handle;
|
---|
1200 |
|
---|
1201 | smb2_util_close(tree, h1);
|
---|
1202 |
|
---|
1203 | /*
|
---|
1204 | * Open the second stream.
|
---|
1205 | */
|
---|
1206 |
|
---|
1207 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
|
---|
1208 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1209 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1210 | h1 = io.smb2.out.file.handle;
|
---|
1211 |
|
---|
1212 | /*
|
---|
1213 | * Now rename the second stream onto the first.
|
---|
1214 | */
|
---|
1215 |
|
---|
1216 | ZERO_STRUCT(sfinfo);
|
---|
1217 |
|
---|
1218 | sfinfo.rename_information.in.overwrite = 1;
|
---|
1219 | sfinfo.rename_information.in.root_fid = 0;
|
---|
1220 | sfinfo.rename_information.in.new_name = ":Stream One";
|
---|
1221 | CHECK_CALL_HANDLE(RENAME_INFORMATION, NT_STATUS_OK);
|
---|
1222 | done:
|
---|
1223 | smb2_util_close(tree, h1);
|
---|
1224 | status = smb2_util_unlink(tree, fname);
|
---|
1225 | smb2_deltree(tree, DNAME);
|
---|
1226 | talloc_free(mem_ctx);
|
---|
1227 |
|
---|
1228 | return ret;
|
---|
1229 | }
|
---|
1230 |
|
---|
1231 | static bool test_stream_rename2(struct torture_context *tctx,
|
---|
1232 | struct smb2_tree *tree)
|
---|
1233 | {
|
---|
1234 | TALLOC_CTX *mem_ctx = talloc_new(tctx);
|
---|
1235 | NTSTATUS status;
|
---|
1236 | union smb_open io;
|
---|
1237 | const char *fname1 = DNAME "\\stream_rename2.txt";
|
---|
1238 | const char *fname2 = DNAME "\\stream2_rename2.txt";
|
---|
1239 | const char *stream_name1 = ":Stream One:$DATA";
|
---|
1240 | const char *stream_name2 = ":Stream Two:$DATA";
|
---|
1241 | const char *stream_name_default = "::$DATA";
|
---|
1242 | const char *sname1;
|
---|
1243 | const char *sname2;
|
---|
1244 | bool ret = true;
|
---|
1245 | struct smb2_handle h, h1;
|
---|
1246 | union smb_setfileinfo sinfo;
|
---|
1247 |
|
---|
1248 | sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream One");
|
---|
1249 | sname2 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream Two");
|
---|
1250 |
|
---|
1251 | smb2_util_unlink(tree, fname1);
|
---|
1252 | smb2_util_unlink(tree, fname2);
|
---|
1253 | smb2_deltree(tree, DNAME);
|
---|
1254 |
|
---|
1255 | status = torture_smb2_testdir(tree, DNAME, &h);
|
---|
1256 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1257 |
|
---|
1258 | ZERO_STRUCT(io.smb2);
|
---|
1259 | io.smb2.in.create_flags = 0;
|
---|
1260 | io.smb2.in.desired_access = SEC_FILE_READ_DATA |
|
---|
1261 | SEC_FILE_WRITE_DATA |
|
---|
1262 | SEC_STD_DELETE |
|
---|
1263 | SEC_FILE_APPEND_DATA |
|
---|
1264 | SEC_STD_READ_CONTROL;
|
---|
1265 | io.smb2.in.create_options = 0;
|
---|
1266 | io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
|
---|
1267 | io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
|
---|
1268 | NTCREATEX_SHARE_ACCESS_WRITE |
|
---|
1269 | NTCREATEX_SHARE_ACCESS_DELETE;
|
---|
1270 | io.smb2.in.alloc_size = 0;
|
---|
1271 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
1272 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
1273 | io.smb2.in.security_flags = 0;
|
---|
1274 | io.smb2.in.fname = sname1;
|
---|
1275 |
|
---|
1276 | /* Open/create new stream. */
|
---|
1277 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1278 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1279 |
|
---|
1280 | smb2_util_close(tree, io.smb2.out.file.handle);
|
---|
1281 |
|
---|
1282 | /*
|
---|
1283 | * Reopen the stream for SMB2 renames.
|
---|
1284 | */
|
---|
1285 | io.smb2.in.fname = sname1;
|
---|
1286 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
1287 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1288 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1289 | h1 = io.smb2.out.file.handle;
|
---|
1290 |
|
---|
1291 | /*
|
---|
1292 | * Check SMB2 rename of a stream using :<stream>.
|
---|
1293 | */
|
---|
1294 | torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
|
---|
1295 | ":<stream>\n", __location__);
|
---|
1296 | ZERO_STRUCT(sinfo);
|
---|
1297 | sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION_SMB2;
|
---|
1298 | sinfo.rename_information.in.file.handle = h1;
|
---|
1299 | sinfo.rename_information.in.overwrite = 1;
|
---|
1300 | sinfo.rename_information.in.root_fid = 0;
|
---|
1301 | sinfo.rename_information.in.new_name = stream_name1;
|
---|
1302 | status = smb2_setinfo_file(tree, &sinfo);
|
---|
1303 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1304 |
|
---|
1305 | /*
|
---|
1306 | * Check SMB2 rename of an overwriting stream using :<stream>.
|
---|
1307 | */
|
---|
1308 | torture_comment(tctx, "(%s) Checking SMB2 rename of an overwriting "
|
---|
1309 | "stream using :<stream>\n", __location__);
|
---|
1310 |
|
---|
1311 | /* Create second stream. */
|
---|
1312 | io.smb2.in.fname = sname2;
|
---|
1313 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
1314 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1315 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1316 | smb2_util_close(tree, io.smb2.out.file.handle);
|
---|
1317 |
|
---|
1318 | /* Rename the first stream onto the second. */
|
---|
1319 | sinfo.rename_information.in.file.handle = h1;
|
---|
1320 | sinfo.rename_information.in.new_name = stream_name2;
|
---|
1321 | status = smb2_setinfo_file(tree, &sinfo);
|
---|
1322 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1323 |
|
---|
1324 | smb2_util_close(tree, h1);
|
---|
1325 |
|
---|
1326 | /*
|
---|
1327 | * Reopen the stream with the new name.
|
---|
1328 | */
|
---|
1329 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
1330 | io.smb2.in.fname = sname2;
|
---|
1331 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1332 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1333 | h1 = io.smb2.out.file.handle;
|
---|
1334 |
|
---|
1335 | /*
|
---|
1336 | * Check SMB2 rename of a stream using <base>:<stream>.
|
---|
1337 | */
|
---|
1338 | torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
|
---|
1339 | "<base>:<stream>\n", __location__);
|
---|
1340 | sinfo.rename_information.in.file.handle = h1;
|
---|
1341 | sinfo.rename_information.in.new_name = sname1;
|
---|
1342 | status = smb2_setinfo_file(tree, &sinfo);
|
---|
1343 | CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
---|
1344 |
|
---|
1345 | if (!torture_setting_bool(tctx, "samba4", false)) {
|
---|
1346 | /*
|
---|
1347 | * Check SMB2 rename to the default stream using :<stream>.
|
---|
1348 | */
|
---|
1349 | torture_comment(tctx, "(%s) Checking SMB2 rename to default stream "
|
---|
1350 | "using :<stream>\n", __location__);
|
---|
1351 | sinfo.rename_information.in.file.handle = h1;
|
---|
1352 | sinfo.rename_information.in.new_name = stream_name_default;
|
---|
1353 | status = smb2_setinfo_file(tree, &sinfo);
|
---|
1354 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1355 | }
|
---|
1356 |
|
---|
1357 | smb2_util_close(tree, h1);
|
---|
1358 |
|
---|
1359 | done:
|
---|
1360 | smb2_util_close(tree, h1);
|
---|
1361 | status = smb2_util_unlink(tree, fname1);
|
---|
1362 | status = smb2_util_unlink(tree, fname2);
|
---|
1363 | smb2_deltree(tree, DNAME);
|
---|
1364 | talloc_free(mem_ctx);
|
---|
1365 |
|
---|
1366 | return ret;
|
---|
1367 | }
|
---|
1368 |
|
---|
1369 | static bool create_file_with_stream(struct torture_context *tctx,
|
---|
1370 | struct smb2_tree *tree,
|
---|
1371 | TALLOC_CTX *mem_ctx,
|
---|
1372 | const char *base_fname,
|
---|
1373 | const char *stream)
|
---|
1374 | {
|
---|
1375 | NTSTATUS status;
|
---|
1376 | bool ret = true;
|
---|
1377 | union smb_open io;
|
---|
1378 |
|
---|
1379 | /* Create a file with a stream */
|
---|
1380 | ZERO_STRUCT(io.smb2);
|
---|
1381 | io.smb2.in.create_flags = 0;
|
---|
1382 | io.smb2.in.desired_access = SEC_FILE_READ_DATA |
|
---|
1383 | SEC_FILE_WRITE_DATA |
|
---|
1384 | SEC_FILE_APPEND_DATA |
|
---|
1385 | SEC_STD_READ_CONTROL;
|
---|
1386 | io.smb2.in.create_options = 0;
|
---|
1387 | io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
|
---|
1388 | io.smb2.in.share_access = 0;
|
---|
1389 | io.smb2.in.alloc_size = 0;
|
---|
1390 | io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
|
---|
1391 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
1392 | io.smb2.in.security_flags = 0;
|
---|
1393 | io.smb2.in.fname = stream;
|
---|
1394 |
|
---|
1395 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1396 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1397 |
|
---|
1398 | done:
|
---|
1399 | smb2_util_close(tree, io.smb2.out.file.handle);
|
---|
1400 | return ret;
|
---|
1401 | }
|
---|
1402 |
|
---|
1403 |
|
---|
1404 | /* Test how streams interact with create dispositions */
|
---|
1405 | static bool test_stream_create_disposition(struct torture_context *tctx,
|
---|
1406 | struct smb2_tree *tree)
|
---|
1407 | {
|
---|
1408 | TALLOC_CTX *mem_ctx = talloc_new(tctx);
|
---|
1409 | NTSTATUS status;
|
---|
1410 | union smb_open io;
|
---|
1411 | const char *fname = DNAME "\\stream_create_disp.txt";
|
---|
1412 | const char *stream = "Stream One:$DATA";
|
---|
1413 | const char *fname_stream;
|
---|
1414 | const char *default_stream_name = "::$DATA";
|
---|
1415 | const char *stream_list[2];
|
---|
1416 | bool ret = true;
|
---|
1417 | struct smb2_handle h, h1;
|
---|
1418 |
|
---|
1419 | /* clean slate .. */
|
---|
1420 | smb2_util_unlink(tree, fname);
|
---|
1421 | smb2_deltree(tree, fname);
|
---|
1422 | smb2_deltree(tree, DNAME);
|
---|
1423 |
|
---|
1424 | status = torture_smb2_testdir(tree, DNAME, &h);
|
---|
1425 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1426 |
|
---|
1427 | fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
|
---|
1428 |
|
---|
1429 | stream_list[0] = talloc_asprintf(mem_ctx, ":%s", stream);
|
---|
1430 | stream_list[1] = default_stream_name;
|
---|
1431 |
|
---|
1432 | if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
|
---|
1433 | fname_stream)) {
|
---|
1434 | goto done;
|
---|
1435 | }
|
---|
1436 |
|
---|
1437 | /* Open the base file with OPEN */
|
---|
1438 | ZERO_STRUCT(io.smb2);
|
---|
1439 | io.smb2.in.create_flags = 0;
|
---|
1440 | io.smb2.in.desired_access = SEC_FILE_READ_DATA |
|
---|
1441 | SEC_FILE_WRITE_DATA |
|
---|
1442 | SEC_FILE_APPEND_DATA |
|
---|
1443 | SEC_STD_READ_CONTROL;
|
---|
1444 | io.smb2.in.create_options = 0;
|
---|
1445 | io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
|
---|
1446 | io.smb2.in.share_access = 0;
|
---|
1447 | io.smb2.in.alloc_size = 0;
|
---|
1448 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
1449 | io.smb2.in.security_flags = 0;
|
---|
1450 | io.smb2.in.fname = fname;
|
---|
1451 |
|
---|
1452 | /*
|
---|
1453 | * check create open: sanity check
|
---|
1454 | */
|
---|
1455 | torture_comment(tctx, "(%s) Checking create disp: open\n",
|
---|
1456 | __location__);
|
---|
1457 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
1458 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1459 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1460 | if (!check_stream_list(tree, tctx, fname, 2, stream_list,
|
---|
1461 | io.smb2.out.file.handle)) {
|
---|
1462 | goto done;
|
---|
1463 | }
|
---|
1464 | smb2_util_close(tree, io.smb2.out.file.handle);
|
---|
1465 |
|
---|
1466 | /*
|
---|
1467 | * check create overwrite
|
---|
1468 | */
|
---|
1469 | torture_comment(tctx, "(%s) Checking create disp: overwrite\n",
|
---|
1470 | __location__);
|
---|
1471 | io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
|
---|
1472 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1473 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1474 | if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
|
---|
1475 | io.smb2.out.file.handle)) {
|
---|
1476 | goto done;
|
---|
1477 | }
|
---|
1478 | smb2_util_close(tree, io.smb2.out.file.handle);
|
---|
1479 |
|
---|
1480 | /*
|
---|
1481 | * check create overwrite_if
|
---|
1482 | */
|
---|
1483 | torture_comment(tctx, "(%s) Checking create disp: overwrite_if\n",
|
---|
1484 | __location__);
|
---|
1485 | smb2_util_unlink(tree, fname);
|
---|
1486 | if (!create_file_with_stream(tctx, tree, mem_ctx, fname, fname_stream))
|
---|
1487 | goto done;
|
---|
1488 |
|
---|
1489 | io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
|
---|
1490 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1491 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1492 | if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
|
---|
1493 | io.smb2.out.file.handle)) {
|
---|
1494 | goto done;
|
---|
1495 | }
|
---|
1496 | smb2_util_close(tree, io.smb2.out.file.handle);
|
---|
1497 |
|
---|
1498 | /*
|
---|
1499 | * check create supersede
|
---|
1500 | */
|
---|
1501 | torture_comment(tctx, "(%s) Checking create disp: supersede\n",
|
---|
1502 | __location__);
|
---|
1503 | smb2_util_unlink(tree, fname);
|
---|
1504 | if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
|
---|
1505 | fname_stream)) {
|
---|
1506 | goto done;
|
---|
1507 | }
|
---|
1508 |
|
---|
1509 | io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
|
---|
1510 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1511 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1512 | if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
|
---|
1513 | io.smb2.out.file.handle)) {
|
---|
1514 | goto done;
|
---|
1515 | }
|
---|
1516 | smb2_util_close(tree, io.smb2.out.file.handle);
|
---|
1517 |
|
---|
1518 | /*
|
---|
1519 | * check create overwrite_if on a stream.
|
---|
1520 | */
|
---|
1521 | torture_comment(tctx, "(%s) Checking create disp: overwrite_if on "
|
---|
1522 | "stream\n", __location__);
|
---|
1523 | smb2_util_unlink(tree, fname);
|
---|
1524 | if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
|
---|
1525 | fname_stream)) {
|
---|
1526 | goto done;
|
---|
1527 | }
|
---|
1528 |
|
---|
1529 | io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
|
---|
1530 | io.smb2.in.fname = fname_stream;
|
---|
1531 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1532 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1533 | if (!check_stream_list(tree, tctx, fname, 2, stream_list,
|
---|
1534 | io.smb2.out.file.handle)) {
|
---|
1535 | goto done;
|
---|
1536 | }
|
---|
1537 | smb2_util_close(tree, io.smb2.out.file.handle);
|
---|
1538 | done:
|
---|
1539 | smb2_util_close(tree, h1);
|
---|
1540 | smb2_util_unlink(tree, fname);
|
---|
1541 | smb2_deltree(tree, DNAME);
|
---|
1542 | talloc_free(mem_ctx);
|
---|
1543 |
|
---|
1544 | return ret;
|
---|
1545 | }
|
---|
1546 |
|
---|
1547 | static bool open_stream(struct smb2_tree *tree,
|
---|
1548 | struct torture_context *mem_ctx,
|
---|
1549 | const char *fname,
|
---|
1550 | struct smb2_handle *h_out)
|
---|
1551 | {
|
---|
1552 | NTSTATUS status;
|
---|
1553 | union smb_open io;
|
---|
1554 |
|
---|
1555 | ZERO_STRUCT(io.smb2);
|
---|
1556 | io.smb2.in.create_flags = 0;
|
---|
1557 | io.smb2.in.desired_access = SEC_FILE_READ_DATA |
|
---|
1558 | SEC_FILE_WRITE_DATA |
|
---|
1559 | SEC_FILE_APPEND_DATA |
|
---|
1560 | SEC_STD_READ_CONTROL |
|
---|
1561 | SEC_FILE_WRITE_ATTRIBUTE;
|
---|
1562 | io.smb2.in.create_options = 0;
|
---|
1563 | io.smb2.in.file_attributes = 0;
|
---|
1564 | io.smb2.in.share_access = 0;
|
---|
1565 | io.smb2.in.alloc_size = 0;
|
---|
1566 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
|
---|
1567 | io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
|
---|
1568 | io.smb2.in.security_flags = 0;
|
---|
1569 | io.smb2.in.fname = fname;
|
---|
1570 |
|
---|
1571 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1572 | if (!NT_STATUS_IS_OK(status)) {
|
---|
1573 | return false;
|
---|
1574 | }
|
---|
1575 | *h_out = io.smb2.out.file.handle;
|
---|
1576 | return true;
|
---|
1577 | }
|
---|
1578 |
|
---|
1579 |
|
---|
1580 | /* Test the effect of setting attributes on a stream. */
|
---|
1581 | static bool test_stream_attributes(struct torture_context *tctx,
|
---|
1582 | struct smb2_tree *tree)
|
---|
1583 | {
|
---|
1584 | TALLOC_CTX *mem_ctx = talloc_new(tctx);
|
---|
1585 | bool ret = true;
|
---|
1586 | NTSTATUS status;
|
---|
1587 | union smb_open io;
|
---|
1588 | const char *fname = DNAME "\\stream_attr.txt";
|
---|
1589 | const char *stream = "Stream One:$DATA";
|
---|
1590 | const char *fname_stream;
|
---|
1591 | struct smb2_handle h, h1;
|
---|
1592 | union smb_fileinfo finfo;
|
---|
1593 | union smb_setfileinfo sfinfo;
|
---|
1594 | time_t basetime = (time(NULL) - 86400) & ~1;
|
---|
1595 |
|
---|
1596 | torture_comment(tctx, "(%s) testing attribute setting on stream\n",
|
---|
1597 | __location__);
|
---|
1598 |
|
---|
1599 | /* clean slate .. */
|
---|
1600 | smb2_util_unlink(tree, fname);
|
---|
1601 | smb2_deltree(tree, fname);
|
---|
1602 | smb2_deltree(tree, DNAME);
|
---|
1603 |
|
---|
1604 | status = torture_smb2_testdir(tree, DNAME, &h);
|
---|
1605 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1606 |
|
---|
1607 | fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
|
---|
1608 |
|
---|
1609 | /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
|
---|
1610 | ret = create_file_with_stream(tctx, tree, mem_ctx, fname,
|
---|
1611 | fname_stream);
|
---|
1612 | if (!ret) {
|
---|
1613 | goto done;
|
---|
1614 | }
|
---|
1615 |
|
---|
1616 | ZERO_STRUCT(io.smb2);
|
---|
1617 | io.smb2.in.fname = fname;
|
---|
1618 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
1619 | io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
|
---|
1620 | io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
|
---|
1621 | NTCREATEX_SHARE_ACCESS_WRITE |
|
---|
1622 | NTCREATEX_SHARE_ACCESS_DELETE;
|
---|
1623 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1624 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1625 |
|
---|
1626 | ZERO_STRUCT(finfo);
|
---|
1627 | finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
|
---|
1628 | finfo.generic.in.file.handle = io.smb2.out.file.handle;
|
---|
1629 | status = smb2_getinfo_file(tree, mem_ctx, &finfo);
|
---|
1630 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1631 |
|
---|
1632 | if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
|
---|
1633 | torture_comment(tctx, "(%s) Incorrect attrib %x - should be "
|
---|
1634 | "%x\n", __location__,
|
---|
1635 | (unsigned int)finfo.basic_info.out.attrib,
|
---|
1636 | (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
|
---|
1637 | ret = false;
|
---|
1638 | goto done;
|
---|
1639 | }
|
---|
1640 |
|
---|
1641 | smb2_util_close(tree, io.smb2.out.file.handle);
|
---|
1642 | /* Now open the stream name. */
|
---|
1643 |
|
---|
1644 | if (!open_stream(tree, tctx, fname_stream, &h1)) {
|
---|
1645 | goto done;
|
---|
1646 | }
|
---|
1647 |
|
---|
1648 | /* Change the time on the stream. */
|
---|
1649 | ZERO_STRUCT(sfinfo);
|
---|
1650 | unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
|
---|
1651 | sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
|
---|
1652 | sfinfo.generic.in.file.handle = h1;
|
---|
1653 | status = smb2_setinfo_file(tree, &sfinfo);
|
---|
1654 | if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
|
---|
1655 | torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
|
---|
1656 | __location__, "SETATTR",
|
---|
1657 | nt_errstr(status), nt_errstr(NT_STATUS_OK));
|
---|
1658 | ret = false;
|
---|
1659 | goto done;
|
---|
1660 | }
|
---|
1661 |
|
---|
1662 | smb2_util_close(tree, h1);
|
---|
1663 |
|
---|
1664 | ZERO_STRUCT(io.smb2);
|
---|
1665 | io.smb2.in.fname = fname;
|
---|
1666 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
1667 | io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
|
---|
1668 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1669 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1670 | h1 = io.smb2.out.file.handle;
|
---|
1671 |
|
---|
1672 | ZERO_STRUCT(finfo);
|
---|
1673 | finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
|
---|
1674 | finfo.generic.in.file.handle = h1;
|
---|
1675 | status = smb2_getinfo_file(tree, mem_ctx, &finfo);
|
---|
1676 | if (!NT_STATUS_IS_OK(status)) {
|
---|
1677 | torture_comment(tctx, "(%s) %s pathinfo - %s\n",
|
---|
1678 | __location__, "SETATTRE", nt_errstr(status));
|
---|
1679 | ret = false;
|
---|
1680 | goto done;
|
---|
1681 | }
|
---|
1682 |
|
---|
1683 | if (nt_time_to_unix(finfo.basic_info.out.write_time) != basetime) {
|
---|
1684 | torture_comment(tctx, "(%s) time incorrect.\n", __location__);
|
---|
1685 | ret = false;
|
---|
1686 | goto done;
|
---|
1687 | }
|
---|
1688 | smb2_util_close(tree, h1);
|
---|
1689 |
|
---|
1690 | if (!open_stream(tree, tctx, fname_stream, &h1)) {
|
---|
1691 | goto done;
|
---|
1692 | }
|
---|
1693 |
|
---|
1694 | /* Changing attributes on stream */
|
---|
1695 | ZERO_STRUCT(sfinfo);
|
---|
1696 | sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
|
---|
1697 |
|
---|
1698 | sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
|
---|
1699 | sfinfo.generic.in.file.handle = h1;
|
---|
1700 | status = smb2_setinfo_file(tree, &sfinfo);
|
---|
1701 | if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
|
---|
1702 | torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
|
---|
1703 | __location__, "SETATTR",
|
---|
1704 | nt_errstr(status), nt_errstr(NT_STATUS_OK));
|
---|
1705 | ret = false;
|
---|
1706 | goto done;
|
---|
1707 | }
|
---|
1708 |
|
---|
1709 | smb2_util_close(tree, h1);
|
---|
1710 |
|
---|
1711 | ZERO_STRUCT(io.smb2);
|
---|
1712 | io.smb2.in.fname = fname;
|
---|
1713 | io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
|
---|
1714 | io.smb2.in.desired_access = SEC_FILE_READ_DATA;
|
---|
1715 | status = smb2_create(tree, mem_ctx, &(io.smb2));
|
---|
1716 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
1717 | h1 = io.smb2.out.file.handle;
|
---|
1718 |
|
---|
1719 | ZERO_STRUCT(finfo);
|
---|
1720 | finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
|
---|
1721 | finfo.generic.in.file.handle = h1;
|
---|
1722 | status = smb2_getinfo_file(tree, mem_ctx, &finfo);
|
---|
1723 | CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
|
---|
1724 |
|
---|
1725 | done:
|
---|
1726 | smb2_util_close(tree, h1);
|
---|
1727 | smb2_util_unlink(tree, fname);
|
---|
1728 | smb2_deltree(tree, DNAME);
|
---|
1729 | talloc_free(mem_ctx);
|
---|
1730 |
|
---|
1731 | return ret;
|
---|
1732 | }
|
---|
1733 |
|
---|
1734 |
|
---|
1735 | /*
|
---|
1736 | basic testing of streams calls SMB2
|
---|
1737 | */
|
---|
1738 | struct torture_suite *torture_smb2_streams_init(void)
|
---|
1739 | {
|
---|
1740 | struct torture_suite *suite =
|
---|
1741 | torture_suite_create(talloc_autofree_context(), "streams");
|
---|
1742 |
|
---|
1743 | torture_suite_add_1smb2_test(suite, "dir", test_stream_dir);
|
---|
1744 | torture_suite_add_1smb2_test(suite, "io", test_stream_io);
|
---|
1745 | torture_suite_add_1smb2_test(suite, "sharemodes", test_stream_sharemodes);
|
---|
1746 | torture_suite_add_1smb2_test(suite, "names", test_stream_names);
|
---|
1747 | torture_suite_add_1smb2_test(suite, "names2", test_stream_names2);
|
---|
1748 | torture_suite_add_1smb2_test(suite, "rename", test_stream_rename);
|
---|
1749 | torture_suite_add_1smb2_test(suite, "rename2", test_stream_rename2);
|
---|
1750 | torture_suite_add_1smb2_test(suite, "create-disposition", test_stream_create_disposition);
|
---|
1751 | torture_suite_add_1smb2_test(suite, "attributes", test_stream_attributes);
|
---|
1752 | torture_suite_add_1smb2_test(suite, "delete", test_stream_delete);
|
---|
1753 |
|
---|
1754 | suite->description = talloc_strdup(suite, "SMB2-STREAM tests");
|
---|
1755 |
|
---|
1756 | return suite;
|
---|
1757 | }
|
---|