Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : SMB2 create test suite
5 :
6 : Copyright (C) Andrew Tridgell 2008
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "libcli/smb2/smb2.h"
24 : #include "libcli/smb2/smb2_calls.h"
25 : #include "libcli/smb/smbXcli_base.h"
26 : #include "torture/torture.h"
27 : #include "torture/util.h"
28 : #include "torture/smb2/proto.h"
29 : #include "librpc/gen_ndr/ndr_security.h"
30 : #include "libcli/security/security.h"
31 :
32 : #include "system/filesys.h"
33 : #include "auth/credentials/credentials.h"
34 : #include "lib/cmdline/cmdline.h"
35 : #include "librpc/gen_ndr/security.h"
36 : #include "lib/events/events.h"
37 :
38 : #define FNAME "test_create.dat"
39 : #define DNAME "smb2_open"
40 :
41 : #define CHECK_STATUS(status, correct) do { \
42 : if (!NT_STATUS_EQUAL(status, correct)) { \
43 : torture_result(tctx, TORTURE_FAIL, \
44 : "(%s) Incorrect status %s - should be %s\n", \
45 : __location__, nt_errstr(status), nt_errstr(correct)); \
46 : return false; \
47 : }} while (0)
48 :
49 : #define CHECK_EQUAL(v, correct) do { \
50 : if (v != correct) { \
51 : torture_result(tctx, TORTURE_FAIL, \
52 : "(%s) Incorrect value for %s 0x%08llx - " \
53 : "should be 0x%08llx\n", \
54 : __location__, #v, \
55 : (unsigned long long)v, \
56 : (unsigned long long)correct); \
57 : return false; \
58 : }} while (0)
59 :
60 : #define CHECK_TIME(t, field) do { \
61 : time_t t1, t2; \
62 : finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
63 : finfo.all_info.in.file.handle = h1; \
64 : status = smb2_getinfo_file(tree, tctx, &finfo); \
65 : CHECK_STATUS(status, NT_STATUS_OK); \
66 : t1 = t & ~1; \
67 : t2 = nt_time_to_unix(finfo.all_info.out.field) & ~1; \
68 : if (abs(t1-t2) > 2) { \
69 : torture_result(tctx, TORTURE_FAIL, \
70 : "(%s) wrong time for field %s %s - %s\n", \
71 : __location__, #field, \
72 : timestring(tctx, t1), \
73 : timestring(tctx, t2)); \
74 : dump_all_info(tctx, &finfo); \
75 : ret = false; \
76 : }} while (0)
77 :
78 : #define CHECK_NTTIME(t, field) do { \
79 : NTTIME t2; \
80 : finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
81 : finfo.all_info.in.file.handle = h1; \
82 : status = smb2_getinfo_file(tree, tctx, &finfo); \
83 : CHECK_STATUS(status, NT_STATUS_OK); \
84 : t2 = finfo.all_info.out.field; \
85 : if (llabs((int64_t)(t-t2)) > 20000) { \
86 : torture_result(tctx, TORTURE_FAIL, \
87 : "(%s) wrong time for field %s %s - %s\n", \
88 : __location__, #field, \
89 : nt_time_string(tctx, t), \
90 : nt_time_string(tctx, t2)); \
91 : dump_all_info(tctx, &finfo); \
92 : ret = false; \
93 : }} while (0)
94 :
95 : #define CHECK_ALL_INFO(v, field) do { \
96 : finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
97 : finfo.all_info.in.file.handle = h1; \
98 : status = smb2_getinfo_file(tree, tctx, &finfo); \
99 : CHECK_STATUS(status, NT_STATUS_OK); \
100 : if ((v) != (finfo.all_info.out.field)) { \
101 : torture_result(tctx, TORTURE_FAIL, \
102 : "(%s) wrong value for field %s 0x%x - 0x%x\n", \
103 : __location__, #field, (int)v,\
104 : (int)(finfo.all_info.out.field)); \
105 : dump_all_info(tctx, &finfo); \
106 : ret = false; \
107 : }} while (0)
108 :
109 : #define CHECK_VAL(v, correct) do { \
110 : if ((v) != (correct)) { \
111 : torture_result(tctx, TORTURE_FAIL, \
112 : "(%s) wrong value for %s 0x%x - should be 0x%x\n", \
113 : __location__, #v, (int)(v), (int)correct); \
114 : ret = false; \
115 : }} while (0)
116 :
117 : #define SET_ATTRIB(sattrib) do { \
118 : union smb_setfileinfo sfinfo; \
119 : ZERO_STRUCT(sfinfo.basic_info.in); \
120 : sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION; \
121 : sfinfo.basic_info.in.file.handle = h1; \
122 : sfinfo.basic_info.in.attrib = sattrib; \
123 : status = smb2_setinfo_file(tree, &sfinfo); \
124 : if (!NT_STATUS_IS_OK(status)) { \
125 : torture_comment(tctx, \
126 : "(%s) Failed to set attrib 0x%x on %s\n", \
127 : __location__, (unsigned int)(sattrib), fname); \
128 : }} while (0)
129 :
130 : /*
131 : stress testing keepalive iops
132 : */
133 :
134 : struct test_smb2_bench_echo_conn;
135 : struct test_smb2_bench_echo_loop;
136 :
137 : struct test_smb2_bench_echo_state {
138 : struct torture_context *tctx;
139 : size_t num_conns;
140 : struct test_smb2_bench_echo_conn *conns;
141 : size_t num_loops;
142 : struct test_smb2_bench_echo_loop *loops;
143 : struct timeval starttime;
144 : int timecount;
145 : int timelimit;
146 : uint64_t num_finished;
147 : double total_latency;
148 : double min_latency;
149 : double max_latency;
150 : bool ok;
151 : bool stop;
152 : };
153 :
154 : struct test_smb2_bench_echo_conn {
155 : struct test_smb2_bench_echo_state *state;
156 : int idx;
157 : struct smb2_tree *tree;
158 : };
159 :
160 : struct test_smb2_bench_echo_loop {
161 : struct test_smb2_bench_echo_state *state;
162 : struct test_smb2_bench_echo_conn *conn;
163 : int idx;
164 : struct tevent_immediate *im;
165 : struct tevent_req *req;
166 : struct timeval starttime;
167 : uint64_t num_started;
168 : uint64_t num_finished;
169 : double total_latency;
170 : double min_latency;
171 : double max_latency;
172 : NTSTATUS error;
173 : };
174 :
175 : static void test_smb2_bench_echo_loop_do(
176 : struct test_smb2_bench_echo_loop *loop);
177 :
178 0 : static void test_smb2_bench_echo_loop_start(struct tevent_context *ctx,
179 : struct tevent_immediate *im,
180 : void *private_data)
181 : {
182 0 : struct test_smb2_bench_echo_loop *loop =
183 : (struct test_smb2_bench_echo_loop *)
184 : private_data;
185 :
186 0 : test_smb2_bench_echo_loop_do(loop);
187 0 : }
188 :
189 : static void test_smb2_bench_echo_loop_done(struct tevent_req *req);
190 :
191 0 : static void test_smb2_bench_echo_loop_do(
192 : struct test_smb2_bench_echo_loop *loop)
193 : {
194 0 : struct test_smb2_bench_echo_state *state = loop->state;
195 :
196 0 : loop->num_started += 1;
197 0 : loop->starttime = timeval_current();
198 0 : loop->req = smb2cli_echo_send(state->loops,
199 0 : state->tctx->ev,
200 0 : loop->conn->tree->session->transport->conn,
201 : 1000);
202 0 : torture_assert_goto(state->tctx, loop->req != NULL,
203 : state->ok, asserted, "smb2_create_send");
204 :
205 0 : tevent_req_set_callback(loop->req,
206 : test_smb2_bench_echo_loop_done,
207 : loop);
208 0 : return;
209 0 : asserted:
210 0 : state->stop = true;
211 : }
212 :
213 0 : static void test_smb2_bench_echo_loop_done(struct tevent_req *req)
214 : {
215 : struct test_smb2_bench_echo_loop *loop =
216 : (struct test_smb2_bench_echo_loop *)
217 0 : _tevent_req_callback_data(req);
218 0 : struct test_smb2_bench_echo_state *state = loop->state;
219 0 : double latency = timeval_elapsed(&loop->starttime);
220 0 : TALLOC_CTX *frame = talloc_stackframe();
221 :
222 0 : torture_assert_goto(state->tctx, loop->req == req,
223 : state->ok, asserted, __location__);
224 0 : loop->error = smb2cli_echo_recv(req);
225 0 : torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
226 : state->ok, asserted, __location__);
227 0 : SMB_ASSERT(latency >= 0.000001);
228 :
229 0 : if (loop->num_finished == 0) {
230 : /* first round */
231 0 : loop->min_latency = latency;
232 0 : loop->max_latency = latency;
233 : }
234 :
235 0 : loop->num_finished += 1;
236 0 : loop->total_latency += latency;
237 :
238 0 : if (latency < loop->min_latency) {
239 0 : loop->min_latency = latency;
240 : }
241 :
242 0 : if (latency > loop->max_latency) {
243 0 : loop->max_latency = latency;
244 : }
245 :
246 0 : TALLOC_FREE(frame);
247 0 : test_smb2_bench_echo_loop_do(loop);
248 0 : return;
249 0 : asserted:
250 0 : state->stop = true;
251 0 : TALLOC_FREE(frame);
252 : }
253 :
254 0 : static void test_smb2_bench_echo_progress(struct tevent_context *ev,
255 : struct tevent_timer *te,
256 : struct timeval current_time,
257 : void *private_data)
258 : {
259 0 : struct test_smb2_bench_echo_state *state =
260 : (struct test_smb2_bench_echo_state *)private_data;
261 0 : uint64_t num_echos = 0;
262 0 : double total_echo_latency = 0;
263 0 : double min_echo_latency = 0;
264 0 : double max_echo_latency = 0;
265 0 : double avs_echo_latency = 0;
266 : size_t i;
267 :
268 0 : state->timecount += 1;
269 :
270 0 : for (i=0;i<state->num_loops;i++) {
271 0 : struct test_smb2_bench_echo_loop *loop =
272 0 : &state->loops[i];
273 :
274 0 : num_echos += loop->num_finished;
275 0 : total_echo_latency += loop->total_latency;
276 0 : if (min_echo_latency == 0.0 && loop->min_latency != 0.0) {
277 0 : min_echo_latency = loop->min_latency;
278 : }
279 0 : if (loop->min_latency < min_echo_latency) {
280 0 : min_echo_latency = loop->min_latency;
281 : }
282 0 : if (max_echo_latency == 0.0) {
283 0 : max_echo_latency = loop->max_latency;
284 : }
285 0 : if (loop->max_latency > max_echo_latency) {
286 0 : max_echo_latency = loop->max_latency;
287 : }
288 0 : loop->num_finished = 0;
289 0 : loop->total_latency = 0.0;
290 : }
291 :
292 0 : state->num_finished += num_echos;
293 0 : state->total_latency += total_echo_latency;
294 0 : if (state->min_latency == 0.0 && min_echo_latency != 0.0) {
295 0 : state->min_latency = min_echo_latency;
296 : }
297 0 : if (min_echo_latency < state->min_latency) {
298 0 : state->min_latency = min_echo_latency;
299 : }
300 0 : if (state->max_latency == 0.0) {
301 0 : state->max_latency = max_echo_latency;
302 : }
303 0 : if (max_echo_latency > state->max_latency) {
304 0 : state->max_latency = max_echo_latency;
305 : }
306 :
307 0 : if (state->timecount < state->timelimit) {
308 0 : te = tevent_add_timer(state->tctx->ev,
309 : state,
310 : timeval_current_ofs(1, 0),
311 : test_smb2_bench_echo_progress,
312 : state);
313 0 : torture_assert_goto(state->tctx, te != NULL,
314 : state->ok, asserted, "tevent_add_timer");
315 :
316 0 : if (!torture_setting_bool(state->tctx, "progress", true)) {
317 0 : return;
318 : }
319 :
320 0 : avs_echo_latency = total_echo_latency / num_echos;
321 :
322 0 : torture_comment(state->tctx,
323 : "%.2f second: "
324 : "echo[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] \r",
325 0 : timeval_elapsed(&state->starttime),
326 : (unsigned long long)num_echos,
327 : avs_echo_latency,
328 : min_echo_latency,
329 : max_echo_latency);
330 0 : return;
331 : }
332 :
333 0 : avs_echo_latency = state->total_latency / state->num_finished;
334 0 : num_echos = state->num_finished / state->timelimit;
335 :
336 0 : torture_comment(state->tctx,
337 : "%.2f second: "
338 : "echo[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
339 0 : timeval_elapsed(&state->starttime),
340 : (unsigned long long)num_echos,
341 : avs_echo_latency,
342 : state->min_latency,
343 : state->max_latency);
344 :
345 0 : asserted:
346 0 : state->stop = true;
347 : }
348 :
349 0 : static bool test_smb2_bench_echo(struct torture_context *tctx,
350 : struct smb2_tree *tree)
351 : {
352 0 : struct test_smb2_bench_echo_state *state = NULL;
353 0 : bool ret = true;
354 0 : int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
355 0 : int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
356 : size_t i;
357 0 : size_t li = 0;
358 0 : int timelimit = torture_setting_int(tctx, "timelimit", 10);
359 0 : struct tevent_timer *te = NULL;
360 : uint32_t timeout_msec;
361 :
362 0 : state = talloc_zero(tctx, struct test_smb2_bench_echo_state);
363 0 : torture_assert(tctx, state != NULL, __location__);
364 0 : state->tctx = tctx;
365 0 : state->num_conns = torture_nprocs;
366 0 : state->conns = talloc_zero_array(state,
367 : struct test_smb2_bench_echo_conn,
368 : state->num_conns);
369 0 : torture_assert(tctx, state->conns != NULL, __location__);
370 0 : state->num_loops = torture_nprocs * torture_qdepth;
371 0 : state->loops = talloc_zero_array(state,
372 : struct test_smb2_bench_echo_loop,
373 : state->num_loops);
374 0 : torture_assert(tctx, state->loops != NULL, __location__);
375 0 : state->ok = true;
376 0 : state->timelimit = MAX(timelimit, 1);
377 :
378 0 : timeout_msec = tree->session->transport->options.request_timeout * 1000;
379 :
380 0 : torture_comment(tctx, "Opening %zu connections\n", state->num_conns);
381 :
382 0 : for (i=0;i<state->num_conns;i++) {
383 0 : struct smb2_tree *ct = NULL;
384 0 : DATA_BLOB out_input_buffer = data_blob_null;
385 0 : DATA_BLOB out_output_buffer = data_blob_null;
386 : size_t pcli;
387 :
388 0 : state->conns[i].state = state;
389 0 : state->conns[i].idx = i;
390 :
391 0 : if (!torture_smb2_connection(tctx, &ct)) {
392 0 : torture_comment(tctx, "Failed opening %zu/%zu connections\n", i, state->num_conns);
393 0 : return false;
394 : }
395 0 : state->conns[i].tree = talloc_steal(state->conns, ct);
396 :
397 0 : smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
398 0 : smb2cli_ioctl(ct->session->transport->conn,
399 : timeout_msec,
400 0 : ct->session->smbXcli,
401 0 : ct->smbXcli,
402 : UINT64_MAX, /* in_fid_persistent */
403 : UINT64_MAX, /* in_fid_volatile */
404 : UINT32_MAX,
405 : 0, /* in_max_input_length */
406 : NULL, /* in_input_buffer */
407 : 1, /* in_max_output_length */
408 : NULL, /* in_output_buffer */
409 : SMB2_IOCTL_FLAG_IS_FSCTL,
410 : ct,
411 : &out_input_buffer,
412 : &out_output_buffer);
413 0 : torture_assert(tctx,
414 : smbXcli_conn_is_connected(ct->session->transport->conn),
415 : "smbXcli_conn_is_connected");
416 :
417 0 : for (pcli = 0; pcli < torture_qdepth; pcli++) {
418 0 : struct test_smb2_bench_echo_loop *loop = &state->loops[li];
419 :
420 0 : loop->idx = li++;
421 0 : loop->state = state;
422 0 : loop->conn = &state->conns[i];
423 0 : loop->im = tevent_create_immediate(state->loops);
424 0 : torture_assert(tctx, loop->im != NULL, __location__);
425 :
426 0 : tevent_schedule_immediate(loop->im,
427 : tctx->ev,
428 : test_smb2_bench_echo_loop_start,
429 : loop);
430 : }
431 : }
432 :
433 0 : torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
434 : state->num_conns, torture_qdepth, state->num_loops);
435 :
436 0 : torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
437 :
438 0 : state->starttime = timeval_current();
439 :
440 0 : te = tevent_add_timer(tctx->ev,
441 : state,
442 : timeval_current_ofs(1, 0),
443 : test_smb2_bench_echo_progress,
444 : state);
445 0 : torture_assert(tctx, te != NULL, __location__);
446 :
447 0 : while (!state->stop) {
448 0 : int rc = tevent_loop_once(tctx->ev);
449 0 : torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
450 : }
451 :
452 0 : torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
453 0 : TALLOC_FREE(state);
454 0 : return ret;
455 : }
456 :
457 : /*
458 : test some interesting combinations found by gentest
459 : */
460 2 : static bool test_create_gentest(struct torture_context *tctx, struct smb2_tree *tree)
461 : {
462 : struct smb2_create io;
463 : NTSTATUS status;
464 : uint32_t access_mask, file_attributes_set;
465 : uint32_t ok_mask, not_supported_mask, invalid_parameter_mask;
466 : uint32_t not_a_directory_mask, unexpected_mask;
467 : union smb_fileinfo q;
468 :
469 2 : ZERO_STRUCT(io);
470 2 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
471 2 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
472 2 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
473 2 : io.in.share_access =
474 : NTCREATEX_SHARE_ACCESS_DELETE|
475 : NTCREATEX_SHARE_ACCESS_READ|
476 : NTCREATEX_SHARE_ACCESS_WRITE;
477 2 : io.in.create_options = 0;
478 2 : io.in.fname = FNAME;
479 :
480 2 : status = smb2_create(tree, tctx, &io);
481 2 : CHECK_STATUS(status, NT_STATUS_OK);
482 :
483 2 : status = smb2_util_close(tree, io.out.file.handle);
484 2 : CHECK_STATUS(status, NT_STATUS_OK);
485 :
486 2 : io.in.create_options = 0xF0000000;
487 2 : status = smb2_create(tree, tctx, &io);
488 2 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
489 :
490 2 : io.in.create_options = 0;
491 :
492 2 : io.in.file_attributes = FILE_ATTRIBUTE_DEVICE;
493 2 : status = smb2_create(tree, tctx, &io);
494 2 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
495 :
496 1 : io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
497 1 : status = smb2_create(tree, tctx, &io);
498 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
499 :
500 1 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
501 1 : io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
502 1 : status = smb2_create(tree, tctx, &io);
503 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
504 :
505 1 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
506 1 : io.in.desired_access = 0x08000000;
507 1 : status = smb2_create(tree, tctx, &io);
508 1 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
509 :
510 1 : io.in.desired_access = 0x04000000;
511 1 : status = smb2_create(tree, tctx, &io);
512 1 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
513 :
514 1 : io.in.file_attributes = 0;
515 1 : io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
516 1 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
517 1 : ok_mask = 0;
518 1 : not_supported_mask = 0;
519 1 : invalid_parameter_mask = 0;
520 1 : not_a_directory_mask = 0;
521 1 : unexpected_mask = 0;
522 : {
523 : int i;
524 33 : for (i=0;i<32;i++) {
525 32 : io.in.create_options = (uint32_t)1<<i;
526 32 : if (io.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
527 1 : continue;
528 : }
529 31 : status = smb2_create(tree, tctx, &io);
530 31 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
531 3 : not_supported_mask |= 1<<i;
532 28 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
533 8 : invalid_parameter_mask |= 1<<i;
534 20 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
535 1 : not_a_directory_mask |= 1<<i;
536 19 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
537 19 : ok_mask |= 1<<i;
538 19 : status = smb2_util_close(tree, io.out.file.handle);
539 19 : CHECK_STATUS(status, NT_STATUS_OK);
540 : } else {
541 0 : unexpected_mask |= 1<<i;
542 0 : torture_comment(tctx,
543 : "create option 0x%08x returned %s\n",
544 : 1<<i, nt_errstr(status));
545 : }
546 : }
547 : }
548 1 : io.in.create_options = 0;
549 :
550 1 : CHECK_EQUAL(ok_mask, 0x00efcf7e);
551 1 : CHECK_EQUAL(not_a_directory_mask, 0x00000001);
552 1 : CHECK_EQUAL(not_supported_mask, 0x00102080);
553 1 : CHECK_EQUAL(invalid_parameter_mask, 0xff000000);
554 1 : CHECK_EQUAL(unexpected_mask, 0x00000000);
555 :
556 1 : io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
557 1 : io.in.file_attributes = 0;
558 1 : access_mask = 0;
559 : {
560 : int i;
561 33 : for (i=0;i<32;i++) {
562 32 : io.in.desired_access = (uint32_t)1<<i;
563 32 : status = smb2_create(tree, tctx, &io);
564 32 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
565 19 : NT_STATUS_EQUAL(status, NT_STATUS_PRIVILEGE_NOT_HELD)) {
566 13 : access_mask |= io.in.desired_access;
567 : } else {
568 19 : CHECK_STATUS(status, NT_STATUS_OK);
569 19 : status = smb2_util_close(tree, io.out.file.handle);
570 19 : CHECK_STATUS(status, NT_STATUS_OK);
571 : }
572 : }
573 : }
574 :
575 1 : if (TARGET_IS_WIN7(tctx)) {
576 0 : CHECK_EQUAL(access_mask, 0x0de0fe00);
577 1 : } else if (torture_setting_bool(tctx, "samba4", false)) {
578 1 : CHECK_EQUAL(access_mask, 0x0cf0fe00);
579 : } else {
580 0 : CHECK_EQUAL(access_mask, 0x0df0fe00);
581 : }
582 :
583 1 : io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
584 1 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
585 1 : io.in.file_attributes = 0;
586 1 : ok_mask = 0;
587 1 : invalid_parameter_mask = 0;
588 1 : unexpected_mask = 0;
589 1 : file_attributes_set = 0;
590 : {
591 : int i;
592 33 : for (i=0;i<32;i++) {
593 32 : io.in.file_attributes = (uint32_t)1<<i;
594 32 : if (io.in.file_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
595 1 : continue;
596 : }
597 31 : smb2_deltree(tree, FNAME);
598 31 : status = smb2_create(tree, tctx, &io);
599 31 : if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
600 19 : invalid_parameter_mask |= 1<<i;
601 12 : } else if (NT_STATUS_IS_OK(status)) {
602 : uint32_t expected;
603 12 : ok_mask |= 1<<i;
604 :
605 12 : expected = (io.in.file_attributes | FILE_ATTRIBUTE_ARCHIVE) & 0x00005127;
606 12 : io.out.file_attr &= ~FILE_ATTRIBUTE_NONINDEXED;
607 12 : CHECK_EQUAL(io.out.file_attr, expected);
608 12 : file_attributes_set |= io.out.file_attr;
609 :
610 12 : status = smb2_util_close(tree, io.out.file.handle);
611 12 : CHECK_STATUS(status, NT_STATUS_OK);
612 : } else {
613 0 : unexpected_mask |= 1<<i;
614 0 : torture_comment(tctx,
615 : "file attribute 0x%08x returned %s\n",
616 : 1<<i, nt_errstr(status));
617 : }
618 : }
619 : }
620 :
621 1 : CHECK_EQUAL(ok_mask, 0x00003fb7);
622 1 : CHECK_EQUAL(invalid_parameter_mask, 0xffff8048);
623 1 : CHECK_EQUAL(unexpected_mask, 0x00000000);
624 1 : CHECK_EQUAL(file_attributes_set, 0x00001127);
625 :
626 1 : smb2_deltree(tree, FNAME);
627 :
628 : /*
629 : * Standalone servers doesn't support encryption
630 : */
631 1 : io.in.file_attributes = FILE_ATTRIBUTE_ENCRYPTED;
632 1 : status = smb2_create(tree, tctx, &io);
633 1 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
634 1 : torture_comment(tctx,
635 : "FILE_ATTRIBUTE_ENCRYPTED returned %s\n",
636 : nt_errstr(status));
637 : } else {
638 0 : CHECK_STATUS(status, NT_STATUS_OK);
639 0 : CHECK_EQUAL(io.out.file_attr, (FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_ARCHIVE));
640 0 : status = smb2_util_close(tree, io.out.file.handle);
641 0 : CHECK_STATUS(status, NT_STATUS_OK);
642 : }
643 :
644 1 : smb2_deltree(tree, FNAME);
645 :
646 1 : ZERO_STRUCT(io);
647 1 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
648 1 : io.in.file_attributes = 0;
649 1 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
650 1 : io.in.share_access =
651 : NTCREATEX_SHARE_ACCESS_READ|
652 : NTCREATEX_SHARE_ACCESS_WRITE;
653 1 : io.in.create_options = 0;
654 1 : io.in.fname = FNAME ":stream1";
655 1 : status = smb2_create(tree, tctx, &io);
656 1 : CHECK_STATUS(status, NT_STATUS_OK);
657 :
658 1 : status = smb2_util_close(tree, io.out.file.handle);
659 1 : CHECK_STATUS(status, NT_STATUS_OK);
660 :
661 1 : io.in.fname = FNAME;
662 1 : io.in.file_attributes = 0x8040;
663 1 : io.in.share_access =
664 : NTCREATEX_SHARE_ACCESS_READ;
665 1 : status = smb2_create(tree, tctx, &io);
666 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
667 :
668 1 : io.in.fname = FNAME;
669 1 : io.in.file_attributes = 0;
670 1 : io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
671 1 : io.in.query_maximal_access = true;
672 1 : status = smb2_create(tree, tctx, &io);
673 1 : CHECK_STATUS(status, NT_STATUS_OK);
674 1 : CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
675 :
676 1 : q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
677 1 : q.access_information.in.file.handle = io.out.file.handle;
678 1 : status = smb2_getinfo_file(tree, tctx, &q);
679 1 : CHECK_STATUS(status, NT_STATUS_OK);
680 1 : CHECK_EQUAL(q.access_information.out.access_flags, io.in.desired_access);
681 :
682 1 : io.in.file_attributes = 0;
683 1 : io.in.desired_access = 0;
684 1 : io.in.query_maximal_access = false;
685 1 : io.in.share_access = 0;
686 1 : status = smb2_create(tree, tctx, &io);
687 1 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
688 :
689 1 : smb2_deltree(tree, FNAME);
690 :
691 1 : return true;
692 : }
693 :
694 :
695 : /*
696 : try the various request blobs
697 : */
698 2 : static bool test_create_blob(struct torture_context *tctx, struct smb2_tree *tree)
699 : {
700 : struct smb2_create io;
701 : NTSTATUS status;
702 :
703 2 : smb2_deltree(tree, FNAME);
704 :
705 2 : ZERO_STRUCT(io);
706 2 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
707 2 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
708 2 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
709 2 : io.in.share_access =
710 : NTCREATEX_SHARE_ACCESS_DELETE|
711 : NTCREATEX_SHARE_ACCESS_READ|
712 : NTCREATEX_SHARE_ACCESS_WRITE;
713 2 : io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
714 : NTCREATEX_OPTIONS_ASYNC_ALERT |
715 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
716 : 0x00200000;
717 2 : io.in.fname = FNAME;
718 :
719 2 : status = smb2_create(tree, tctx, &io);
720 2 : CHECK_STATUS(status, NT_STATUS_OK);
721 :
722 2 : status = smb2_util_close(tree, io.out.file.handle);
723 2 : CHECK_STATUS(status, NT_STATUS_OK);
724 :
725 2 : torture_comment(tctx, "Testing alloc size\n");
726 : /* FIXME We use 1M cause that's the rounded size of Samba.
727 : * We should ask the server for the cluser size and calulate it
728 : * correctly. */
729 2 : io.in.alloc_size = 0x00100000;
730 2 : status = smb2_create(tree, tctx, &io);
731 2 : CHECK_STATUS(status, NT_STATUS_OK);
732 2 : CHECK_EQUAL(io.out.alloc_size, io.in.alloc_size);
733 :
734 2 : status = smb2_util_close(tree, io.out.file.handle);
735 2 : CHECK_STATUS(status, NT_STATUS_OK);
736 :
737 2 : torture_comment(tctx, "Testing durable open\n");
738 2 : io.in.durable_open = true;
739 2 : status = smb2_create(tree, tctx, &io);
740 2 : CHECK_STATUS(status, NT_STATUS_OK);
741 :
742 2 : status = smb2_util_close(tree, io.out.file.handle);
743 2 : CHECK_STATUS(status, NT_STATUS_OK);
744 :
745 2 : torture_comment(tctx, "Testing query maximal access\n");
746 2 : io.in.query_maximal_access = true;
747 2 : status = smb2_create(tree, tctx, &io);
748 2 : CHECK_STATUS(status, NT_STATUS_OK);
749 2 : CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
750 :
751 2 : status = smb2_util_close(tree, io.out.file.handle);
752 2 : CHECK_STATUS(status, NT_STATUS_OK);
753 :
754 2 : torture_comment(tctx, "Testing timewarp\n");
755 2 : io.in.timewarp = 10000;
756 2 : status = smb2_create(tree, tctx, &io);
757 2 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
758 1 : io.in.timewarp = 0;
759 :
760 1 : torture_comment(tctx, "Testing query_on_disk\n");
761 1 : io.in.query_on_disk_id = true;
762 1 : status = smb2_create(tree, tctx, &io);
763 1 : CHECK_STATUS(status, NT_STATUS_OK);
764 :
765 1 : status = smb2_util_close(tree, io.out.file.handle);
766 1 : CHECK_STATUS(status, NT_STATUS_OK);
767 :
768 1 : torture_comment(tctx, "Testing unknown tag\n");
769 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
770 : "FooO", data_blob(NULL, 0));
771 1 : CHECK_STATUS(status, NT_STATUS_OK);
772 :
773 1 : status = smb2_create(tree, tctx, &io);
774 1 : CHECK_STATUS(status, NT_STATUS_OK);
775 :
776 1 : status = smb2_util_close(tree, io.out.file.handle);
777 1 : CHECK_STATUS(status, NT_STATUS_OK);
778 :
779 1 : torture_comment(tctx, "Testing bad tag length 0\n");
780 1 : ZERO_STRUCT(io.in.blobs);
781 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
782 : "x", data_blob(NULL, 0));
783 1 : CHECK_STATUS(status, NT_STATUS_OK);
784 1 : status = smb2_create(tree, tctx, &io);
785 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
786 :
787 1 : torture_comment(tctx, "Testing bad tag length 1\n");
788 1 : ZERO_STRUCT(io.in.blobs);
789 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
790 : "x", data_blob(NULL, 0));
791 1 : CHECK_STATUS(status, NT_STATUS_OK);
792 1 : status = smb2_create(tree, tctx, &io);
793 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
794 :
795 1 : torture_comment(tctx, "Testing bad tag length 2\n");
796 1 : ZERO_STRUCT(io.in.blobs);
797 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
798 : "xx", data_blob(NULL, 0));
799 1 : CHECK_STATUS(status, NT_STATUS_OK);
800 1 : status = smb2_create(tree, tctx, &io);
801 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
802 :
803 1 : torture_comment(tctx, "Testing bad tag length 3\n");
804 1 : ZERO_STRUCT(io.in.blobs);
805 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
806 : "xxx", data_blob(NULL, 0));
807 1 : CHECK_STATUS(status, NT_STATUS_OK);
808 1 : status = smb2_create(tree, tctx, &io);
809 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
810 :
811 1 : torture_comment(tctx, "Testing tag length 4\n");
812 1 : ZERO_STRUCT(io.in.blobs);
813 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
814 : "xxxx", data_blob(NULL, 0));
815 1 : CHECK_STATUS(status, NT_STATUS_OK);
816 1 : status = smb2_create(tree, tctx, &io);
817 1 : CHECK_STATUS(status, NT_STATUS_OK);
818 :
819 1 : torture_comment(tctx, "Testing tag length 5\n");
820 1 : ZERO_STRUCT(io.in.blobs);
821 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
822 : "xxxxx", data_blob(NULL, 0));
823 1 : CHECK_STATUS(status, NT_STATUS_OK);
824 1 : status = smb2_create(tree, tctx, &io);
825 1 : CHECK_STATUS(status, NT_STATUS_OK);
826 :
827 1 : torture_comment(tctx, "Testing tag length 6\n");
828 1 : ZERO_STRUCT(io.in.blobs);
829 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
830 : "xxxxxx", data_blob(NULL, 0));
831 1 : CHECK_STATUS(status, NT_STATUS_OK);
832 1 : status = smb2_create(tree, tctx, &io);
833 1 : CHECK_STATUS(status, NT_STATUS_OK);
834 :
835 1 : torture_comment(tctx, "Testing tag length 7\n");
836 1 : ZERO_STRUCT(io.in.blobs);
837 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
838 : "xxxxxxx", data_blob(NULL, 0));
839 1 : CHECK_STATUS(status, NT_STATUS_OK);
840 1 : status = smb2_create(tree, tctx, &io);
841 1 : CHECK_STATUS(status, NT_STATUS_OK);
842 :
843 1 : torture_comment(tctx, "Testing tag length 8\n");
844 1 : ZERO_STRUCT(io.in.blobs);
845 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
846 : "xxxxxxxx", data_blob(NULL, 0));
847 1 : CHECK_STATUS(status, NT_STATUS_OK);
848 1 : status = smb2_create(tree, tctx, &io);
849 1 : CHECK_STATUS(status, NT_STATUS_OK);
850 :
851 1 : torture_comment(tctx, "Testing tag length 16\n");
852 1 : ZERO_STRUCT(io.in.blobs);
853 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
854 : "xxxxxxxxxxxxxxxx", data_blob(NULL, 0));
855 1 : CHECK_STATUS(status, NT_STATUS_OK);
856 1 : status = smb2_create(tree, tctx, &io);
857 1 : CHECK_STATUS(status, NT_STATUS_OK);
858 :
859 1 : torture_comment(tctx, "Testing tag length 17\n");
860 1 : ZERO_STRUCT(io.in.blobs);
861 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
862 : "xxxxxxxxxxxxxxxxx", data_blob(NULL, 0));
863 1 : CHECK_STATUS(status, NT_STATUS_OK);
864 1 : status = smb2_create(tree, tctx, &io);
865 1 : CHECK_STATUS(status, NT_STATUS_OK);
866 :
867 1 : torture_comment(tctx, "Testing tag length 34\n");
868 1 : ZERO_STRUCT(io.in.blobs);
869 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
870 : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
871 : data_blob(NULL, 0));
872 1 : CHECK_STATUS(status, NT_STATUS_OK);
873 1 : status = smb2_create(tree, tctx, &io);
874 1 : CHECK_STATUS(status, NT_STATUS_OK);
875 :
876 1 : smb2_deltree(tree, FNAME);
877 :
878 1 : return true;
879 : }
880 :
881 : #define FAIL_UNLESS(__cond) \
882 : do { \
883 : if (__cond) {} else { \
884 : torture_result(tctx, TORTURE_FAIL, "%s) condition violated: %s\n", \
885 : __location__, #__cond); \
886 : ret = false; goto done; \
887 : } \
888 : } while(0)
889 :
890 : /*
891 : try creating with acls
892 : */
893 4 : static bool test_create_acl_ext(struct torture_context *tctx, struct smb2_tree *tree, bool test_dir)
894 : {
895 4 : bool ret = true;
896 : struct smb2_create io;
897 : NTSTATUS status;
898 : struct security_ace ace;
899 : struct security_descriptor *sd;
900 : struct dom_sid *test_sid;
901 4 : union smb_fileinfo q = {};
902 4 : uint32_t attrib =
903 : FILE_ATTRIBUTE_HIDDEN |
904 : FILE_ATTRIBUTE_SYSTEM |
905 : (test_dir ? FILE_ATTRIBUTE_DIRECTORY : 0);
906 4 : NTSTATUS (*delete_func)(struct smb2_tree *, const char *) =
907 4 : test_dir ? smb2_util_rmdir : smb2_util_unlink;
908 :
909 4 : ZERO_STRUCT(ace);
910 :
911 4 : smb2_deltree(tree, FNAME);
912 :
913 4 : ZERO_STRUCT(io);
914 4 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
915 4 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
916 4 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
917 4 : io.in.share_access =
918 : NTCREATEX_SHARE_ACCESS_DELETE |
919 : NTCREATEX_SHARE_ACCESS_READ |
920 : NTCREATEX_SHARE_ACCESS_WRITE;
921 4 : io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT | 0x00200000 |
922 : (test_dir ? NTCREATEX_OPTIONS_DIRECTORY :
923 : (NTCREATEX_OPTIONS_NON_DIRECTORY_FILE));
924 :
925 4 : io.in.fname = FNAME;
926 :
927 4 : torture_comment(tctx, "basic create\n");
928 :
929 4 : status = smb2_create(tree, tctx, &io);
930 4 : CHECK_STATUS(status, NT_STATUS_OK);
931 :
932 4 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
933 4 : q.query_secdesc.in.file.handle = io.out.file.handle;
934 4 : q.query_secdesc.in.secinfo_flags =
935 : SECINFO_OWNER |
936 : SECINFO_GROUP |
937 : SECINFO_DACL;
938 4 : status = smb2_getinfo_file(tree, tctx, &q);
939 4 : CHECK_STATUS(status, NT_STATUS_OK);
940 4 : sd = q.query_secdesc.out.sd;
941 :
942 4 : status = smb2_util_close(tree, io.out.file.handle);
943 4 : CHECK_STATUS(status, NT_STATUS_OK);
944 4 : status = delete_func(tree, FNAME);
945 4 : CHECK_STATUS(status, NT_STATUS_OK);
946 :
947 4 : torture_comment(tctx, "adding a new ACE\n");
948 4 : test_sid = dom_sid_parse_talloc(tctx, SID_NT_AUTHENTICATED_USERS);
949 :
950 4 : ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
951 4 : ace.flags = 0;
952 4 : ace.access_mask = SEC_STD_ALL;
953 4 : ace.trustee = *test_sid;
954 :
955 4 : status = security_descriptor_dacl_add(sd, &ace);
956 4 : CHECK_STATUS(status, NT_STATUS_OK);
957 :
958 4 : torture_comment(tctx, "creating a file with an initial ACL\n");
959 :
960 4 : io.in.sec_desc = sd;
961 4 : status = smb2_create(tree, tctx, &io);
962 4 : CHECK_STATUS(status, NT_STATUS_OK);
963 :
964 4 : FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));
965 :
966 4 : status = smb2_util_close(tree, io.out.file.handle);
967 4 : CHECK_STATUS(status, NT_STATUS_OK);
968 4 : status = delete_func(tree, FNAME);
969 4 : CHECK_STATUS(status, NT_STATUS_OK);
970 :
971 4 : torture_comment(tctx, "creating with attributes\n");
972 :
973 4 : io.in.sec_desc = NULL;
974 4 : io.in.file_attributes = attrib;
975 4 : status = smb2_create(tree, tctx, &io);
976 4 : CHECK_STATUS(status, NT_STATUS_OK);
977 :
978 4 : FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));
979 :
980 3 : status = smb2_util_close(tree, io.out.file.handle);
981 3 : CHECK_STATUS(status, NT_STATUS_OK);
982 3 : status = delete_func(tree, FNAME);
983 3 : CHECK_STATUS(status, NT_STATUS_OK);
984 :
985 3 : torture_comment(tctx, "creating with attributes and ACL\n");
986 :
987 3 : io.in.sec_desc = sd;
988 3 : io.in.file_attributes = attrib;
989 3 : status = smb2_create(tree, tctx, &io);
990 3 : CHECK_STATUS(status, NT_STATUS_OK);
991 :
992 3 : FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));
993 3 : FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));
994 :
995 3 : status = smb2_util_close(tree, io.out.file.handle);
996 3 : CHECK_STATUS(status, NT_STATUS_OK);
997 3 : status = delete_func(tree, FNAME);
998 3 : CHECK_STATUS(status, NT_STATUS_OK);
999 :
1000 3 : torture_comment(tctx, "creating with attributes, ACL and owner\n");
1001 3 : sd = security_descriptor_dacl_create(tctx,
1002 : 0, SID_WORLD, SID_BUILTIN_USERS,
1003 : SID_WORLD,
1004 : SEC_ACE_TYPE_ACCESS_ALLOWED,
1005 : SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
1006 : 0,
1007 : NULL);
1008 :
1009 3 : io.in.sec_desc = sd;
1010 3 : io.in.file_attributes = attrib;
1011 3 : status = smb2_create(tree, tctx, &io);
1012 3 : CHECK_STATUS(status, NT_STATUS_OK);
1013 :
1014 3 : FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));
1015 3 : FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));
1016 :
1017 4 : done:
1018 4 : status = smb2_util_close(tree, io.out.file.handle);
1019 4 : CHECK_STATUS(status, NT_STATUS_OK);
1020 4 : status = delete_func(tree, FNAME);
1021 4 : CHECK_STATUS(status, NT_STATUS_OK);
1022 :
1023 4 : return ret;
1024 : }
1025 :
1026 : /*
1027 : test SMB2 open
1028 : */
1029 2 : static bool test_smb2_open(struct torture_context *tctx,
1030 : struct smb2_tree *tree)
1031 : {
1032 : union smb_open io;
1033 : union smb_fileinfo finfo;
1034 2 : const char *fname = DNAME "\\torture_ntcreatex.txt";
1035 2 : const char *dname = DNAME "\\torture_ntcreatex.dir";
1036 : NTSTATUS status;
1037 2 : struct smb2_handle h = {{0}};
1038 2 : struct smb2_handle h1 = {{0}};
1039 2 : bool ret = true;
1040 : size_t i;
1041 : struct {
1042 : uint32_t create_disp;
1043 : bool with_file;
1044 : NTSTATUS correct_status;
1045 2 : } open_funcs[] = {
1046 : { NTCREATEX_DISP_SUPERSEDE, true, NT_STATUS_OK },
1047 : { NTCREATEX_DISP_SUPERSEDE, false, NT_STATUS_OK },
1048 : { NTCREATEX_DISP_OPEN, true, NT_STATUS_OK },
1049 : { NTCREATEX_DISP_OPEN, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
1050 : { NTCREATEX_DISP_CREATE, true, NT_STATUS_OBJECT_NAME_COLLISION },
1051 : { NTCREATEX_DISP_CREATE, false, NT_STATUS_OK },
1052 : { NTCREATEX_DISP_OPEN_IF, true, NT_STATUS_OK },
1053 : { NTCREATEX_DISP_OPEN_IF, false, NT_STATUS_OK },
1054 : { NTCREATEX_DISP_OVERWRITE, true, NT_STATUS_OK },
1055 : { NTCREATEX_DISP_OVERWRITE, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
1056 : { NTCREATEX_DISP_OVERWRITE_IF, true, NT_STATUS_OK },
1057 : { NTCREATEX_DISP_OVERWRITE_IF, false, NT_STATUS_OK },
1058 : { 6, true, NT_STATUS_INVALID_PARAMETER },
1059 : { 6, false, NT_STATUS_INVALID_PARAMETER },
1060 : };
1061 :
1062 2 : torture_comment(tctx, "Checking SMB2 Open\n");
1063 :
1064 2 : smb2_util_unlink(tree, fname);
1065 2 : smb2_util_rmdir(tree, dname);
1066 :
1067 2 : status = torture_smb2_testdir(tree, DNAME, &h);
1068 2 : CHECK_STATUS(status, NT_STATUS_OK);
1069 :
1070 2 : ZERO_STRUCT(io.smb2);
1071 : /* reasonable default parameters */
1072 2 : io.generic.level = RAW_OPEN_SMB2;
1073 2 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1074 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1075 2 : io.smb2.in.alloc_size = 1024*1024;
1076 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1077 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1078 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1079 2 : io.smb2.in.create_options = 0;
1080 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1081 2 : io.smb2.in.security_flags = 0;
1082 2 : io.smb2.in.fname = fname;
1083 :
1084 : /* test the create disposition */
1085 30 : for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
1086 28 : if (open_funcs[i].with_file) {
1087 14 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1088 14 : status= smb2_create(tree, tctx, &(io.smb2));
1089 14 : if (!NT_STATUS_IS_OK(status)) {
1090 0 : torture_comment(tctx,
1091 : "Failed to create file %s status %s %zu\n",
1092 : fname, nt_errstr(status), i);
1093 :
1094 0 : ret = false;
1095 0 : goto done;
1096 : }
1097 14 : smb2_util_close(tree, io.smb2.out.file.handle);
1098 : }
1099 28 : io.smb2.in.create_disposition = open_funcs[i].create_disp;
1100 28 : status = smb2_create(tree, tctx, &(io.smb2));
1101 28 : if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
1102 0 : torture_comment(tctx,
1103 : "(%s) incorrect status %s should be %s (i=%zu "
1104 : "with_file=%d open_disp=%d)\n",
1105 : __location__, nt_errstr(status),
1106 : nt_errstr(open_funcs[i].correct_status),
1107 0 : i, (int)open_funcs[i].with_file,
1108 0 : (int)open_funcs[i].create_disp);
1109 :
1110 0 : ret = false;
1111 0 : goto done;
1112 : }
1113 28 : if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
1114 22 : smb2_util_close(tree, io.smb2.out.file.handle);
1115 22 : smb2_util_unlink(tree, fname);
1116 : }
1117 : }
1118 :
1119 : /* basic field testing */
1120 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1121 :
1122 2 : status = smb2_create(tree, tctx, &(io.smb2));
1123 2 : CHECK_STATUS(status, NT_STATUS_OK);
1124 2 : h1 = io.smb2.out.file.handle;
1125 :
1126 2 : CHECK_VAL(io.smb2.out.oplock_level, 0);
1127 2 : CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
1128 2 : CHECK_NTTIME(io.smb2.out.create_time, create_time);
1129 2 : CHECK_NTTIME(io.smb2.out.access_time, access_time);
1130 2 : CHECK_NTTIME(io.smb2.out.write_time, write_time);
1131 2 : CHECK_NTTIME(io.smb2.out.change_time, change_time);
1132 2 : CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
1133 2 : CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
1134 2 : CHECK_ALL_INFO(io.smb2.out.size, size);
1135 :
1136 : /* check fields when the file already existed */
1137 2 : smb2_util_close(tree, h1);
1138 2 : smb2_util_unlink(tree, fname);
1139 :
1140 2 : status = smb2_create_complex_file(tctx, tree, fname, &h1);
1141 2 : CHECK_STATUS(status, NT_STATUS_OK);
1142 :
1143 1 : smb2_util_close(tree, h1);
1144 :
1145 1 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1146 1 : status = smb2_create(tree, tctx, &(io.smb2));
1147 1 : CHECK_STATUS(status, NT_STATUS_OK);
1148 1 : h1 = io.smb2.out.file.handle;
1149 :
1150 1 : CHECK_VAL(io.smb2.out.oplock_level, 0);
1151 1 : CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_EXISTED);
1152 1 : CHECK_NTTIME(io.smb2.out.create_time, create_time);
1153 1 : CHECK_NTTIME(io.smb2.out.access_time, access_time);
1154 1 : CHECK_NTTIME(io.smb2.out.write_time, write_time);
1155 1 : CHECK_NTTIME(io.smb2.out.change_time, change_time);
1156 1 : CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
1157 1 : CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
1158 1 : CHECK_ALL_INFO(io.smb2.out.size, size);
1159 1 : smb2_util_close(tree, h1);
1160 1 : smb2_util_unlink(tree, fname);
1161 :
1162 : /* create a directory */
1163 1 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1164 1 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1165 1 : io.smb2.in.alloc_size = 0;
1166 1 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1167 1 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1168 1 : io.smb2.in.create_options = 0;
1169 1 : io.smb2.in.fname = dname;
1170 1 : fname = dname;
1171 :
1172 1 : smb2_util_rmdir(tree, fname);
1173 1 : smb2_util_unlink(tree, fname);
1174 :
1175 1 : io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1176 1 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1177 1 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1178 1 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1179 : NTCREATEX_SHARE_ACCESS_WRITE;
1180 1 : status = smb2_create(tree, tctx, &(io.smb2));
1181 1 : CHECK_STATUS(status, NT_STATUS_OK);
1182 1 : h1 = io.smb2.out.file.handle;
1183 :
1184 1 : CHECK_VAL(io.smb2.out.oplock_level, 0);
1185 1 : CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
1186 1 : CHECK_NTTIME(io.smb2.out.create_time, create_time);
1187 1 : CHECK_NTTIME(io.smb2.out.access_time, access_time);
1188 1 : CHECK_NTTIME(io.smb2.out.write_time, write_time);
1189 1 : CHECK_NTTIME(io.smb2.out.change_time, change_time);
1190 1 : CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
1191 1 : CHECK_VAL(io.smb2.out.file_attr & ~FILE_ATTRIBUTE_NONINDEXED,
1192 : FILE_ATTRIBUTE_DIRECTORY);
1193 1 : CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
1194 1 : CHECK_ALL_INFO(io.smb2.out.size, size);
1195 1 : CHECK_VAL(io.smb2.out.size, 0);
1196 1 : smb2_util_unlink(tree, fname);
1197 :
1198 1 : done:
1199 1 : smb2_util_close(tree, h1);
1200 1 : smb2_util_unlink(tree, fname);
1201 1 : smb2_deltree(tree, DNAME);
1202 1 : return ret;
1203 : }
1204 :
1205 : /*
1206 : test with an already opened and byte range locked file
1207 : */
1208 :
1209 2 : static bool test_smb2_open_brlocked(struct torture_context *tctx,
1210 : struct smb2_tree *tree)
1211 : {
1212 : union smb_open io, io1;
1213 : union smb_lock io2;
1214 : struct smb2_lock_element lock[1];
1215 2 : const char *fname = DNAME "\\torture_ntcreatex.txt";
1216 : NTSTATUS status;
1217 2 : bool ret = true;
1218 : struct smb2_handle h;
1219 2 : char b = 42;
1220 :
1221 2 : torture_comment(tctx,
1222 : "Testing SMB2 open with a byte range locked file\n");
1223 :
1224 2 : smb2_util_unlink(tree, fname);
1225 :
1226 2 : status = torture_smb2_testdir(tree, DNAME, &h);
1227 2 : CHECK_STATUS(status, NT_STATUS_OK);
1228 :
1229 2 : ZERO_STRUCT(io.smb2);
1230 2 : io.generic.level = RAW_OPEN_SMB2;
1231 2 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1232 2 : io.smb2.in.desired_access = 0x2019f;
1233 2 : io.smb2.in.alloc_size = 0;
1234 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1235 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1236 : NTCREATEX_SHARE_ACCESS_WRITE;
1237 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1238 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1239 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1240 2 : io.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
1241 2 : io.smb2.in.fname = fname;
1242 :
1243 2 : status = smb2_create(tree, tctx, &(io.smb2));
1244 2 : CHECK_STATUS(status, NT_STATUS_OK);
1245 :
1246 2 : status = smb2_util_write(tree, io.smb2.out.file.handle, &b, 0, 1);
1247 2 : CHECK_STATUS(status, NT_STATUS_OK);
1248 :
1249 2 : ZERO_STRUCT(io2.smb2);
1250 2 : io2.smb2.level = RAW_LOCK_SMB2;
1251 2 : io2.smb2.in.file.handle = io.smb2.out.file.handle;
1252 2 : io2.smb2.in.lock_count = 1;
1253 :
1254 2 : ZERO_STRUCT(lock);
1255 2 : lock[0].offset = 0;
1256 2 : lock[0].length = 1;
1257 2 : lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1258 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1259 2 : io2.smb2.in.locks = &lock[0];
1260 2 : status = smb2_lock(tree, &(io2.smb2));
1261 2 : CHECK_STATUS(status, NT_STATUS_OK);
1262 :
1263 2 : ZERO_STRUCT(io1.smb2);
1264 2 : io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1265 2 : io1.smb2.in.desired_access = 0x20196;
1266 2 : io1.smb2.in.alloc_size = 0;
1267 2 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1268 2 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1269 : NTCREATEX_SHARE_ACCESS_WRITE;
1270 2 : io1.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1271 2 : io1.smb2.in.create_options = 0;
1272 2 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1273 2 : io1.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
1274 2 : io1.smb2.in.fname = fname;
1275 :
1276 2 : status = smb2_create(tree, tctx, &(io1.smb2));
1277 2 : CHECK_STATUS(status, NT_STATUS_OK);
1278 :
1279 2 : smb2_util_close(tree, io.smb2.out.file.handle);
1280 2 : smb2_util_close(tree, io1.smb2.out.file.handle);
1281 2 : smb2_util_unlink(tree, fname);
1282 2 : smb2_deltree(tree, DNAME);
1283 :
1284 2 : return ret;
1285 : }
1286 :
1287 : /* A little torture test to expose a race condition in Samba 3.0.20 ... :-) */
1288 :
1289 2 : static bool test_smb2_open_multi(struct torture_context *tctx,
1290 : struct smb2_tree *tree)
1291 : {
1292 2 : const char *fname = "test_oplock.dat";
1293 : NTSTATUS status;
1294 2 : bool ret = true;
1295 : union smb_open io;
1296 : struct smb2_tree **trees;
1297 : struct smb2_request **requests;
1298 : union smb_open *ios;
1299 2 : int i, num_files = 3;
1300 2 : int num_ok = 0;
1301 2 : int num_collision = 0;
1302 :
1303 2 : torture_comment(tctx,
1304 : "Testing SMB2 Open with multiple connections\n");
1305 2 : trees = talloc_array(tctx, struct smb2_tree *, num_files);
1306 2 : requests = talloc_array(tctx, struct smb2_request *, num_files);
1307 2 : ios = talloc_array(tctx, union smb_open, num_files);
1308 2 : if ((tctx->ev == NULL) || (trees == NULL) || (requests == NULL) ||
1309 : (ios == NULL)) {
1310 0 : torture_comment(tctx, ("talloc failed\n"));
1311 0 : ret = false;
1312 0 : goto done;
1313 : }
1314 :
1315 2 : tree->session->transport->options.request_timeout = 60;
1316 :
1317 8 : for (i=0; i<num_files; i++) {
1318 6 : if (!torture_smb2_connection(tctx, &(trees[i]))) {
1319 0 : torture_comment(tctx,
1320 : "Could not open %d'th connection\n", i);
1321 0 : ret = false;
1322 0 : goto done;
1323 : }
1324 6 : trees[i]->session->transport->options.request_timeout = 60;
1325 : }
1326 :
1327 : /* cleanup */
1328 2 : smb2_util_unlink(tree, fname);
1329 :
1330 : /*
1331 : base ntcreatex parms
1332 : */
1333 2 : ZERO_STRUCT(io.smb2);
1334 2 : io.generic.level = RAW_OPEN_SMB2;
1335 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1336 2 : io.smb2.in.alloc_size = 0;
1337 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1338 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1339 : NTCREATEX_SHARE_ACCESS_WRITE|
1340 : NTCREATEX_SHARE_ACCESS_DELETE;
1341 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1342 2 : io.smb2.in.create_options = 0;
1343 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1344 2 : io.smb2.in.security_flags = 0;
1345 2 : io.smb2.in.fname = fname;
1346 2 : io.smb2.in.create_flags = 0;
1347 :
1348 8 : for (i=0; i<num_files; i++) {
1349 6 : ios[i] = io;
1350 6 : requests[i] = smb2_create_send(trees[i], &(ios[i].smb2));
1351 6 : if (requests[i] == NULL) {
1352 0 : torture_comment(tctx,
1353 : "could not send %d'th request\n", i);
1354 0 : ret = false;
1355 0 : goto done;
1356 : }
1357 : }
1358 :
1359 2 : torture_comment(tctx, "waiting for replies\n");
1360 24 : while (1) {
1361 26 : bool unreplied = false;
1362 43 : for (i=0; i<num_files; i++) {
1363 41 : if (requests[i] == NULL) {
1364 11 : continue;
1365 : }
1366 30 : if (requests[i]->state < SMB2_REQUEST_DONE) {
1367 24 : unreplied = true;
1368 24 : break;
1369 : }
1370 6 : status = smb2_create_recv(requests[i], tctx,
1371 6 : &(ios[i].smb2));
1372 :
1373 6 : torture_comment(tctx,
1374 : "File %d returned status %s\n", i,
1375 : nt_errstr(status));
1376 :
1377 6 : if (NT_STATUS_IS_OK(status)) {
1378 2 : num_ok += 1;
1379 : }
1380 :
1381 6 : if (NT_STATUS_EQUAL(status,
1382 : NT_STATUS_OBJECT_NAME_COLLISION)) {
1383 4 : num_collision += 1;
1384 : }
1385 :
1386 6 : requests[i] = NULL;
1387 : }
1388 26 : if (!unreplied) {
1389 2 : break;
1390 : }
1391 :
1392 24 : if (tevent_loop_once(tctx->ev) != 0) {
1393 0 : torture_comment(tctx, "tevent_loop_once failed\n");
1394 0 : ret = false;
1395 0 : goto done;
1396 : }
1397 : }
1398 :
1399 2 : if ((num_ok != 1) || (num_ok + num_collision != num_files)) {
1400 0 : ret = false;
1401 : }
1402 2 : done:
1403 2 : smb2_deltree(tree, fname);
1404 :
1405 2 : return ret;
1406 : }
1407 :
1408 : /*
1409 : test opening for delete on a read-only attribute file.
1410 : */
1411 :
1412 2 : static bool test_smb2_open_for_delete(struct torture_context *tctx,
1413 : struct smb2_tree *tree)
1414 : {
1415 : union smb_open io;
1416 : union smb_fileinfo finfo;
1417 2 : const char *fname = DNAME "\\torture_open_for_delete.txt";
1418 : NTSTATUS status;
1419 : struct smb2_handle h, h1;
1420 2 : bool ret = true;
1421 :
1422 2 : torture_comment(tctx,
1423 : "Checking SMB2_OPEN for delete on a readonly file.\n");
1424 2 : smb2_util_unlink(tree, fname);
1425 2 : smb2_deltree(tree, fname);
1426 :
1427 2 : status = torture_smb2_testdir(tree, DNAME, &h);
1428 2 : CHECK_STATUS(status, NT_STATUS_OK);
1429 :
1430 : /* reasonable default parameters */
1431 2 : ZERO_STRUCT(io.smb2);
1432 2 : io.generic.level = RAW_OPEN_SMB2;
1433 2 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1434 2 : io.smb2.in.alloc_size = 0;
1435 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1436 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_READONLY;
1437 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1438 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1439 2 : io.smb2.in.create_options = 0;
1440 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1441 2 : io.smb2.in.security_flags = 0;
1442 2 : io.smb2.in.fname = fname;
1443 :
1444 : /* Create the readonly file. */
1445 :
1446 2 : status = smb2_create(tree, tctx, &(io.smb2));
1447 2 : CHECK_STATUS(status, NT_STATUS_OK);
1448 2 : h1 = io.smb2.out.file.handle;
1449 :
1450 2 : CHECK_VAL(io.smb2.out.oplock_level, 0);
1451 2 : io.smb2.in.create_options = 0;
1452 2 : CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
1453 2 : CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
1454 2 : smb2_util_close(tree, h1);
1455 :
1456 : /* Now try and open for delete only - should succeed. */
1457 2 : io.smb2.in.desired_access = SEC_STD_DELETE;
1458 2 : io.smb2.in.file_attributes = 0;
1459 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1460 : NTCREATEX_SHARE_ACCESS_WRITE |
1461 : NTCREATEX_SHARE_ACCESS_DELETE;
1462 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1463 2 : status = smb2_create(tree, tctx, &(io.smb2));
1464 2 : CHECK_STATUS(status, NT_STATUS_OK);
1465 2 : smb2_util_close(tree, io.smb2.out.file.handle);
1466 :
1467 : /* Clear readonly flag to allow file deletion */
1468 2 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1469 : SEC_FILE_WRITE_ATTRIBUTE;
1470 2 : status = smb2_create(tree, tctx, &(io.smb2));
1471 2 : CHECK_STATUS(status, NT_STATUS_OK);
1472 2 : h1 = io.smb2.out.file.handle;
1473 2 : SET_ATTRIB(FILE_ATTRIBUTE_ARCHIVE);
1474 2 : smb2_util_close(tree, h1);
1475 :
1476 2 : smb2_util_close(tree, h);
1477 2 : smb2_util_unlink(tree, fname);
1478 2 : smb2_deltree(tree, DNAME);
1479 :
1480 2 : return ret;
1481 : }
1482 :
1483 : /*
1484 : test SMB2 open with a leading slash on the path.
1485 : Trying to create a directory with a leading slash
1486 : should give NT_STATUS_INVALID_PARAMETER error
1487 : */
1488 2 : static bool test_smb2_leading_slash(struct torture_context *tctx,
1489 : struct smb2_tree *tree)
1490 : {
1491 : union smb_open io;
1492 2 : const char *dnameslash = "\\"DNAME;
1493 : NTSTATUS status;
1494 2 : bool ret = true;
1495 :
1496 2 : torture_comment(tctx,
1497 : "Trying to create a directory with leading slash on path\n");
1498 2 : smb2_deltree(tree, dnameslash);
1499 :
1500 2 : ZERO_STRUCT(io.smb2);
1501 2 : io.generic.level = RAW_OPEN_SMB2;
1502 2 : io.smb2.in.oplock_level = 0;
1503 2 : io.smb2.in.desired_access = SEC_RIGHTS_DIR_ALL;
1504 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1505 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1506 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1507 : NTCREATEX_SHARE_ACCESS_WRITE |
1508 : NTCREATEX_SHARE_ACCESS_DELETE;
1509 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1510 2 : io.smb2.in.fname = dnameslash;
1511 :
1512 2 : status = smb2_create(tree, tree, &(io.smb2));
1513 2 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1514 :
1515 2 : smb2_deltree(tree, dnameslash);
1516 2 : return ret;
1517 : }
1518 :
1519 : /*
1520 : test SMB2 open with an invalid impersonation level.
1521 : Should give NT_STATUS_BAD_IMPERSONATION_LEVEL error
1522 : */
1523 2 : static bool test_smb2_impersonation_level(struct torture_context *tctx,
1524 : struct smb2_tree *tree)
1525 : {
1526 : union smb_open io;
1527 2 : const char *fname = DNAME "\\torture_invalid_impersonation_level.txt";
1528 : NTSTATUS status;
1529 : struct smb2_handle h;
1530 2 : bool ret = true;
1531 :
1532 2 : torture_comment(tctx,
1533 : "Testing SMB2 open with an invalid impersonation level.\n");
1534 :
1535 2 : smb2_util_unlink(tree, fname);
1536 2 : smb2_util_rmdir(tree, DNAME);
1537 :
1538 2 : status = torture_smb2_testdir(tree, DNAME, &h);
1539 2 : CHECK_STATUS(status, NT_STATUS_OK);
1540 :
1541 2 : ZERO_STRUCT(io.smb2);
1542 2 : io.generic.level = RAW_OPEN_SMB2;
1543 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1544 2 : io.smb2.in.alloc_size = 0;
1545 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1546 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1547 : NTCREATEX_SHARE_ACCESS_WRITE|
1548 : NTCREATEX_SHARE_ACCESS_DELETE;
1549 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1550 2 : io.smb2.in.create_options = 0;
1551 2 : io.smb2.in.impersonation_level = 0x12345678;
1552 2 : io.smb2.in.security_flags = 0;
1553 2 : io.smb2.in.fname = fname;
1554 2 : io.smb2.in.create_flags = 0;
1555 :
1556 2 : status = smb2_create(tree, tree, &(io.smb2));
1557 2 : CHECK_STATUS(status, NT_STATUS_BAD_IMPERSONATION_LEVEL);
1558 :
1559 1 : smb2_util_close(tree, h);
1560 1 : smb2_util_unlink(tree, fname);
1561 1 : smb2_deltree(tree, DNAME);
1562 1 : return ret;
1563 : }
1564 :
1565 2 : static bool test_create_acl_file(struct torture_context *tctx,
1566 : struct smb2_tree *tree)
1567 : {
1568 2 : torture_comment(tctx, "Testing nttrans create with sec_desc on files\n");
1569 :
1570 2 : return test_create_acl_ext(tctx, tree, false);
1571 : }
1572 :
1573 2 : static bool test_create_acl_dir(struct torture_context *tctx,
1574 : struct smb2_tree *tree)
1575 : {
1576 2 : torture_comment(tctx, "Testing nttrans create with sec_desc on directories\n");
1577 :
1578 2 : return test_create_acl_ext(tctx, tree, true);
1579 : }
1580 :
1581 : #define CHECK_ACCESS_FLAGS(_fh, flags) do { \
1582 : union smb_fileinfo _q; \
1583 : _q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; \
1584 : _q.access_information.in.file.handle = (_fh); \
1585 : status = smb2_getinfo_file(tree, tctx, &_q); \
1586 : CHECK_STATUS(status, NT_STATUS_OK); \
1587 : if (_q.access_information.out.access_flags != (flags)) { \
1588 : torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect access_flags 0x%08x - should be 0x%08x\n", \
1589 : __location__, _q.access_information.out.access_flags, (flags)); \
1590 : ret = false; \
1591 : goto done; \
1592 : } \
1593 : } while (0)
1594 :
1595 : /*
1596 : * Test creating a file with a NULL DACL.
1597 : */
1598 2 : static bool test_create_null_dacl(struct torture_context *tctx,
1599 : struct smb2_tree *tree)
1600 : {
1601 : NTSTATUS status;
1602 : struct smb2_create io;
1603 2 : const char *fname = "nulldacl.txt";
1604 2 : bool ret = true;
1605 : struct smb2_handle handle;
1606 : union smb_fileinfo q;
1607 : union smb_setfileinfo s;
1608 2 : struct security_descriptor *sd = security_descriptor_initialise(tctx);
1609 : struct security_acl dacl;
1610 :
1611 2 : torture_comment(tctx, "TESTING SEC_DESC WITH A NULL DACL\n");
1612 :
1613 2 : smb2_util_unlink(tree, fname);
1614 :
1615 2 : ZERO_STRUCT(io);
1616 2 : io.level = RAW_OPEN_SMB2;
1617 2 : io.in.create_flags = 0;
1618 2 : io.in.desired_access = SEC_STD_READ_CONTROL | SEC_STD_WRITE_DAC
1619 : | SEC_STD_WRITE_OWNER;
1620 2 : io.in.create_options = 0;
1621 2 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1622 2 : io.in.share_access =
1623 : NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1624 2 : io.in.alloc_size = 0;
1625 2 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
1626 2 : io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
1627 2 : io.in.security_flags = 0;
1628 2 : io.in.fname = fname;
1629 2 : io.in.sec_desc = sd;
1630 : /* XXX create_options ? */
1631 2 : io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
1632 : NTCREATEX_OPTIONS_ASYNC_ALERT |
1633 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
1634 : 0x00200000;
1635 :
1636 2 : torture_comment(tctx, "creating a file with a empty sd\n");
1637 2 : status = smb2_create(tree, tctx, &io);
1638 2 : CHECK_STATUS(status, NT_STATUS_OK);
1639 2 : handle = io.out.file.handle;
1640 :
1641 2 : torture_comment(tctx, "get the original sd\n");
1642 2 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1643 2 : q.query_secdesc.in.file.handle = handle;
1644 2 : q.query_secdesc.in.secinfo_flags =
1645 : SECINFO_OWNER |
1646 : SECINFO_GROUP |
1647 : SECINFO_DACL;
1648 2 : status = smb2_getinfo_file(tree, tctx, &q);
1649 2 : CHECK_STATUS(status, NT_STATUS_OK);
1650 :
1651 : /*
1652 : * Testing the created DACL,
1653 : * the server should add the inherited DACL
1654 : * when SEC_DESC_DACL_PRESENT isn't specified
1655 : */
1656 2 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1657 0 : ret = false;
1658 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1659 : }
1660 2 : if (q.query_secdesc.out.sd->dacl == NULL) {
1661 0 : ret = false;
1662 0 : torture_fail_goto(tctx, done, "no DACL has been created on the server!\n");
1663 : }
1664 :
1665 2 : torture_comment(tctx, "set NULL DACL\n");
1666 2 : sd->type |= SEC_DESC_DACL_PRESENT;
1667 :
1668 2 : s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
1669 2 : s.set_secdesc.in.file.handle = handle;
1670 2 : s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
1671 2 : s.set_secdesc.in.sd = sd;
1672 2 : status = smb2_setinfo_file(tree, &s);
1673 2 : CHECK_STATUS(status, NT_STATUS_OK);
1674 :
1675 2 : torture_comment(tctx, "get the sd\n");
1676 2 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1677 2 : q.query_secdesc.in.file.handle = handle;
1678 2 : q.query_secdesc.in.secinfo_flags =
1679 : SECINFO_OWNER |
1680 : SECINFO_GROUP |
1681 : SECINFO_DACL;
1682 2 : status = smb2_getinfo_file(tree, tctx, &q);
1683 2 : CHECK_STATUS(status, NT_STATUS_OK);
1684 :
1685 : /* Testing the modified DACL */
1686 2 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1687 0 : ret = false;
1688 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1689 : }
1690 2 : if (q.query_secdesc.out.sd->dacl != NULL) {
1691 0 : ret = false;
1692 0 : torture_fail_goto(tctx, done, "DACL has been created on the server!\n");
1693 : }
1694 :
1695 2 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
1696 :
1697 2 : torture_comment(tctx, "try open for read control\n");
1698 2 : io.in.desired_access = SEC_STD_READ_CONTROL;
1699 2 : status = smb2_create(tree, tctx, &io);
1700 2 : CHECK_STATUS(status, NT_STATUS_OK);
1701 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1702 : SEC_STD_READ_CONTROL);
1703 2 : smb2_util_close(tree, io.out.file.handle);
1704 :
1705 2 : torture_comment(tctx, "try open for write\n");
1706 2 : io.in.desired_access = SEC_FILE_WRITE_DATA;
1707 2 : status = smb2_create(tree, tctx, &io);
1708 2 : CHECK_STATUS(status, NT_STATUS_OK);
1709 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1710 : SEC_FILE_WRITE_DATA);
1711 2 : smb2_util_close(tree, io.out.file.handle);
1712 :
1713 2 : torture_comment(tctx, "try open for read\n");
1714 2 : io.in.desired_access = SEC_FILE_READ_DATA;
1715 2 : status = smb2_create(tree, tctx, &io);
1716 2 : CHECK_STATUS(status, NT_STATUS_OK);
1717 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1718 : SEC_FILE_READ_DATA);
1719 2 : smb2_util_close(tree, io.out.file.handle);
1720 :
1721 2 : torture_comment(tctx, "try open for generic write\n");
1722 2 : io.in.desired_access = SEC_GENERIC_WRITE;
1723 2 : status = smb2_create(tree, tctx, &io);
1724 2 : CHECK_STATUS(status, NT_STATUS_OK);
1725 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1726 : SEC_RIGHTS_FILE_WRITE);
1727 2 : smb2_util_close(tree, io.out.file.handle);
1728 :
1729 2 : torture_comment(tctx, "try open for generic read\n");
1730 2 : io.in.desired_access = SEC_GENERIC_READ;
1731 2 : status = smb2_create(tree, tctx, &io);
1732 2 : CHECK_STATUS(status, NT_STATUS_OK);
1733 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1734 : SEC_RIGHTS_FILE_READ);
1735 2 : smb2_util_close(tree, io.out.file.handle);
1736 :
1737 2 : torture_comment(tctx, "set DACL with 0 aces\n");
1738 2 : ZERO_STRUCT(dacl);
1739 2 : dacl.revision = SECURITY_ACL_REVISION_NT4;
1740 2 : dacl.num_aces = 0;
1741 2 : sd->dacl = &dacl;
1742 :
1743 2 : s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
1744 2 : s.set_secdesc.in.file.handle = handle;
1745 2 : s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
1746 2 : s.set_secdesc.in.sd = sd;
1747 2 : status = smb2_setinfo_file(tree, &s);
1748 2 : CHECK_STATUS(status, NT_STATUS_OK);
1749 :
1750 2 : torture_comment(tctx, "get the sd\n");
1751 2 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1752 2 : q.query_secdesc.in.file.handle = handle;
1753 2 : q.query_secdesc.in.secinfo_flags =
1754 : SECINFO_OWNER |
1755 : SECINFO_GROUP |
1756 : SECINFO_DACL;
1757 2 : status = smb2_getinfo_file(tree, tctx, &q);
1758 2 : CHECK_STATUS(status, NT_STATUS_OK);
1759 :
1760 : /* Testing the modified DACL */
1761 2 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1762 0 : ret = false;
1763 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1764 : }
1765 2 : if (q.query_secdesc.out.sd->dacl == NULL) {
1766 0 : ret = false;
1767 0 : torture_fail_goto(tctx, done, "no DACL has been created on the server!\n");
1768 : }
1769 2 : if (q.query_secdesc.out.sd->dacl->num_aces != 0) {
1770 0 : torture_result(tctx, TORTURE_FAIL, "DACL has %u aces!\n",
1771 0 : q.query_secdesc.out.sd->dacl->num_aces);
1772 0 : ret = false;
1773 0 : goto done;
1774 : }
1775 :
1776 2 : torture_comment(tctx, "try open for read control\n");
1777 2 : io.in.desired_access = SEC_STD_READ_CONTROL;
1778 2 : status = smb2_create(tree, tctx, &io);
1779 2 : CHECK_STATUS(status, NT_STATUS_OK);
1780 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1781 : SEC_STD_READ_CONTROL);
1782 2 : smb2_util_close(tree, io.out.file.handle);
1783 :
1784 2 : torture_comment(tctx, "try open for write => access_denied\n");
1785 2 : io.in.desired_access = SEC_FILE_WRITE_DATA;
1786 2 : status = smb2_create(tree, tctx, &io);
1787 2 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1788 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1789 : } else {
1790 2 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1791 : }
1792 :
1793 2 : torture_comment(tctx, "try open for read => access_denied\n");
1794 2 : io.in.desired_access = SEC_FILE_READ_DATA;
1795 2 : status = smb2_create(tree, tctx, &io);
1796 2 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1797 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1798 : } else {
1799 2 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1800 : }
1801 :
1802 2 : torture_comment(tctx, "try open for generic write => access_denied\n");
1803 2 : io.in.desired_access = SEC_GENERIC_WRITE;
1804 2 : status = smb2_create(tree, tctx, &io);
1805 2 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1806 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1807 : } else {
1808 2 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1809 : }
1810 :
1811 2 : torture_comment(tctx, "try open for generic read => access_denied\n");
1812 2 : io.in.desired_access = SEC_GENERIC_READ;
1813 2 : status = smb2_create(tree, tctx, &io);
1814 2 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1815 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1816 : } else {
1817 2 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1818 : }
1819 :
1820 2 : torture_comment(tctx, "set empty sd\n");
1821 2 : sd->type &= ~SEC_DESC_DACL_PRESENT;
1822 2 : sd->dacl = NULL;
1823 :
1824 2 : s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
1825 2 : s.set_secdesc.in.file.handle = handle;
1826 2 : s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
1827 2 : s.set_secdesc.in.sd = sd;
1828 2 : status = smb2_setinfo_file(tree, &s);
1829 2 : CHECK_STATUS(status, NT_STATUS_OK);
1830 :
1831 2 : torture_comment(tctx, "get the sd\n");
1832 2 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1833 2 : q.query_secdesc.in.file.handle = handle;
1834 2 : q.query_secdesc.in.secinfo_flags =
1835 : SECINFO_OWNER |
1836 : SECINFO_GROUP |
1837 : SECINFO_DACL;
1838 2 : status = smb2_getinfo_file(tree, tctx, &q);
1839 2 : CHECK_STATUS(status, NT_STATUS_OK);
1840 :
1841 : /* Testing the modified DACL */
1842 2 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1843 0 : ret = false;
1844 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1845 : }
1846 2 : if (q.query_secdesc.out.sd->dacl != NULL) {
1847 0 : ret = false;
1848 0 : torture_fail_goto(tctx, done, "DACL has been created on the server!\n");
1849 : }
1850 2 : done:
1851 2 : smb2_util_close(tree, handle);
1852 2 : smb2_util_unlink(tree, fname);
1853 2 : smb2_tdis(tree);
1854 2 : smb2_logoff(tree->session);
1855 2 : return ret;
1856 : }
1857 :
1858 : /*
1859 : test SMB2 mkdir with OPEN_IF on the same name twice.
1860 : Must use 2 connections to hit the race.
1861 : */
1862 :
1863 2 : static bool test_mkdir_dup(struct torture_context *tctx,
1864 : struct smb2_tree *tree)
1865 : {
1866 2 : const char *fname = "mkdir_dup";
1867 : NTSTATUS status;
1868 2 : bool ret = true;
1869 : union smb_open io;
1870 : struct smb2_tree **trees;
1871 : struct smb2_request **requests;
1872 : union smb_open *ios;
1873 2 : int i, num_files = 2;
1874 2 : int num_ok = 0;
1875 2 : int num_created = 0;
1876 2 : int num_existed = 0;
1877 :
1878 2 : torture_comment(tctx,
1879 : "Testing SMB2 Create Directory with multiple connections\n");
1880 2 : trees = talloc_array(tctx, struct smb2_tree *, num_files);
1881 2 : requests = talloc_array(tctx, struct smb2_request *, num_files);
1882 2 : ios = talloc_array(tctx, union smb_open, num_files);
1883 2 : if ((tctx->ev == NULL) || (trees == NULL) || (requests == NULL) ||
1884 : (ios == NULL)) {
1885 0 : torture_fail(tctx, ("talloc failed\n"));
1886 : ret = false;
1887 : goto done;
1888 : }
1889 :
1890 2 : tree->session->transport->options.request_timeout = 60;
1891 :
1892 6 : for (i=0; i<num_files; i++) {
1893 4 : if (!torture_smb2_connection(tctx, &(trees[i]))) {
1894 0 : torture_fail(tctx,
1895 : talloc_asprintf(tctx,
1896 : "Could not open %d'th connection\n", i));
1897 : ret = false;
1898 : goto done;
1899 : }
1900 4 : trees[i]->session->transport->options.request_timeout = 60;
1901 : }
1902 :
1903 : /* cleanup */
1904 2 : smb2_util_unlink(tree, fname);
1905 2 : smb2_util_rmdir(tree, fname);
1906 :
1907 : /*
1908 : base ntcreatex parms
1909 : */
1910 2 : ZERO_STRUCT(io.smb2);
1911 2 : io.generic.level = RAW_OPEN_SMB2;
1912 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1913 2 : io.smb2.in.alloc_size = 0;
1914 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1915 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1916 : NTCREATEX_SHARE_ACCESS_WRITE|
1917 : NTCREATEX_SHARE_ACCESS_DELETE;
1918 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1919 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1920 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1921 2 : io.smb2.in.security_flags = 0;
1922 2 : io.smb2.in.fname = fname;
1923 2 : io.smb2.in.create_flags = 0;
1924 :
1925 6 : for (i=0; i<num_files; i++) {
1926 4 : ios[i] = io;
1927 4 : requests[i] = smb2_create_send(trees[i], &(ios[i].smb2));
1928 4 : if (requests[i] == NULL) {
1929 0 : torture_fail(tctx,
1930 : talloc_asprintf(tctx,
1931 : "could not send %d'th request\n", i));
1932 : ret = false;
1933 : goto done;
1934 : }
1935 : }
1936 :
1937 2 : torture_comment(tctx, "waiting for replies\n");
1938 16 : while (1) {
1939 18 : bool unreplied = false;
1940 28 : for (i=0; i<num_files; i++) {
1941 26 : if (requests[i] == NULL) {
1942 6 : continue;
1943 : }
1944 20 : if (requests[i]->state < SMB2_REQUEST_DONE) {
1945 16 : unreplied = true;
1946 16 : break;
1947 : }
1948 4 : status = smb2_create_recv(requests[i], tctx,
1949 4 : &(ios[i].smb2));
1950 :
1951 4 : if (NT_STATUS_IS_OK(status)) {
1952 4 : num_ok += 1;
1953 :
1954 4 : if (ios[i].smb2.out.create_action ==
1955 : NTCREATEX_ACTION_CREATED) {
1956 2 : num_created++;
1957 : }
1958 4 : if (ios[i].smb2.out.create_action ==
1959 : NTCREATEX_ACTION_EXISTED) {
1960 2 : num_existed++;
1961 : }
1962 : } else {
1963 0 : torture_fail(tctx,
1964 : talloc_asprintf(tctx,
1965 : "File %d returned status %s\n", i,
1966 : nt_errstr(status)));
1967 : }
1968 :
1969 :
1970 4 : requests[i] = NULL;
1971 : }
1972 18 : if (!unreplied) {
1973 2 : break;
1974 : }
1975 :
1976 16 : if (tevent_loop_once(tctx->ev) != 0) {
1977 0 : torture_fail(tctx, "tevent_loop_once failed\n");
1978 : ret = false;
1979 : goto done;
1980 : }
1981 : }
1982 :
1983 2 : if (num_ok != 2) {
1984 0 : torture_fail(tctx,
1985 : talloc_asprintf(tctx,
1986 : "num_ok == %d\n", num_ok));
1987 : ret = false;
1988 : }
1989 2 : if (num_created != 1) {
1990 0 : torture_fail(tctx,
1991 : talloc_asprintf(tctx,
1992 : "num_created == %d\n", num_created));
1993 : ret = false;
1994 : }
1995 2 : if (num_existed != 1) {
1996 0 : torture_fail(tctx,
1997 : talloc_asprintf(tctx,
1998 : "num_existed == %d\n", num_existed));
1999 : ret = false;
2000 : }
2001 2 : done:
2002 2 : smb2_deltree(tree, fname);
2003 :
2004 2 : return ret;
2005 : }
2006 :
2007 : /*
2008 : test directory creation with an initial allocation size > 0
2009 : */
2010 2 : static bool test_dir_alloc_size(struct torture_context *tctx,
2011 : struct smb2_tree *tree)
2012 : {
2013 2 : bool ret = true;
2014 2 : const char *dname = DNAME "\\torture_alloc_size.dir";
2015 : NTSTATUS status;
2016 : struct smb2_create c;
2017 2 : struct smb2_handle h1 = {{0}}, h2;
2018 :
2019 2 : torture_comment(tctx, "Checking initial allocation size on directories\n");
2020 :
2021 2 : smb2_deltree(tree, dname);
2022 :
2023 2 : status = torture_smb2_testdir(tree, DNAME, &h1);
2024 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed");
2025 :
2026 2 : ZERO_STRUCT(c);
2027 2 : c.in.create_disposition = NTCREATEX_DISP_CREATE;
2028 2 : c.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
2029 2 : c.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
2030 2 : c.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2031 2 : c.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2032 2 : c.in.fname = dname;
2033 : /*
2034 : * An insanely large value so we can check the value is
2035 : * ignored: Samba either returns 0 (current behaviour), or,
2036 : * once vfswrap_get_alloc_size() is fixed to allow retrieving
2037 : * the allocated size for directories, returns
2038 : * smb_roundup(..., stat.st_size) which would be 1 MB by
2039 : * default.
2040 : *
2041 : * Windows returns 0 for empty directories, once directories
2042 : * have a few entries it starts replying with values > 0.
2043 : */
2044 2 : c.in.alloc_size = 1024*1024*1024;
2045 :
2046 2 : status = smb2_create(tree, tctx, &c);
2047 2 : h2 = c.out.file.handle;
2048 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2049 : "dir create with initial alloc size failed");
2050 :
2051 2 : smb2_util_close(tree, h2);
2052 :
2053 2 : torture_comment(tctx, "Got directory alloc size: %ju\n", (uintmax_t)c.out.alloc_size);
2054 :
2055 : /*
2056 : * See above for the rational for this test
2057 : */
2058 2 : if (c.out.alloc_size > 1024*1024) {
2059 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "bad alloc size: %ju",
2060 : (uintmax_t)c.out.alloc_size));
2061 : }
2062 :
2063 2 : done:
2064 2 : if (!smb2_util_handle_empty(h1)) {
2065 2 : smb2_util_close(tree, h1);
2066 : }
2067 2 : smb2_deltree(tree, DNAME);
2068 2 : return ret;
2069 : }
2070 :
2071 0 : static bool test_twrp_write(struct torture_context *tctx, struct smb2_tree *tree)
2072 : {
2073 : struct smb2_create io;
2074 0 : struct smb2_handle h1 = {{0}};
2075 : NTSTATUS status;
2076 0 : bool ret = true;
2077 0 : char *p = NULL;
2078 : struct tm tm;
2079 : time_t t;
2080 : uint64_t nttime;
2081 0 : const char *file = NULL;
2082 0 : const char *snapshot = NULL;
2083 : uint32_t expected_access;
2084 : union smb_fileinfo getinfo;
2085 : union smb_setfileinfo setinfo;
2086 0 : struct security_descriptor *sd = NULL, *sd_orig = NULL;
2087 0 : const char *owner_sid = NULL;
2088 : struct create_disps_tests {
2089 : const char *file;
2090 : uint32_t create_disposition;
2091 : uint32_t create_options;
2092 : NTSTATUS expected_status;
2093 : };
2094 0 : struct create_disps_tests *cd_test = NULL;
2095 :
2096 0 : file = torture_setting_string(tctx, "twrp_file", NULL);
2097 0 : if (file == NULL) {
2098 0 : torture_skip(tctx, "missing 'twrp_file' option\n");
2099 : }
2100 :
2101 0 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
2102 0 : if (snapshot == NULL) {
2103 0 : torture_skip(tctx, "missing 'twrp_snapshot' option\n");
2104 : }
2105 :
2106 0 : torture_comment(tctx, "Testing timewarp (%s) (%s)\n", file, snapshot);
2107 :
2108 0 : setenv("TZ", "GMT", 1);
2109 :
2110 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2111 : * effect if it is greather than 1. */
2112 0 : ZERO_STRUCT(tm);
2113 :
2114 0 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
2115 0 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
2116 0 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
2117 :
2118 0 : t = mktime(&tm);
2119 0 : unix_to_nt_time(&nttime, t);
2120 :
2121 0 : io = (struct smb2_create) {
2122 : .in.desired_access = SEC_FILE_READ_DATA,
2123 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2124 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2125 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2126 : .in.fname = file,
2127 : .in.query_maximal_access = true,
2128 : .in.timewarp = nttime,
2129 : };
2130 :
2131 0 : status = smb2_create(tree, tctx, &io);
2132 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2133 : "smb2_create\n");
2134 0 : smb2_util_close(tree, io.out.file.handle);
2135 :
2136 0 : expected_access = SEC_RIGHTS_FILE_ALL &
2137 : ~(SEC_FILE_EXECUTE | SEC_DIR_DELETE_CHILD);
2138 :
2139 0 : torture_assert_int_equal_goto(tctx,
2140 : io.out.maximal_access & expected_access,
2141 : expected_access,
2142 : ret, done, "Bad access\n");
2143 :
2144 : {
2145 : /*
2146 : * Test create dispositions
2147 : */
2148 0 : struct create_disps_tests cd_tests[] = {
2149 : {
2150 : .file = file,
2151 : .create_disposition = NTCREATEX_DISP_OPEN,
2152 : .expected_status = NT_STATUS_OK,
2153 : },
2154 : {
2155 : .file = file,
2156 : .create_disposition = NTCREATEX_DISP_OPEN_IF,
2157 : .expected_status = NT_STATUS_OK,
2158 : },
2159 : {
2160 : .file = file,
2161 : .create_disposition = NTCREATEX_DISP_OVERWRITE,
2162 : .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2163 : },
2164 : {
2165 : .file = file,
2166 : .create_disposition = NTCREATEX_DISP_OVERWRITE_IF,
2167 : .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2168 : },
2169 : {
2170 : .file = file,
2171 : .create_disposition = NTCREATEX_DISP_SUPERSEDE,
2172 : .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2173 : },
2174 : {
2175 : .file = "newfile",
2176 : .create_disposition = NTCREATEX_DISP_OPEN_IF,
2177 : .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2178 : },
2179 : {
2180 : .file = "newfile",
2181 : .create_disposition = NTCREATEX_DISP_OVERWRITE_IF,
2182 : .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2183 : },
2184 : {
2185 : .file = "newfile",
2186 : .create_disposition = NTCREATEX_DISP_CREATE,
2187 : .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2188 : },
2189 : {
2190 : .file = "newfile",
2191 : .create_disposition = NTCREATEX_DISP_SUPERSEDE,
2192 : .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2193 : },
2194 : {
2195 : .file = "newdir",
2196 : .create_disposition = NTCREATEX_DISP_OPEN_IF,
2197 : .create_options = NTCREATEX_OPTIONS_DIRECTORY,
2198 : .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2199 : },
2200 : {
2201 : .file = "newdir",
2202 : .create_disposition = NTCREATEX_DISP_CREATE,
2203 : .create_options = NTCREATEX_OPTIONS_DIRECTORY,
2204 : .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2205 : },
2206 : {
2207 : .file = NULL,
2208 : },
2209 : };
2210 :
2211 0 : for (cd_test = &cd_tests[0]; cd_test->file != NULL; cd_test++) {
2212 0 : io = (struct smb2_create) {
2213 0 : .in.fname = cd_test->file,
2214 0 : .in.create_disposition = cd_test->create_disposition,
2215 0 : .in.create_options = cd_test->create_options,
2216 :
2217 : .in.desired_access = SEC_FILE_READ_DATA,
2218 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2219 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2220 : .in.timewarp = nttime,
2221 : };
2222 :
2223 0 : status = smb2_create(tree, tctx, &io);
2224 0 : torture_assert_ntstatus_equal_goto(
2225 : tctx, status, cd_test->expected_status, ret, done,
2226 : "Bad status\n");
2227 : }
2228 : }
2229 :
2230 0 : io = (struct smb2_create) {
2231 : .in.desired_access = expected_access,
2232 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2233 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2234 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2235 : .in.fname = file,
2236 : .in.timewarp = nttime,
2237 : };
2238 :
2239 0 : status = smb2_create(tree, tctx, &io);
2240 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2241 : "smb2_create\n");
2242 0 : h1 = io.out.file.handle;
2243 :
2244 0 : status = smb2_util_write(tree, h1, "123", 0, 3);
2245 0 : torture_assert_ntstatus_equal_goto(tctx, status,
2246 : NT_STATUS_MEDIA_WRITE_PROTECTED,
2247 : ret, done, "smb2_create\n");
2248 :
2249 : /*
2250 : * Verify access mask
2251 : */
2252 :
2253 0 : ZERO_STRUCT(getinfo);
2254 0 : getinfo.generic.level = RAW_FILEINFO_ACCESS_INFORMATION;
2255 0 : getinfo.generic.in.file.handle = h1;
2256 :
2257 0 : status = smb2_getinfo_file(tree, tree, &getinfo);
2258 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2259 : "smb2_getinfo_file\n");
2260 :
2261 0 : torture_assert_int_equal_goto(
2262 : tctx,
2263 : getinfo.access_information.out.access_flags,
2264 : expected_access,
2265 : ret, done,
2266 : "Bad access mask\n");
2267 :
2268 : /*
2269 : * Check we can't set various things
2270 : */
2271 :
2272 0 : ZERO_STRUCT(getinfo);
2273 0 : getinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
2274 0 : getinfo.query_secdesc.in.file.handle = h1;
2275 0 : getinfo.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
2276 :
2277 0 : status = smb2_getinfo_file(tree, tctx, &getinfo);
2278 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2279 : "smb2_getinfo_file\n");
2280 :
2281 0 : sd_orig = getinfo.query_secdesc.out.sd;
2282 0 : owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
2283 :
2284 0 : sd = security_descriptor_dacl_create(tctx,
2285 : 0, NULL, NULL,
2286 : owner_sid,
2287 : SEC_ACE_TYPE_ACCESS_ALLOWED,
2288 : SEC_FILE_WRITE_DATA,
2289 : 0,
2290 : NULL);
2291 :
2292 : /* Try to set ACL */
2293 :
2294 0 : ZERO_STRUCT(setinfo);
2295 0 : setinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
2296 0 : setinfo.set_secdesc.in.file.handle = h1;
2297 0 : setinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL;
2298 0 : setinfo.set_secdesc.in.sd = sd;
2299 :
2300 0 : status = smb2_setinfo_file(tree, &setinfo);
2301 0 : torture_assert_ntstatus_equal_goto(
2302 : tctx,
2303 : status,
2304 : NT_STATUS_MEDIA_WRITE_PROTECTED,
2305 : ret, done,
2306 : "smb2_setinfo_file\n");
2307 :
2308 : /* Try to delete */
2309 :
2310 0 : ZERO_STRUCT(setinfo);
2311 0 : setinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
2312 0 : setinfo.disposition_info.in.delete_on_close = 1;
2313 0 : setinfo.generic.in.file.handle = h1;
2314 :
2315 0 : status = smb2_setinfo_file(tree, &setinfo);
2316 0 : torture_assert_ntstatus_equal_goto(
2317 : tctx,
2318 : status,
2319 : NT_STATUS_MEDIA_WRITE_PROTECTED,
2320 : ret, done,
2321 : "smb2_setinfo_file\n");
2322 :
2323 0 : ZERO_STRUCT(setinfo);
2324 0 : setinfo.basic_info.in.attrib = FILE_ATTRIBUTE_HIDDEN;
2325 0 : setinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
2326 0 : setinfo.generic.in.file.handle = h1;
2327 :
2328 0 : status = smb2_setinfo_file(tree, &setinfo);
2329 0 : torture_assert_ntstatus_equal_goto(
2330 : tctx,
2331 : status,
2332 : NT_STATUS_MEDIA_WRITE_PROTECTED,
2333 : ret, done,
2334 : "smb2_setinfo_file\n");
2335 :
2336 : /* Try to truncate */
2337 :
2338 0 : ZERO_STRUCT(setinfo);
2339 0 : setinfo.generic.level = SMB_SFILEINFO_END_OF_FILE_INFORMATION;
2340 0 : setinfo.generic.in.file.handle = h1;
2341 0 : setinfo.end_of_file_info.in.size = 0x100000;
2342 :
2343 0 : status = smb2_setinfo_file(tree, &setinfo);
2344 0 : torture_assert_ntstatus_equal_goto(
2345 : tctx,
2346 : status,
2347 : NT_STATUS_MEDIA_WRITE_PROTECTED,
2348 : ret, done,
2349 : "smb2_setinfo_file\n");
2350 :
2351 : /* Try to set a hardlink */
2352 :
2353 0 : ZERO_STRUCT(setinfo);
2354 0 : setinfo.generic.level = RAW_SFILEINFO_LINK_INFORMATION;
2355 0 : setinfo.generic.in.file.handle = h1;
2356 0 : setinfo.link_information.in.new_name = "hardlink";
2357 :
2358 0 : status = smb2_setinfo_file(tree, &setinfo);
2359 0 : torture_assert_ntstatus_equal_goto(
2360 : tctx,
2361 : status,
2362 : NT_STATUS_NOT_SAME_DEVICE,
2363 : ret, done,
2364 : "smb2_setinfo_file\n");
2365 :
2366 : /* Try to rename */
2367 :
2368 0 : ZERO_STRUCT(setinfo);
2369 0 : setinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
2370 0 : setinfo.rename_information.in.file.handle = h1;
2371 0 : setinfo.rename_information.in.new_name = "renamed";
2372 :
2373 0 : status = smb2_setinfo_file(tree, &setinfo);
2374 0 : torture_assert_ntstatus_equal_goto(
2375 : tctx,
2376 : status,
2377 : NT_STATUS_NOT_SAME_DEVICE,
2378 : ret, done,
2379 : "smb2_setinfo_file\n");
2380 :
2381 0 : smb2_util_close(tree, h1);
2382 0 : ZERO_STRUCT(h1);
2383 :
2384 0 : done:
2385 0 : if (!smb2_util_handle_empty(h1)) {
2386 0 : smb2_util_close(tree, h1);
2387 : }
2388 0 : return ret;
2389 : }
2390 :
2391 0 : static bool test_twrp_stream(struct torture_context *tctx,
2392 : struct smb2_tree *tree)
2393 : {
2394 : struct smb2_create io;
2395 : NTSTATUS status;
2396 0 : bool ret = true;
2397 0 : char *p = NULL;
2398 : struct tm tm;
2399 : time_t t;
2400 : uint64_t nttime;
2401 0 : const char *file = NULL;
2402 0 : const char *stream = NULL;
2403 0 : const char *snapshot = NULL;
2404 : int stream_size;
2405 0 : char *path = NULL;
2406 0 : uint8_t *buf = NULL;
2407 0 : struct smb2_handle h1 = {{0}};
2408 : struct smb2_read r;
2409 :
2410 0 : file = torture_setting_string(tctx, "twrp_file", NULL);
2411 0 : if (file == NULL) {
2412 0 : torture_skip(tctx, "missing 'twrp_file' option\n");
2413 : }
2414 :
2415 0 : stream = torture_setting_string(tctx, "twrp_stream", NULL);
2416 0 : if (stream == NULL) {
2417 0 : torture_skip(tctx, "missing 'twrp_stream' option\n");
2418 : }
2419 :
2420 0 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
2421 0 : if (snapshot == NULL) {
2422 0 : torture_skip(tctx, "missing 'twrp_snapshot' option\n");
2423 : }
2424 :
2425 0 : stream_size = torture_setting_int(tctx, "twrp_stream_size", 0);
2426 0 : if (stream_size == 0) {
2427 0 : torture_skip(tctx, "missing 'twrp_stream_size' option\n");
2428 : }
2429 :
2430 0 : torture_comment(tctx, "Testing timewarp on stream (%s) (%s)\n",
2431 : file, snapshot);
2432 :
2433 0 : path = talloc_asprintf(tree, "%s:%s", file, stream);
2434 0 : torture_assert_not_null_goto(tctx, path, ret, done, "path\n");
2435 :
2436 0 : buf = talloc_zero_array(tree, uint8_t, stream_size);
2437 0 : torture_assert_not_null_goto(tctx, buf, ret, done, "buf\n");
2438 :
2439 0 : setenv("TZ", "GMT", 1);
2440 :
2441 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2442 : * effect if it is greather than 1. */
2443 0 : ZERO_STRUCT(tm);
2444 :
2445 0 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
2446 0 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
2447 0 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
2448 :
2449 0 : t = mktime(&tm);
2450 0 : unix_to_nt_time(&nttime, t);
2451 :
2452 0 : io = (struct smb2_create) {
2453 : .in.desired_access = SEC_FILE_READ_DATA,
2454 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2455 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2456 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2457 : .in.fname = path,
2458 : .in.timewarp = nttime,
2459 : };
2460 :
2461 0 : status = smb2_create(tree, tctx, &io);
2462 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2463 : "smb2_create\n");
2464 0 : h1 = io.out.file.handle;
2465 :
2466 0 : r = (struct smb2_read) {
2467 : .in.file.handle = h1,
2468 : .in.length = stream_size,
2469 : .in.offset = 0,
2470 : };
2471 :
2472 0 : status = smb2_read(tree, tree, &r);
2473 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2474 : "smb2_create\n");
2475 :
2476 0 : smb2_util_close(tree, h1);
2477 :
2478 0 : done:
2479 0 : return ret;
2480 : }
2481 :
2482 0 : static bool test_twrp_openroot(struct torture_context *tctx, struct smb2_tree *tree)
2483 : {
2484 : struct smb2_create io;
2485 : NTSTATUS status;
2486 0 : bool ret = true;
2487 0 : char *p = NULL;
2488 : struct tm tm;
2489 : time_t t;
2490 : uint64_t nttime;
2491 0 : const char *snapshot = NULL;
2492 :
2493 0 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
2494 0 : if (snapshot == NULL) {
2495 0 : torture_skip(tctx, "missing 'twrp_snapshot' option\n");
2496 : }
2497 :
2498 0 : torture_comment(tctx, "Testing open of root of "
2499 : "share with timewarp (%s)\n",
2500 : snapshot);
2501 :
2502 0 : setenv("TZ", "GMT", 1);
2503 :
2504 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2505 : * effect if it is greather than 1. */
2506 0 : ZERO_STRUCT(tm);
2507 :
2508 0 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
2509 0 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
2510 0 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
2511 :
2512 0 : t = mktime(&tm);
2513 0 : unix_to_nt_time(&nttime, t);
2514 :
2515 0 : io = (struct smb2_create) {
2516 : .in.desired_access = SEC_FILE_READ_DATA,
2517 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2518 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2519 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2520 : .in.fname = "",
2521 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2522 : .in.timewarp = nttime,
2523 : };
2524 :
2525 0 : status = smb2_create(tree, tctx, &io);
2526 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2527 : "smb2_create\n");
2528 0 : smb2_util_close(tree, io.out.file.handle);
2529 :
2530 0 : done:
2531 0 : return ret;
2532 : }
2533 :
2534 0 : static bool test_twrp_listdir(struct torture_context *tctx,
2535 : struct smb2_tree *tree)
2536 : {
2537 : struct smb2_create create;
2538 0 : struct smb2_handle h = {{0}};
2539 : struct smb2_find find;
2540 : unsigned int count;
2541 : union smb_search_data *d;
2542 0 : char *p = NULL;
2543 : struct tm tm;
2544 : time_t t;
2545 : uint64_t nttime;
2546 0 : const char *snapshot = NULL;
2547 : uint64_t normal_fileid;
2548 : uint64_t snapshot_fileid;
2549 : NTSTATUS status;
2550 0 : bool ret = true;
2551 :
2552 0 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
2553 0 : if (snapshot == NULL) {
2554 0 : torture_fail(tctx, "missing 'twrp_snapshot' option\n");
2555 : }
2556 :
2557 0 : torture_comment(tctx, "Testing File-Ids of directory listing "
2558 : "with timewarp (%s)\n",
2559 : snapshot);
2560 :
2561 0 : setenv("TZ", "GMT", 1);
2562 :
2563 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2564 : * effect if it is greather than 1. */
2565 0 : ZERO_STRUCT(tm);
2566 :
2567 0 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
2568 0 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
2569 0 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
2570 :
2571 0 : t = mktime(&tm);
2572 0 : unix_to_nt_time(&nttime, t);
2573 :
2574 : /*
2575 : * 1: Query the file's File-Id
2576 : */
2577 0 : create = (struct smb2_create) {
2578 : .in.desired_access = SEC_FILE_READ_DATA,
2579 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2580 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2581 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2582 : .in.fname = "subdir/hardlink",
2583 : .in.query_on_disk_id = true,
2584 : };
2585 :
2586 0 : status = smb2_create(tree, tctx, &create);
2587 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2588 : "test file could not be created\n");
2589 0 : smb2_util_close(tree, create.out.file.handle);
2590 0 : normal_fileid = BVAL(&create.out.on_disk_id, 0);
2591 :
2592 : /*
2593 : * 2: check directory listing of the file returns same File-Id
2594 : */
2595 :
2596 0 : create = (struct smb2_create) {
2597 : .in.desired_access = SEC_DIR_LIST,
2598 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2599 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2600 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2601 : .in.fname = "subdir",
2602 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2603 : };
2604 :
2605 0 : status = smb2_create(tree, tctx, &create);
2606 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2607 : "smb2_create\n");
2608 0 : h = create.out.file.handle;
2609 :
2610 0 : find = (struct smb2_find) {
2611 : .in.file.handle = h,
2612 : .in.pattern = "*",
2613 : .in.max_response_size = 0x1000,
2614 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
2615 : };
2616 :
2617 0 : status = smb2_find_level(tree, tree, &find, &count, &d);
2618 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2619 : "smb2_find_level failed\n");
2620 :
2621 0 : smb2_util_close(tree, h);
2622 :
2623 0 : torture_assert_int_equal_goto(tctx, count, 3, ret, done, "Bad count\n");
2624 0 : torture_assert_str_equal_goto(tctx,
2625 : d[2].id_both_directory_info.name.s,
2626 : "hardlink",
2627 : ret, done, "bad name");
2628 0 : torture_assert_u64_equal_goto(tctx,
2629 : d[2].id_both_directory_info.file_id,
2630 : normal_fileid,
2631 : ret, done, "bad fileid\n");
2632 :
2633 : /*
2634 : * 3: Query File-Id of snapshot of the file and check the File-Id is
2635 : * different compared to the basefile
2636 : */
2637 :
2638 0 : create = (struct smb2_create) {
2639 : .in.desired_access = SEC_FILE_READ_DATA,
2640 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2641 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2642 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2643 : .in.fname = "subdir/hardlink",
2644 : .in.query_on_disk_id = true,
2645 : .in.timewarp = nttime,
2646 : };
2647 :
2648 0 : status = smb2_create(tree, tctx, &create);
2649 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2650 : "test file could not be created\n");
2651 0 : smb2_util_close(tree, create.out.file.handle);
2652 :
2653 0 : snapshot_fileid = BVAL(&create.out.on_disk_id, 0);
2654 :
2655 : /*
2656 : * 4: List directory of the snapshot and check the File-Id returned here
2657 : * is the same as in 3.
2658 : */
2659 :
2660 0 : create = (struct smb2_create) {
2661 : .in.desired_access = SEC_DIR_LIST,
2662 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2663 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2664 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2665 : .in.fname = "subdir",
2666 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2667 : .in.timewarp = nttime,
2668 : };
2669 :
2670 0 : status = smb2_create(tree, tctx, &create);
2671 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2672 : "smb2_create\n");
2673 0 : h = create.out.file.handle;
2674 :
2675 0 : find = (struct smb2_find) {
2676 : .in.file.handle = h,
2677 : .in.pattern = "*",
2678 : .in.max_response_size = 0x1000,
2679 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
2680 : };
2681 :
2682 0 : status = smb2_find_level(tree, tree, &find, &count, &d);
2683 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2684 : "smb2_find_level failed\n");
2685 0 : smb2_util_close(tree, h);
2686 :
2687 0 : torture_assert_int_equal_goto(tctx, count, 3, ret, done, "Bad count\n");
2688 0 : torture_assert_str_equal_goto(tctx,
2689 : d[2].id_both_directory_info.name.s,
2690 : "hardlink",
2691 : ret, done, "bad name");
2692 0 : torture_assert_u64_equal_goto(tctx,
2693 : snapshot_fileid,
2694 : d[2].id_both_directory_info.file_id,
2695 : ret, done, "bad fileid\n");
2696 :
2697 0 : done:
2698 0 : return ret;
2699 : }
2700 :
2701 0 : static bool test_fileid(struct torture_context *tctx,
2702 : struct smb2_tree *tree)
2703 : {
2704 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2705 0 : const char *fname = DNAME "\\foo";
2706 0 : const char *sname = DNAME "\\foo:bar";
2707 : struct smb2_handle testdirh;
2708 : struct smb2_handle h1;
2709 : struct smb2_create create;
2710 : union smb_fileinfo finfo;
2711 : union smb_setfileinfo sinfo;
2712 : struct smb2_find f;
2713 : unsigned int count;
2714 : union smb_search_data *d;
2715 : uint64_t expected_fileid;
2716 : uint64_t returned_fileid;
2717 : NTSTATUS status;
2718 0 : bool ret = true;
2719 :
2720 0 : smb2_deltree(tree, DNAME);
2721 :
2722 0 : status = torture_smb2_testdir(tree, DNAME, &testdirh);
2723 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2724 : "torture_smb2_testdir failed\n");
2725 :
2726 : /*
2727 : * Initial create with QFID
2728 : */
2729 0 : create = (struct smb2_create) {
2730 : .in.desired_access = SEC_FILE_ALL,
2731 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2732 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2733 : .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
2734 : .in.fname = fname,
2735 : .in.query_on_disk_id = true,
2736 : };
2737 :
2738 0 : status = smb2_create(tree, tctx, &create);
2739 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2740 : "test file could not be created\n");
2741 0 : h1 = create.out.file.handle;
2742 0 : expected_fileid = BVAL(&create.out.on_disk_id, 0);
2743 :
2744 : /*
2745 : * Getinfo the File-ID on the just opened handle
2746 : */
2747 0 : finfo = (union smb_fileinfo) {
2748 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2749 : .generic.in.file.handle = h1,
2750 : };
2751 :
2752 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2753 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2754 : "torture_smb2_testdir\n");
2755 0 : smb2_util_close(tree, h1);
2756 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2757 : expected_fileid,
2758 : ret, done, "bad fileid\n");
2759 :
2760 : /*
2761 : * Open existing with QFID
2762 : */
2763 0 : create = (struct smb2_create) {
2764 : .in.desired_access = SEC_FILE_ALL,
2765 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2766 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2767 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2768 : .in.fname = fname,
2769 : .in.query_on_disk_id = true,
2770 : };
2771 :
2772 0 : status = smb2_create(tree, tctx, &create);
2773 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2774 : "test file could not be created\n");
2775 0 : h1 = create.out.file.handle;
2776 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2777 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2778 : ret, done, "bad fileid\n");
2779 :
2780 : /*
2781 : * Getinfo the File-ID on the just opened handle
2782 : */
2783 0 : finfo = (union smb_fileinfo) {
2784 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2785 : .generic.in.file.handle = h1,
2786 : };
2787 :
2788 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2789 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2790 : "torture_smb2_testdir\n");
2791 0 : smb2_util_close(tree, h1);
2792 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2793 : expected_fileid,
2794 : ret, done, "bad fileid\n");
2795 :
2796 : /*
2797 : * Overwrite with QFID
2798 : */
2799 0 : create = (struct smb2_create) {
2800 : .in.desired_access = SEC_FILE_ALL,
2801 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2802 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2803 : .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
2804 : .in.fname = fname,
2805 : .in.query_on_disk_id = true,
2806 : };
2807 :
2808 0 : status = smb2_create(tree, tctx, &create);
2809 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2810 : "test file could not be created\n");
2811 0 : h1 = create.out.file.handle;
2812 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2813 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2814 : ret, done, "bad fileid\n");
2815 :
2816 : /*
2817 : * Getinfo the File-ID on the open with overwrite handle
2818 : */
2819 0 : finfo = (union smb_fileinfo) {
2820 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2821 : .generic.in.file.handle = h1,
2822 : };
2823 :
2824 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2825 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2826 : "torture_smb2_testdir\n");
2827 0 : smb2_util_close(tree, h1);
2828 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2829 : expected_fileid,
2830 : ret, done, "bad fileid\n");
2831 :
2832 : /*
2833 : * Do some modifications on the basefile (IO, setinfo), verifying
2834 : * File-ID after each step.
2835 : */
2836 0 : create = (struct smb2_create) {
2837 : .in.desired_access = SEC_FILE_ALL,
2838 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2839 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2840 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2841 : .in.fname = fname,
2842 : .in.query_on_disk_id = true,
2843 : };
2844 :
2845 0 : status = smb2_create(tree, tctx, &create);
2846 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2847 : "test file could not be created\n");
2848 0 : h1 = create.out.file.handle;
2849 :
2850 0 : status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
2851 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2852 : "smb2_util_write failed\n");
2853 :
2854 0 : finfo = (union smb_fileinfo) {
2855 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2856 : .generic.in.file.handle = h1,
2857 : };
2858 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2859 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2860 : "smb2_getinfo_file failed\n");
2861 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2862 : expected_fileid,
2863 : ret, done, "bad fileid\n");
2864 :
2865 0 : sinfo = (union smb_setfileinfo) {
2866 : .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
2867 : .basic_info.in.file.handle = h1,
2868 : };
2869 0 : unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
2870 :
2871 0 : status = smb2_setinfo_file(tree, &sinfo);
2872 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2873 : "smb2_setinfo_file failed\n");
2874 :
2875 0 : finfo = (union smb_fileinfo) {
2876 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2877 : .generic.in.file.handle = h1,
2878 : };
2879 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2880 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2881 : "smb2_getinfo_file failed\n");
2882 0 : smb2_util_close(tree, h1);
2883 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2884 : expected_fileid,
2885 : ret, done, "bad fileid\n");
2886 :
2887 : /*
2888 : * Create stream, check the stream's File-ID, should be the same as the
2889 : * base file (sic!, tested against Windows).
2890 : */
2891 0 : create = (struct smb2_create) {
2892 : .in.desired_access = SEC_FILE_ALL,
2893 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2894 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2895 : .in.create_disposition = NTCREATEX_DISP_CREATE,
2896 : .in.fname = sname,
2897 : .in.query_on_disk_id = true,
2898 : };
2899 :
2900 0 : status = smb2_create(tree, tctx, &create);
2901 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2902 : "test file could not be created\n");
2903 0 : h1 = create.out.file.handle;
2904 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2905 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2906 : ret, done, "bad fileid\n");
2907 :
2908 : /*
2909 : * Getinfo the File-ID on the created stream
2910 : */
2911 0 : finfo = (union smb_fileinfo) {
2912 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2913 : .generic.in.file.handle = h1,
2914 : };
2915 :
2916 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2917 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2918 : "smb2_getinfo_file failed\n");
2919 0 : smb2_util_close(tree, h1);
2920 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2921 : expected_fileid,
2922 : ret, done, "bad fileid\n");
2923 :
2924 : /*
2925 : * Open stream, check the stream's File-ID, should be the same as the
2926 : * base file (sic!, tested against Windows).
2927 : */
2928 0 : create = (struct smb2_create) {
2929 : .in.desired_access = SEC_FILE_ALL,
2930 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2931 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2932 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2933 : .in.fname = sname,
2934 : .in.query_on_disk_id = true,
2935 : };
2936 :
2937 0 : status = smb2_create(tree, tctx, &create);
2938 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2939 : "test file could not be created\n");
2940 0 : h1 = create.out.file.handle;
2941 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2942 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2943 : ret, done, "bad fileid\n");
2944 :
2945 : /*
2946 : * Getinfo the File-ID on the opened stream
2947 : */
2948 0 : finfo = (union smb_fileinfo) {
2949 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2950 : .generic.in.file.handle = h1,
2951 : };
2952 :
2953 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2954 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2955 : "smb2_getinfo_file failed\n");
2956 0 : smb2_util_close(tree, h1);
2957 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2958 : expected_fileid,
2959 : ret, done, "bad fileid\n");
2960 :
2961 : /*
2962 : * Overwrite stream, check the stream's File-ID, should be the same as
2963 : * the base file (sic!, tested against Windows).
2964 : */
2965 0 : create = (struct smb2_create) {
2966 : .in.desired_access = SEC_FILE_ALL,
2967 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2968 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2969 : .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
2970 : .in.fname = sname,
2971 : .in.query_on_disk_id = true,
2972 : };
2973 :
2974 0 : status = smb2_create(tree, tctx, &create);
2975 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2976 : "test file could not be created\n");
2977 0 : h1 = create.out.file.handle;
2978 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2979 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2980 : ret, done, "bad fileid\n");
2981 :
2982 : /*
2983 : * Getinfo the File-ID on the overwritten stream
2984 : */
2985 0 : finfo = (union smb_fileinfo) {
2986 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2987 : .generic.in.file.handle = h1,
2988 : };
2989 :
2990 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2991 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2992 : "smb2_getinfo_file failed\n");
2993 0 : smb2_util_close(tree, h1);
2994 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2995 : expected_fileid,
2996 : ret, done, "bad fileid\n");
2997 :
2998 : /*
2999 : * Do some modifications on the stream (IO, setinfo), verifying File-ID
3000 : * after earch step.
3001 : */
3002 0 : create = (struct smb2_create) {
3003 : .in.desired_access = SEC_FILE_ALL,
3004 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3005 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3006 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3007 : .in.fname = sname,
3008 : .in.query_on_disk_id = true,
3009 : };
3010 :
3011 0 : status = smb2_create(tree, tctx, &create);
3012 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3013 : "test file could not be created\n");
3014 0 : h1 = create.out.file.handle;
3015 :
3016 0 : status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
3017 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3018 : "smb2_util_write failed\n");
3019 :
3020 0 : finfo = (union smb_fileinfo) {
3021 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3022 : .generic.in.file.handle = h1,
3023 : };
3024 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3025 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3026 : "smb2_getinfo_file failed\n");
3027 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3028 : expected_fileid,
3029 : ret, done, "bad fileid\n");
3030 :
3031 0 : sinfo = (union smb_setfileinfo) {
3032 : .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
3033 : .basic_info.in.file.handle = h1,
3034 : };
3035 0 : unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
3036 :
3037 0 : status = smb2_setinfo_file(tree, &sinfo);
3038 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3039 : "smb2_setinfo_file failed\n");
3040 :
3041 0 : finfo = (union smb_fileinfo) {
3042 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3043 : .generic.in.file.handle = h1,
3044 : };
3045 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3046 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3047 : "smb2_getinfo_file failed\n");
3048 0 : smb2_util_close(tree, h1);
3049 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3050 : expected_fileid,
3051 : ret, done, "bad fileid\n");
3052 :
3053 : /*
3054 : * Final open of the basefile with QFID
3055 : */
3056 0 : create = (struct smb2_create) {
3057 : .in.desired_access = SEC_FILE_ALL,
3058 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3059 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3060 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3061 : .in.fname = fname,
3062 : .in.query_on_disk_id = true,
3063 : };
3064 :
3065 0 : status = smb2_create(tree, tctx, &create);
3066 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3067 : "test file could not be created\n");
3068 0 : h1 = create.out.file.handle;
3069 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
3070 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
3071 : ret, done, "bad fileid\n");
3072 :
3073 : /*
3074 : * Final Getinfo checking File-ID
3075 : */
3076 0 : finfo = (union smb_fileinfo) {
3077 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3078 : .generic.in.file.handle = h1,
3079 : };
3080 :
3081 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3082 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3083 : "torture_smb2_testdir\n");
3084 0 : smb2_util_close(tree, h1);
3085 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3086 : expected_fileid,
3087 : ret, done, "bad fileid\n");
3088 :
3089 : /*
3090 : * Final list directory, verifying the operations on basefile and stream
3091 : * didn't modify the base file metadata.
3092 : */
3093 0 : f = (struct smb2_find) {
3094 : .in.file.handle = testdirh,
3095 : .in.pattern = "foo",
3096 : .in.max_response_size = 0x1000,
3097 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
3098 : .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART,
3099 : };
3100 :
3101 0 : status = smb2_find_level(tree, tree, &f, &count, &d);
3102 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3103 : "smb2_find_level failed\n");
3104 0 : torture_assert_u64_equal_goto(tctx,
3105 : d->id_both_directory_info.file_id,
3106 : expected_fileid,
3107 : ret, done, "bad fileid\n");
3108 :
3109 0 : done:
3110 0 : smb2_util_close(tree, testdirh);
3111 0 : smb2_deltree(tree, DNAME);
3112 0 : talloc_free(mem_ctx);
3113 0 : return ret;
3114 : }
3115 :
3116 0 : static bool test_fileid_dir(struct torture_context *tctx,
3117 : struct smb2_tree *tree)
3118 : {
3119 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
3120 0 : const char *dname = DNAME "\\foo";
3121 0 : const char *sname = DNAME "\\foo:bar";
3122 : struct smb2_handle testdirh;
3123 : struct smb2_handle h1;
3124 : struct smb2_create create;
3125 : union smb_fileinfo finfo;
3126 : union smb_setfileinfo sinfo;
3127 : struct smb2_find f;
3128 : unsigned int count;
3129 : union smb_search_data *d;
3130 : uint64_t expected_fileid;
3131 : uint64_t returned_fileid;
3132 : NTSTATUS status;
3133 0 : bool ret = true;
3134 :
3135 0 : smb2_deltree(tree, DNAME);
3136 :
3137 0 : status = torture_smb2_testdir(tree, DNAME, &testdirh);
3138 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3139 : "torture_smb2_testdir failed\n");
3140 :
3141 : /*
3142 : * Initial directory create with QFID
3143 : */
3144 0 : create = (struct smb2_create) {
3145 : .in.desired_access = SEC_FILE_ALL,
3146 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3147 : .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
3148 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
3149 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
3150 : .in.fname = dname,
3151 : .in.query_on_disk_id = true,
3152 : };
3153 :
3154 0 : status = smb2_create(tree, tctx, &create);
3155 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3156 : "test file could not be created\n");
3157 0 : h1 = create.out.file.handle;
3158 0 : expected_fileid = BVAL(&create.out.on_disk_id, 0);
3159 :
3160 : /*
3161 : * Getinfo the File-ID on the just opened handle
3162 : */
3163 0 : finfo = (union smb_fileinfo) {
3164 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3165 : .generic.in.file.handle = h1,
3166 : };
3167 :
3168 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3169 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3170 : "torture_smb2_testdir\n");
3171 0 : smb2_util_close(tree, h1);
3172 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3173 : expected_fileid,
3174 : ret, done, "bad fileid\n");
3175 :
3176 : /*
3177 : * Open existing directory with QFID
3178 : */
3179 0 : create = (struct smb2_create) {
3180 : .in.desired_access = SEC_FILE_ALL,
3181 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3182 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3183 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
3184 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
3185 : .in.fname = dname,
3186 : .in.query_on_disk_id = true,
3187 : };
3188 :
3189 0 : status = smb2_create(tree, tctx, &create);
3190 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3191 : "test file could not be created\n");
3192 0 : h1 = create.out.file.handle;
3193 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
3194 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
3195 : ret, done, "bad fileid\n");
3196 :
3197 : /*
3198 : * Getinfo the File-ID on the just opened handle
3199 : */
3200 0 : finfo = (union smb_fileinfo) {
3201 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3202 : .generic.in.file.handle = h1,
3203 : };
3204 :
3205 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3206 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3207 : "torture_smb2_testdir\n");
3208 0 : smb2_util_close(tree, h1);
3209 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3210 : expected_fileid,
3211 : ret, done, "bad fileid\n");
3212 :
3213 : /*
3214 : * Create stream, check the stream's File-ID, should be the same as the
3215 : * base file (sic!, tested against Windows).
3216 : */
3217 0 : create = (struct smb2_create) {
3218 : .in.desired_access = SEC_FILE_ALL,
3219 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3220 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3221 : .in.create_disposition = NTCREATEX_DISP_CREATE,
3222 : .in.fname = sname,
3223 : .in.query_on_disk_id = true,
3224 : };
3225 :
3226 0 : status = smb2_create(tree, tctx, &create);
3227 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3228 : "test file could not be created\n");
3229 0 : h1 = create.out.file.handle;
3230 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
3231 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
3232 : ret, done, "bad fileid\n");
3233 :
3234 : /*
3235 : * Getinfo the File-ID on the created stream
3236 : */
3237 0 : finfo = (union smb_fileinfo) {
3238 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3239 : .generic.in.file.handle = h1,
3240 : };
3241 :
3242 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3243 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3244 : "smb2_getinfo_file failed\n");
3245 0 : smb2_util_close(tree, h1);
3246 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3247 : expected_fileid,
3248 : ret, done, "bad fileid\n");
3249 :
3250 : /*
3251 : * Open stream, check the stream's File-ID, should be the same as the
3252 : * base file (sic!, tested against Windows).
3253 : */
3254 0 : create = (struct smb2_create) {
3255 : .in.desired_access = SEC_FILE_ALL,
3256 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3257 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3258 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3259 : .in.fname = sname,
3260 : .in.query_on_disk_id = true,
3261 : };
3262 :
3263 0 : status = smb2_create(tree, tctx, &create);
3264 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3265 : "test file could not be created\n");
3266 0 : h1 = create.out.file.handle;
3267 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
3268 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
3269 : ret, done, "bad fileid\n");
3270 :
3271 : /*
3272 : * Getinfo the File-ID on the opened stream
3273 : */
3274 0 : finfo = (union smb_fileinfo) {
3275 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3276 : .generic.in.file.handle = h1,
3277 : };
3278 :
3279 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3280 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3281 : "smb2_getinfo_file failed\n");
3282 0 : smb2_util_close(tree, h1);
3283 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3284 : expected_fileid,
3285 : ret, done, "bad fileid\n");
3286 :
3287 : /*
3288 : * Overwrite stream, check the stream's File-ID, should be the same as
3289 : * the base file (sic!, tested against Windows).
3290 : */
3291 0 : create = (struct smb2_create) {
3292 : .in.desired_access = SEC_FILE_ALL,
3293 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3294 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3295 : .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
3296 : .in.fname = sname,
3297 : .in.query_on_disk_id = true,
3298 : };
3299 :
3300 0 : status = smb2_create(tree, tctx, &create);
3301 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3302 : "test file could not be created\n");
3303 0 : h1 = create.out.file.handle;
3304 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
3305 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
3306 : ret, done, "bad fileid\n");
3307 :
3308 : /*
3309 : * Getinfo the File-ID on the overwritten stream
3310 : */
3311 0 : finfo = (union smb_fileinfo) {
3312 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3313 : .generic.in.file.handle = h1,
3314 : };
3315 :
3316 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3317 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3318 : "smb2_getinfo_file failed\n");
3319 0 : smb2_util_close(tree, h1);
3320 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3321 : expected_fileid,
3322 : ret, done, "bad fileid\n");
3323 :
3324 : /*
3325 : * Do some modifications on the stream (IO, setinfo), verifying File-ID
3326 : * after earch step.
3327 : */
3328 0 : create = (struct smb2_create) {
3329 : .in.desired_access = SEC_FILE_ALL,
3330 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3331 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3332 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3333 : .in.fname = sname,
3334 : .in.query_on_disk_id = true,
3335 : };
3336 :
3337 0 : status = smb2_create(tree, tctx, &create);
3338 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3339 : "test file could not be created\n");
3340 0 : h1 = create.out.file.handle;
3341 :
3342 0 : status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
3343 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3344 : "smb2_util_write failed\n");
3345 :
3346 0 : finfo = (union smb_fileinfo) {
3347 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3348 : .generic.in.file.handle = h1,
3349 : };
3350 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3351 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3352 : "smb2_getinfo_file failed\n");
3353 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3354 : expected_fileid,
3355 : ret, done, "bad fileid\n");
3356 :
3357 0 : sinfo = (union smb_setfileinfo) {
3358 : .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
3359 : .basic_info.in.file.handle = h1,
3360 : };
3361 0 : unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
3362 :
3363 0 : status = smb2_setinfo_file(tree, &sinfo);
3364 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3365 : "smb2_setinfo_file failed\n");
3366 :
3367 0 : finfo = (union smb_fileinfo) {
3368 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3369 : .generic.in.file.handle = h1,
3370 : };
3371 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3372 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3373 : "smb2_getinfo_file failed\n");
3374 0 : smb2_util_close(tree, h1);
3375 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3376 : expected_fileid,
3377 : ret, done, "bad fileid\n");
3378 :
3379 : /*
3380 : * Final open of the directory with QFID
3381 : */
3382 0 : create = (struct smb2_create) {
3383 : .in.desired_access = SEC_FILE_ALL,
3384 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3385 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
3386 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
3387 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3388 : .in.fname = dname,
3389 : .in.query_on_disk_id = true,
3390 : };
3391 :
3392 0 : status = smb2_create(tree, tctx, &create);
3393 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3394 : "test file could not be created\n");
3395 0 : h1 = create.out.file.handle;
3396 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
3397 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
3398 : ret, done, "bad fileid\n");
3399 :
3400 : /*
3401 : * Final Getinfo checking File-ID
3402 : */
3403 0 : finfo = (union smb_fileinfo) {
3404 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3405 : .generic.in.file.handle = h1,
3406 : };
3407 :
3408 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3409 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3410 : "torture_smb2_testdir\n");
3411 0 : smb2_util_close(tree, h1);
3412 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3413 : expected_fileid,
3414 : ret, done, "bad fileid\n");
3415 :
3416 : /*
3417 : * Final list directory, verifying the operations on basefile and stream
3418 : * didn't modify the base file metadata.
3419 : */
3420 0 : f = (struct smb2_find) {
3421 : .in.file.handle = testdirh,
3422 : .in.pattern = "foo",
3423 : .in.max_response_size = 0x1000,
3424 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
3425 : .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART,
3426 : };
3427 :
3428 0 : status = smb2_find_level(tree, tree, &f, &count, &d);
3429 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3430 : "smb2_find_level failed\n");
3431 0 : torture_assert_u64_equal_goto(tctx,
3432 : d->id_both_directory_info.file_id,
3433 : expected_fileid,
3434 : ret, done, "bad fileid\n");
3435 :
3436 0 : done:
3437 0 : smb2_util_close(tree, testdirh);
3438 0 : smb2_deltree(tree, DNAME);
3439 0 : talloc_free(mem_ctx);
3440 0 : return ret;
3441 : }
3442 :
3443 0 : static bool test_fileid_unique_object(
3444 : struct torture_context *tctx,
3445 : struct smb2_tree *tree,
3446 : unsigned int num_objs,
3447 : bool create_dirs)
3448 0 : {
3449 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
3450 0 : char *fname = NULL;
3451 : struct smb2_handle testdirh;
3452 : struct smb2_handle h1;
3453 : struct smb2_create create;
3454 : unsigned int i;
3455 0 : uint64_t fileid_array[num_objs];
3456 : NTSTATUS status;
3457 0 : bool ret = true;
3458 :
3459 0 : smb2_deltree(tree, DNAME);
3460 :
3461 0 : status = torture_smb2_testdir(tree, DNAME, &testdirh);
3462 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3463 : "test_fileid_unique failed\n");
3464 0 : smb2_util_close(tree, testdirh);
3465 :
3466 : /* Create num_obj files as rapidly as we can. */
3467 0 : for (i = 0; i < num_objs; i++) {
3468 0 : fname = talloc_asprintf(mem_ctx,
3469 : "%s\\testfile.%u",
3470 : DNAME,
3471 : i);
3472 0 : torture_assert_goto(tctx,
3473 : fname != NULL,
3474 : ret,
3475 : done,
3476 : "talloc failed\n");
3477 :
3478 0 : create = (struct smb2_create) {
3479 : .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
3480 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3481 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3482 : .in.create_disposition = NTCREATEX_DISP_CREATE,
3483 : .in.fname = fname,
3484 : };
3485 :
3486 0 : if (create_dirs) {
3487 0 : create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
3488 0 : create.in.create_options = FILE_DIRECTORY_FILE;
3489 : }
3490 :
3491 0 : status = smb2_create(tree, tctx, &create);
3492 0 : if (!NT_STATUS_IS_OK(status)) {
3493 0 : torture_fail(tctx,
3494 : talloc_asprintf(tctx,
3495 : "test file %s could not be created\n",
3496 : fname));
3497 : TALLOC_FREE(fname);
3498 : ret = false;
3499 : goto done;
3500 : }
3501 :
3502 0 : h1 = create.out.file.handle;
3503 0 : smb2_util_close(tree, h1);
3504 0 : TALLOC_FREE(fname);
3505 : }
3506 :
3507 : /*
3508 : * Get the file ids.
3509 : */
3510 0 : for (i = 0; i < num_objs; i++) {
3511 : union smb_fileinfo finfo;
3512 :
3513 0 : fname = talloc_asprintf(mem_ctx,
3514 : "%s\\testfile.%u",
3515 : DNAME,
3516 : i);
3517 0 : torture_assert_goto(tctx,
3518 : fname != NULL,
3519 : ret,
3520 : done,
3521 : "talloc failed\n");
3522 :
3523 0 : create = (struct smb2_create) {
3524 : .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
3525 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3526 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3527 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3528 : .in.fname = fname,
3529 : };
3530 :
3531 0 : if (create_dirs) {
3532 0 : create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
3533 0 : create.in.create_options = FILE_DIRECTORY_FILE;
3534 : }
3535 :
3536 0 : status = smb2_create(tree, tctx, &create);
3537 0 : if (!NT_STATUS_IS_OK(status)) {
3538 0 : torture_fail(tctx,
3539 : talloc_asprintf(tctx,
3540 : "test file %s could not "
3541 : "be opened: %s\n",
3542 : fname,
3543 : nt_errstr(status)));
3544 : TALLOC_FREE(fname);
3545 : ret = false;
3546 : goto done;
3547 : }
3548 :
3549 0 : h1 = create.out.file.handle;
3550 :
3551 0 : finfo = (union smb_fileinfo) {
3552 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3553 : .generic.in.file.handle = h1,
3554 : };
3555 :
3556 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3557 0 : if (!NT_STATUS_IS_OK(status)) {
3558 0 : torture_fail(tctx,
3559 : talloc_asprintf(tctx,
3560 : "failed to get fileid for "
3561 : "test file %s: %s\n",
3562 : fname,
3563 : nt_errstr(status)));
3564 : TALLOC_FREE(fname);
3565 : ret = false;
3566 : goto done;
3567 : }
3568 0 : smb2_util_close(tree, h1);
3569 :
3570 0 : fileid_array[i] = finfo.all_info2.out.file_id;
3571 0 : TALLOC_FREE(fname);
3572 : }
3573 :
3574 : /* All returned fileids must be unique. 100 is small so brute force. */
3575 0 : for (i = 0; i < num_objs - 1; i++) {
3576 : unsigned int j;
3577 0 : for (j = i + 1; j < num_objs; j++) {
3578 0 : if (fileid_array[i] == fileid_array[j]) {
3579 0 : torture_fail(tctx,
3580 : talloc_asprintf(tctx,
3581 : "fileid %u == fileid %u (0x%"PRIu64")\n",
3582 : i,
3583 : j,
3584 : fileid_array[i]));
3585 : ret = false;
3586 : goto done;
3587 : }
3588 : }
3589 : }
3590 :
3591 0 : done:
3592 :
3593 0 : smb2_util_close(tree, testdirh);
3594 0 : smb2_deltree(tree, DNAME);
3595 0 : talloc_free(mem_ctx);
3596 0 : return ret;
3597 : }
3598 :
3599 0 : static bool test_fileid_unique(
3600 : struct torture_context *tctx,
3601 : struct smb2_tree *tree)
3602 : {
3603 0 : return test_fileid_unique_object(tctx, tree, 100, false);
3604 : }
3605 :
3606 0 : static bool test_fileid_unique_dir(
3607 : struct torture_context *tctx,
3608 : struct smb2_tree *tree)
3609 : {
3610 0 : return test_fileid_unique_object(tctx, tree, 100, true);
3611 : }
3612 :
3613 2 : static bool test_dosattr_tmp_dir(struct torture_context *tctx,
3614 : struct smb2_tree *tree)
3615 : {
3616 2 : bool ret = true;
3617 : NTSTATUS status;
3618 : struct smb2_create c;
3619 2 : struct smb2_handle h1 = {{0}};
3620 2 : const char *fname = DNAME;
3621 :
3622 2 : smb2_deltree(tree, fname);
3623 2 : smb2_util_rmdir(tree, fname);
3624 :
3625 2 : c = (struct smb2_create) {
3626 : .in.desired_access = SEC_RIGHTS_DIR_ALL,
3627 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
3628 : .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
3629 : .in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3630 : NTCREATEX_SHARE_ACCESS_WRITE |
3631 : NTCREATEX_SHARE_ACCESS_DELETE,
3632 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
3633 : .in.fname = DNAME,
3634 : };
3635 :
3636 2 : status = smb2_create(tree, tctx, &c);
3637 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3638 : "smb2_create\n");
3639 2 : h1 = c.out.file.handle;
3640 :
3641 : /* Try to set temporary attribute on directory */
3642 2 : SET_ATTRIB(FILE_ATTRIBUTE_TEMPORARY);
3643 :
3644 2 : torture_assert_ntstatus_equal_goto(tctx, status,
3645 : NT_STATUS_INVALID_PARAMETER,
3646 : ret, done,
3647 : "Unexpected setinfo result\n");
3648 :
3649 2 : done:
3650 2 : if (!smb2_util_handle_empty(h1)) {
3651 2 : smb2_util_close(tree, h1);
3652 : }
3653 2 : smb2_util_unlink(tree, fname);
3654 2 : smb2_deltree(tree, fname);
3655 :
3656 2 : return ret;
3657 : }
3658 :
3659 : /*
3660 : test opening quota fakefile handle and returned attributes
3661 : */
3662 2 : static bool test_smb2_open_quota_fake_file(struct torture_context *tctx,
3663 : struct smb2_tree *tree)
3664 : {
3665 2 : const char *fname = "$Extend\\$Quota:$Q:$INDEX_ALLOCATION";
3666 : struct smb2_create create;
3667 2 : struct smb2_handle h = {{0}};
3668 : NTSTATUS status;
3669 2 : bool ret = true;
3670 :
3671 2 : create = (struct smb2_create) {
3672 : .in.desired_access = SEC_RIGHTS_FILE_READ,
3673 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3674 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3675 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3676 : .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
3677 : .in.fname = fname,
3678 : };
3679 :
3680 2 : status = smb2_create(tree, tree, &create);
3681 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3682 : "smb2_create failed\n");
3683 1 : h = create.out.file.handle;
3684 :
3685 1 : torture_assert_u64_equal_goto(tctx,
3686 : create.out.file_attr,
3687 : FILE_ATTRIBUTE_HIDDEN
3688 : | FILE_ATTRIBUTE_SYSTEM
3689 : | FILE_ATTRIBUTE_DIRECTORY
3690 : | FILE_ATTRIBUTE_ARCHIVE,
3691 : ret,
3692 : done,
3693 : "Wrong attributes\n");
3694 :
3695 1 : torture_assert_u64_equal_goto(tctx,
3696 : create.out.create_time, 0,
3697 : ret,
3698 : done,
3699 : "create_time is not 0\n");
3700 1 : torture_assert_u64_equal_goto(tctx,
3701 : create.out.access_time, 0,
3702 : ret,
3703 : done,
3704 : "access_time is not 0\n");
3705 1 : torture_assert_u64_equal_goto(tctx,
3706 : create.out.write_time, 0,
3707 : ret,
3708 : done,
3709 : "write_time is not 0\n");
3710 1 : torture_assert_u64_equal_goto(tctx,
3711 : create.out.change_time, 0,
3712 : ret,
3713 : done,
3714 : "change_time is not 0\n");
3715 :
3716 1 : done:
3717 2 : smb2_util_close(tree, h);
3718 2 : return ret;
3719 : }
3720 :
3721 : /*
3722 : stress testing path base operations
3723 : e.g. contention on lockting.tdb records
3724 : */
3725 :
3726 : struct test_smb2_bench_path_contention_shared_conn;
3727 : struct test_smb2_bench_path_contention_shared_loop;
3728 :
3729 : struct test_smb2_bench_path_contention_shared_state {
3730 : struct torture_context *tctx;
3731 : size_t num_conns;
3732 : struct test_smb2_bench_path_contention_shared_conn *conns;
3733 : size_t num_loops;
3734 : struct test_smb2_bench_path_contention_shared_loop *loops;
3735 : struct timeval starttime;
3736 : int timecount;
3737 : int timelimit;
3738 : struct {
3739 : uint64_t num_finished;
3740 : double total_latency;
3741 : double min_latency;
3742 : double max_latency;
3743 : } opens;
3744 : struct {
3745 : uint64_t num_finished;
3746 : double total_latency;
3747 : double min_latency;
3748 : double max_latency;
3749 : } closes;
3750 : bool ok;
3751 : bool stop;
3752 : };
3753 :
3754 : struct test_smb2_bench_path_contention_shared_conn {
3755 : struct test_smb2_bench_path_contention_shared_state *state;
3756 : int idx;
3757 : struct smb2_tree *tree;
3758 : };
3759 :
3760 : struct test_smb2_bench_path_contention_shared_loop {
3761 : struct test_smb2_bench_path_contention_shared_state *state;
3762 : struct test_smb2_bench_path_contention_shared_conn *conn;
3763 : int idx;
3764 : struct tevent_immediate *im;
3765 : struct {
3766 : struct smb2_create io;
3767 : struct smb2_request *req;
3768 : struct timeval starttime;
3769 : uint64_t num_started;
3770 : uint64_t num_finished;
3771 : double total_latency;
3772 : double min_latency;
3773 : double max_latency;
3774 : } opens;
3775 : struct {
3776 : struct smb2_close io;
3777 : struct smb2_request *req;
3778 : struct timeval starttime;
3779 : uint64_t num_started;
3780 : uint64_t num_finished;
3781 : double total_latency;
3782 : double min_latency;
3783 : double max_latency;
3784 : } closes;
3785 : NTSTATUS error;
3786 : };
3787 :
3788 : static void test_smb2_bench_path_contention_loop_open(
3789 : struct test_smb2_bench_path_contention_shared_loop *loop);
3790 :
3791 8 : static void test_smb2_bench_path_contention_loop_start(struct tevent_context *ctx,
3792 : struct tevent_immediate *im,
3793 : void *private_data)
3794 : {
3795 8 : struct test_smb2_bench_path_contention_shared_loop *loop =
3796 : (struct test_smb2_bench_path_contention_shared_loop *)
3797 : private_data;
3798 :
3799 8 : test_smb2_bench_path_contention_loop_open(loop);
3800 8 : }
3801 :
3802 : static void test_smb2_bench_path_contention_loop_opened(struct smb2_request *req);
3803 :
3804 10752 : static void test_smb2_bench_path_contention_loop_open(
3805 : struct test_smb2_bench_path_contention_shared_loop *loop)
3806 : {
3807 10752 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
3808 :
3809 10752 : loop->opens.num_started += 1;
3810 10752 : loop->opens.starttime = timeval_current();
3811 10752 : loop->opens.req = smb2_create_send(loop->conn->tree, &loop->opens.io);
3812 10752 : torture_assert_goto(state->tctx, loop->opens.req != NULL,
3813 : state->ok, asserted, "smb2_create_send");
3814 :
3815 10752 : loop->opens.req->async.fn = test_smb2_bench_path_contention_loop_opened;
3816 10752 : loop->opens.req->async.private_data = loop;
3817 10752 : return;
3818 0 : asserted:
3819 0 : state->stop = true;
3820 : }
3821 :
3822 : static void test_smb2_bench_path_contention_loop_close(
3823 : struct test_smb2_bench_path_contention_shared_loop *loop);
3824 :
3825 10746 : static void test_smb2_bench_path_contention_loop_opened(struct smb2_request *req)
3826 : {
3827 10746 : struct test_smb2_bench_path_contention_shared_loop *loop =
3828 : (struct test_smb2_bench_path_contention_shared_loop *)
3829 : req->async.private_data;
3830 10746 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
3831 10746 : double latency = timeval_elapsed(&loop->opens.starttime);
3832 10746 : TALLOC_CTX *frame = talloc_stackframe();
3833 :
3834 10746 : torture_assert_goto(state->tctx, loop->opens.req == req,
3835 : state->ok, asserted, __location__);
3836 10746 : loop->error = smb2_create_recv(req, frame, &loop->opens.io);
3837 10746 : torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
3838 : state->ok, asserted, __location__);
3839 10746 : ZERO_STRUCT(loop->opens.io.out.blobs);
3840 10746 : SMB_ASSERT(latency >= 0.000001);
3841 :
3842 10746 : if (loop->opens.num_finished == 0) {
3843 : /* first round */
3844 8 : loop->opens.min_latency = latency;
3845 8 : loop->opens.max_latency = latency;
3846 : }
3847 :
3848 10746 : loop->opens.num_finished += 1;
3849 10746 : loop->opens.total_latency += latency;
3850 :
3851 10746 : if (latency < loop->opens.min_latency) {
3852 59 : loop->opens.min_latency = latency;
3853 : }
3854 :
3855 10746 : if (latency > loop->opens.max_latency) {
3856 25 : loop->opens.max_latency = latency;
3857 : }
3858 :
3859 10746 : TALLOC_FREE(frame);
3860 10746 : test_smb2_bench_path_contention_loop_close(loop);
3861 10746 : return;
3862 0 : asserted:
3863 0 : state->stop = true;
3864 0 : TALLOC_FREE(frame);
3865 : }
3866 :
3867 : static void test_smb2_bench_path_contention_loop_closed(struct smb2_request *req);
3868 :
3869 10746 : static void test_smb2_bench_path_contention_loop_close(
3870 : struct test_smb2_bench_path_contention_shared_loop *loop)
3871 : {
3872 10746 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
3873 :
3874 10746 : loop->closes.num_started += 1;
3875 10746 : loop->closes.starttime = timeval_current();
3876 10746 : loop->closes.io.in.file = loop->opens.io.out.file;
3877 10746 : loop->closes.req = smb2_close_send(loop->conn->tree, &loop->closes.io);
3878 10746 : torture_assert_goto(state->tctx, loop->closes.req != NULL,
3879 : state->ok, asserted, "smb2_close_send");
3880 :
3881 10746 : loop->closes.req->async.fn = test_smb2_bench_path_contention_loop_closed;
3882 10746 : loop->closes.req->async.private_data = loop;
3883 10746 : return;
3884 0 : asserted:
3885 0 : state->stop = true;
3886 : }
3887 :
3888 10744 : static void test_smb2_bench_path_contention_loop_closed(struct smb2_request *req)
3889 : {
3890 10744 : struct test_smb2_bench_path_contention_shared_loop *loop =
3891 : (struct test_smb2_bench_path_contention_shared_loop *)
3892 : req->async.private_data;
3893 10744 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
3894 10744 : double latency = timeval_elapsed(&loop->closes.starttime);
3895 :
3896 10744 : torture_assert_goto(state->tctx, loop->closes.req == req,
3897 : state->ok, asserted, __location__);
3898 10744 : loop->error = smb2_close_recv(req, &loop->closes.io);
3899 10744 : torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
3900 : state->ok, asserted, __location__);
3901 10744 : SMB_ASSERT(latency >= 0.000001);
3902 10744 : if (loop->closes.num_finished == 0) {
3903 : /* first round */
3904 8 : loop->closes.min_latency = latency;
3905 8 : loop->closes.max_latency = latency;
3906 : }
3907 10744 : loop->closes.num_finished += 1;
3908 :
3909 10744 : loop->closes.total_latency += latency;
3910 :
3911 10744 : if (latency < loop->closes.min_latency) {
3912 47 : loop->closes.min_latency = latency;
3913 : }
3914 :
3915 10744 : if (latency > loop->closes.max_latency) {
3916 39 : loop->closes.max_latency = latency;
3917 : }
3918 :
3919 10744 : test_smb2_bench_path_contention_loop_open(loop);
3920 10744 : return;
3921 0 : asserted:
3922 0 : state->stop = true;
3923 : }
3924 :
3925 2 : static void test_smb2_bench_path_contention_progress(struct tevent_context *ev,
3926 : struct tevent_timer *te,
3927 : struct timeval current_time,
3928 : void *private_data)
3929 : {
3930 2 : struct test_smb2_bench_path_contention_shared_state *state =
3931 : (struct test_smb2_bench_path_contention_shared_state *)private_data;
3932 2 : uint64_t num_opens = 0;
3933 2 : double total_open_latency = 0;
3934 2 : double min_open_latency = 0;
3935 2 : double max_open_latency = 0;
3936 2 : double avs_open_latency = 0;
3937 2 : uint64_t num_closes = 0;
3938 2 : double total_close_latency = 0;
3939 2 : double min_close_latency = 0;
3940 2 : double max_close_latency = 0;
3941 2 : double avs_close_latency = 0;
3942 : size_t i;
3943 :
3944 2 : state->timecount += 1;
3945 :
3946 10 : for (i=0;i<state->num_loops;i++) {
3947 8 : struct test_smb2_bench_path_contention_shared_loop *loop =
3948 8 : &state->loops[i];
3949 :
3950 8 : num_opens += loop->opens.num_finished;
3951 8 : total_open_latency += loop->opens.total_latency;
3952 8 : if (min_open_latency == 0.0 && loop->opens.min_latency != 0.0) {
3953 2 : min_open_latency = loop->opens.min_latency;
3954 : }
3955 8 : if (loop->opens.min_latency < min_open_latency) {
3956 0 : min_open_latency = loop->opens.min_latency;
3957 : }
3958 8 : if (max_open_latency == 0.0) {
3959 2 : max_open_latency = loop->opens.max_latency;
3960 : }
3961 8 : if (loop->opens.max_latency > max_open_latency) {
3962 3 : max_open_latency = loop->opens.max_latency;
3963 : }
3964 8 : loop->opens.num_finished = 0;
3965 8 : loop->opens.total_latency = 0.0;
3966 :
3967 8 : num_closes += loop->closes.num_finished;
3968 8 : total_close_latency += loop->closes.total_latency;
3969 8 : if (min_close_latency == 0.0 && loop->closes.min_latency != 0.0) {
3970 2 : min_close_latency = loop->closes.min_latency;
3971 : }
3972 8 : if (loop->closes.min_latency < min_close_latency) {
3973 0 : min_close_latency = loop->closes.min_latency;
3974 : }
3975 8 : if (max_close_latency == 0.0) {
3976 2 : max_close_latency = loop->closes.max_latency;
3977 : }
3978 8 : if (loop->closes.max_latency > max_close_latency) {
3979 2 : max_close_latency = loop->closes.max_latency;
3980 : }
3981 8 : loop->closes.num_finished = 0;
3982 8 : loop->closes.total_latency = 0.0;
3983 : }
3984 :
3985 2 : state->opens.num_finished += num_opens;
3986 2 : state->opens.total_latency += total_open_latency;
3987 2 : if (state->opens.min_latency == 0.0 && min_open_latency != 0.0) {
3988 2 : state->opens.min_latency = min_open_latency;
3989 : }
3990 2 : if (min_open_latency < state->opens.min_latency) {
3991 0 : state->opens.min_latency = min_open_latency;
3992 : }
3993 2 : if (state->opens.max_latency == 0.0) {
3994 2 : state->opens.max_latency = max_open_latency;
3995 : }
3996 2 : if (max_open_latency > state->opens.max_latency) {
3997 0 : state->opens.max_latency = max_open_latency;
3998 : }
3999 :
4000 2 : state->closes.num_finished += num_closes;
4001 2 : state->closes.total_latency += total_close_latency;
4002 2 : if (state->closes.min_latency == 0.0 && min_close_latency != 0.0) {
4003 2 : state->closes.min_latency = min_close_latency;
4004 : }
4005 2 : if (min_close_latency < state->closes.min_latency) {
4006 0 : state->closes.min_latency = min_close_latency;
4007 : }
4008 2 : if (state->closes.max_latency == 0.0) {
4009 2 : state->closes.max_latency = max_close_latency;
4010 : }
4011 2 : if (max_close_latency > state->closes.max_latency) {
4012 0 : state->closes.max_latency = max_close_latency;
4013 : }
4014 :
4015 2 : if (state->timecount < state->timelimit) {
4016 0 : te = tevent_add_timer(state->tctx->ev,
4017 : state,
4018 : timeval_current_ofs(1, 0),
4019 : test_smb2_bench_path_contention_progress,
4020 : state);
4021 0 : torture_assert_goto(state->tctx, te != NULL,
4022 : state->ok, asserted, "tevent_add_timer");
4023 :
4024 0 : if (!torture_setting_bool(state->tctx, "progress", true)) {
4025 0 : return;
4026 : }
4027 :
4028 0 : avs_open_latency = total_open_latency / num_opens;
4029 0 : avs_close_latency = total_close_latency / num_closes;
4030 :
4031 0 : torture_comment(state->tctx,
4032 : "%.2f second: "
4033 : "open[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
4034 : "close[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] \r",
4035 0 : timeval_elapsed(&state->starttime),
4036 : (unsigned long long)num_opens,
4037 : avs_open_latency,
4038 : min_open_latency,
4039 : max_open_latency,
4040 : (unsigned long long)num_closes,
4041 : avs_close_latency,
4042 : min_close_latency,
4043 : max_close_latency);
4044 0 : return;
4045 : }
4046 :
4047 2 : avs_open_latency = state->opens.total_latency / state->opens.num_finished;
4048 2 : avs_close_latency = state->closes.total_latency / state->closes.num_finished;
4049 2 : num_opens = state->opens.num_finished / state->timelimit;
4050 2 : num_closes = state->closes.num_finished / state->timelimit;
4051 :
4052 2 : torture_comment(state->tctx,
4053 : "%.2f second: "
4054 : "open[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
4055 : "close[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
4056 2 : timeval_elapsed(&state->starttime),
4057 : (unsigned long long)num_opens,
4058 : avs_open_latency,
4059 : state->opens.min_latency,
4060 : state->opens.max_latency,
4061 : (unsigned long long)num_closes,
4062 : avs_close_latency,
4063 : state->closes.min_latency,
4064 : state->closes.max_latency);
4065 :
4066 2 : asserted:
4067 2 : state->stop = true;
4068 : }
4069 :
4070 2 : static bool test_smb2_bench_path_contention_shared(struct torture_context *tctx,
4071 : struct smb2_tree *tree)
4072 : {
4073 2 : struct test_smb2_bench_path_contention_shared_state *state = NULL;
4074 2 : bool ret = true;
4075 2 : int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
4076 2 : int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
4077 : size_t i;
4078 2 : size_t li = 0;
4079 2 : int timelimit = torture_setting_int(tctx, "timelimit", 10);
4080 2 : const char *path = torture_setting_string(tctx, "bench_path", "");
4081 2 : struct smb2_create open_io = { .level = RAW_OPEN_SMB2, };
4082 2 : struct smb2_close close_io = { .level = RAW_CLOSE_SMB2, };
4083 2 : struct tevent_timer *te = NULL;
4084 : uint32_t timeout_msec;
4085 :
4086 2 : state = talloc_zero(tctx, struct test_smb2_bench_path_contention_shared_state);
4087 2 : torture_assert(tctx, state != NULL, __location__);
4088 2 : state->tctx = tctx;
4089 2 : state->num_conns = torture_nprocs;
4090 2 : state->conns = talloc_zero_array(state,
4091 : struct test_smb2_bench_path_contention_shared_conn,
4092 : state->num_conns);
4093 2 : torture_assert(tctx, state->conns != NULL, __location__);
4094 2 : state->num_loops = torture_nprocs * torture_qdepth;
4095 2 : state->loops = talloc_zero_array(state,
4096 : struct test_smb2_bench_path_contention_shared_loop,
4097 : state->num_loops);
4098 2 : torture_assert(tctx, state->loops != NULL, __location__);
4099 2 : state->ok = true;
4100 2 : state->timelimit = MAX(timelimit, 1);
4101 :
4102 2 : open_io.in.desired_access = SEC_DIR_READ_ATTRIBUTE;
4103 2 : open_io.in.alloc_size = 0;
4104 2 : open_io.in.file_attributes = 0;
4105 2 : open_io.in.share_access = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
4106 2 : open_io.in.create_disposition = FILE_OPEN;
4107 2 : open_io.in.create_options = FILE_OPEN_REPARSE_POINT;
4108 2 : open_io.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
4109 2 : open_io.in.security_flags = 0;
4110 2 : open_io.in.fname = path;
4111 2 : open_io.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
4112 2 : open_io.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
4113 :
4114 2 : timeout_msec = tree->session->transport->options.request_timeout * 1000;
4115 :
4116 2 : torture_comment(tctx, "Opening %zd connections\n", state->num_conns);
4117 :
4118 10 : for (i=0;i<state->num_conns;i++) {
4119 8 : struct smb2_tree *ct = NULL;
4120 8 : DATA_BLOB out_input_buffer = data_blob_null;
4121 8 : DATA_BLOB out_output_buffer = data_blob_null;
4122 : size_t pcli;
4123 :
4124 8 : state->conns[i].state = state;
4125 8 : state->conns[i].idx = i;
4126 :
4127 8 : if (!torture_smb2_connection(tctx, &ct)) {
4128 0 : torture_comment(tctx, "Failed opening %zd/%zd connections\n", i, state->num_conns);
4129 0 : return false;
4130 : }
4131 8 : state->conns[i].tree = talloc_steal(state->conns, ct);
4132 :
4133 8 : smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
4134 8 : smb2cli_ioctl(ct->session->transport->conn,
4135 : timeout_msec,
4136 8 : ct->session->smbXcli,
4137 8 : ct->smbXcli,
4138 : UINT64_MAX, /* in_fid_persistent */
4139 : UINT64_MAX, /* in_fid_volatile */
4140 : UINT32_MAX,
4141 : 0, /* in_max_input_length */
4142 : NULL, /* in_input_buffer */
4143 : 1, /* in_max_output_length */
4144 : NULL, /* in_output_buffer */
4145 : SMB2_IOCTL_FLAG_IS_FSCTL,
4146 : ct,
4147 : &out_input_buffer,
4148 : &out_output_buffer);
4149 8 : torture_assert(tctx,
4150 : smbXcli_conn_is_connected(ct->session->transport->conn),
4151 : "smbXcli_conn_is_connected");
4152 16 : for (pcli = 0; pcli < torture_qdepth; pcli++) {
4153 8 : struct test_smb2_bench_path_contention_shared_loop *loop = &state->loops[li];
4154 :
4155 8 : loop->idx = li++;
4156 8 : loop->state = state;
4157 8 : loop->conn = &state->conns[i];
4158 8 : loop->im = tevent_create_immediate(state->loops);
4159 8 : torture_assert(tctx, loop->im != NULL, __location__);
4160 8 : loop->opens.io = open_io;
4161 8 : loop->closes.io = close_io;
4162 :
4163 8 : tevent_schedule_immediate(loop->im,
4164 : tctx->ev,
4165 : test_smb2_bench_path_contention_loop_start,
4166 : loop);
4167 : }
4168 : }
4169 :
4170 2 : torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
4171 : state->num_conns, torture_qdepth, state->num_loops);
4172 :
4173 2 : torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
4174 :
4175 2 : state->starttime = timeval_current();
4176 :
4177 2 : te = tevent_add_timer(tctx->ev,
4178 : state,
4179 : timeval_current_ofs(1, 0),
4180 : test_smb2_bench_path_contention_progress,
4181 : state);
4182 2 : torture_assert(tctx, te != NULL, __location__);
4183 :
4184 80143 : while (!state->stop) {
4185 80141 : int rc = tevent_loop_once(tctx->ev);
4186 80141 : torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
4187 : }
4188 :
4189 2 : torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
4190 2 : TALLOC_FREE(state);
4191 2 : return ret;
4192 : }
4193 :
4194 : /**
4195 : Find Maximum Path Length
4196 : */
4197 0 : static bool generate_path(const size_t len,
4198 : char *buffer,
4199 : const size_t buf_len)
4200 : {
4201 : size_t i;
4202 :
4203 0 : if (len >= buf_len) {
4204 0 : return false;
4205 : }
4206 :
4207 0 : for (i = 0; i < len ; i++) {
4208 0 : buffer[i] = (char)(i % 10) + 48;
4209 : }
4210 0 : buffer[i] = '\0';
4211 0 : return true;
4212 : }
4213 :
4214 2 : static bool test_path_length_test(struct torture_context *tctx,
4215 : struct smb2_tree *tree)
4216 : {
4217 2 : const size_t max_name = 2048;
4218 2 : char *name = talloc_array(tctx, char, max_name);
4219 2 : struct smb2_handle fh = {{0}};
4220 2 : size_t length = 128;
4221 2 : size_t max_file_name = 0;
4222 2 : size_t max_path_length = 0;
4223 2 : char *path_ok = NULL;
4224 2 : char *path_next = NULL;
4225 2 : char *topdir = NULL;
4226 2 : bool is_interactive = torture_setting_bool(tctx, "interactive", false);
4227 : NTSTATUS status;
4228 2 : bool ret = true;
4229 :
4230 2 : if (!is_interactive) {
4231 2 : torture_result(tctx, TORTURE_SKIP,
4232 : "Interactive Test: Skipping... "
4233 : "(enable with --interactive)\n");
4234 2 : return ret;
4235 : }
4236 :
4237 0 : torture_comment(tctx, "Testing filename and path lengths\n");
4238 :
4239 : /* Find Longest File Name */
4240 0 : for (length = 128; length < max_name; length++) {
4241 0 : if (!generate_path(length, name, max_name)) {
4242 0 : torture_result(tctx, TORTURE_FAIL,
4243 : "Failed to generate path.");
4244 0 : return false;
4245 : }
4246 :
4247 0 : status = torture_smb2_testfile(tree, name, &fh);
4248 0 : if (!NT_STATUS_IS_OK(status)) {
4249 0 : break;
4250 : }
4251 :
4252 0 : smb2_util_close(tree, fh);
4253 0 : smb2_util_unlink(tree, name);
4254 :
4255 0 : max_file_name = length;
4256 : }
4257 :
4258 0 : torture_assert_int_not_equal_goto(tctx, length, max_name, ret, done,
4259 : "Name too big\n");
4260 :
4261 0 : torture_comment(tctx, "Max file name length: %zu\n", max_file_name);
4262 :
4263 : /* Remove one char that caused the failure above */
4264 0 : name[max_file_name] = '\0';
4265 :
4266 0 : path_ok = talloc_strdup(tree, name);
4267 0 : torture_assert_not_null_goto(tctx, path_ok, ret, done,
4268 : "talloc_strdup failed\n");
4269 :
4270 0 : topdir = talloc_strdup(tree, name);
4271 0 : torture_assert_not_null_goto(tctx, topdir, ret, done,
4272 : "talloc_strdup failed\n");
4273 :
4274 0 : status = smb2_util_mkdir(tree, path_ok);
4275 0 : if (!NT_STATUS_IS_OK(status)) {
4276 0 : torture_comment(tctx, "mkdir [%s] failed: %s\n",
4277 : path_ok, nt_errstr(status));
4278 0 : torture_result(tctx, TORTURE_FAIL, "Initial mkdir failed");
4279 0 : return false;
4280 : }
4281 :
4282 : while (true) {
4283 0 : path_next = talloc_asprintf(tctx, "%s\\%s", path_ok, name);
4284 0 : torture_assert_not_null_goto(tctx, path_next, ret, done,
4285 : "talloc_asprintf failed\n");
4286 :
4287 0 : status = smb2_util_mkdir(tree, path_next);
4288 0 : if (!NT_STATUS_IS_OK(status)) {
4289 0 : break;
4290 : }
4291 :
4292 0 : path_ok = path_next;
4293 : }
4294 :
4295 0 : for (length = 1; length < max_name; length++) {
4296 0 : if (!generate_path(length, name, max_name)) {
4297 0 : torture_result(tctx, TORTURE_FAIL,
4298 : "Failed to generate path.");
4299 0 : return false;
4300 : }
4301 :
4302 0 : path_next = talloc_asprintf(tctx, "%s\\%s", path_ok, name);
4303 0 : torture_assert_not_null_goto(tctx, path_next, ret, done,
4304 : "talloc_asprintf failed\n");
4305 :
4306 0 : status = torture_smb2_testfile(tree, path_next, &fh);
4307 0 : if (!NT_STATUS_IS_OK(status)) {
4308 0 : break;
4309 : }
4310 0 : smb2_util_close(tree, fh);
4311 0 : path_ok = path_next;
4312 : }
4313 :
4314 0 : max_path_length = talloc_array_length(path_ok);
4315 :
4316 0 : torture_comment(tctx, "Max path name length: %zu\n", max_path_length);
4317 :
4318 0 : done:
4319 0 : return ret;
4320 : }
4321 :
4322 : /*
4323 : basic testing of SMB2 read
4324 : */
4325 966 : struct torture_suite *torture_smb2_create_init(TALLOC_CTX *ctx)
4326 : {
4327 966 : struct torture_suite *suite = torture_suite_create(ctx, "create");
4328 :
4329 966 : torture_suite_add_1smb2_test(suite, "gentest", test_create_gentest);
4330 966 : torture_suite_add_1smb2_test(suite, "blob", test_create_blob);
4331 966 : torture_suite_add_1smb2_test(suite, "open", test_smb2_open);
4332 966 : torture_suite_add_1smb2_test(suite, "brlocked", test_smb2_open_brlocked);
4333 966 : torture_suite_add_1smb2_test(suite, "multi", test_smb2_open_multi);
4334 966 : torture_suite_add_1smb2_test(suite, "delete", test_smb2_open_for_delete);
4335 966 : torture_suite_add_1smb2_test(suite, "leading-slash", test_smb2_leading_slash);
4336 966 : torture_suite_add_1smb2_test(suite, "impersonation", test_smb2_impersonation_level);
4337 966 : torture_suite_add_1smb2_test(suite, "aclfile", test_create_acl_file);
4338 966 : torture_suite_add_1smb2_test(suite, "acldir", test_create_acl_dir);
4339 966 : torture_suite_add_1smb2_test(suite, "nulldacl", test_create_null_dacl);
4340 966 : torture_suite_add_1smb2_test(suite, "mkdir-dup", test_mkdir_dup);
4341 966 : torture_suite_add_1smb2_test(suite, "dir-alloc-size", test_dir_alloc_size);
4342 966 : torture_suite_add_1smb2_test(suite, "dosattr_tmp_dir", test_dosattr_tmp_dir);
4343 966 : torture_suite_add_1smb2_test(suite, "quota-fake-file", test_smb2_open_quota_fake_file);
4344 966 : torture_suite_add_1smb2_test(suite, "path-length", test_path_length_test);
4345 966 : torture_suite_add_1smb2_test(suite, "bench-path-contention-shared", test_smb2_bench_path_contention_shared);
4346 :
4347 966 : suite->description = talloc_strdup(suite, "SMB2-CREATE tests");
4348 :
4349 966 : return suite;
4350 : }
4351 :
4352 966 : struct torture_suite *torture_smb2_twrp_init(TALLOC_CTX *ctx)
4353 : {
4354 966 : struct torture_suite *suite = torture_suite_create(ctx, "twrp");
4355 :
4356 966 : torture_suite_add_1smb2_test(suite, "write", test_twrp_write);
4357 966 : torture_suite_add_1smb2_test(suite, "stream", test_twrp_stream);
4358 966 : torture_suite_add_1smb2_test(suite, "openroot", test_twrp_openroot);
4359 966 : torture_suite_add_1smb2_test(suite, "listdir", test_twrp_listdir);
4360 :
4361 966 : suite->description = talloc_strdup(suite, "SMB2-TWRP tests");
4362 :
4363 966 : return suite;
4364 : }
4365 :
4366 : /*
4367 : basic testing of SMB2 File-IDs
4368 : */
4369 966 : struct torture_suite *torture_smb2_fileid_init(TALLOC_CTX *ctx)
4370 : {
4371 966 : struct torture_suite *suite = torture_suite_create(ctx, "fileid");
4372 :
4373 966 : torture_suite_add_1smb2_test(suite, "fileid", test_fileid);
4374 966 : torture_suite_add_1smb2_test(suite, "fileid-dir", test_fileid_dir);
4375 966 : torture_suite_add_1smb2_test(suite, "unique", test_fileid_unique);
4376 966 : torture_suite_add_1smb2_test(suite, "unique-dir", test_fileid_unique_dir);
4377 :
4378 966 : suite->description = talloc_strdup(suite, "SMB2-FILEID tests");
4379 :
4380 966 : return suite;
4381 : }
4382 :
4383 966 : struct torture_suite *torture_smb2_bench_init(TALLOC_CTX *ctx)
4384 : {
4385 966 : struct torture_suite *suite = torture_suite_create(ctx, "bench");
4386 :
4387 966 : torture_suite_add_1smb2_test(suite, "oplock1", test_smb2_bench_oplock);
4388 966 : torture_suite_add_1smb2_test(suite, "path-contention-shared", test_smb2_bench_path_contention_shared);
4389 966 : torture_suite_add_1smb2_test(suite, "echo", test_smb2_bench_echo);
4390 :
4391 966 : suite->description = talloc_strdup(suite, "SMB2-BENCH tests");
4392 :
4393 966 : return suite;
4394 : }
4395 :
4396 0 : static bool test_no_stream(struct torture_context *tctx,
4397 : struct smb2_tree *tree)
4398 : {
4399 : struct smb2_create c;
4400 : NTSTATUS status;
4401 0 : bool ret = true;
4402 0 : const char *names[] = {
4403 : "test_no_stream::$DATA",
4404 : "test_no_stream::foooooooooooo",
4405 : "test_no_stream:stream",
4406 : "test_no_stream:stream:$DATA",
4407 : NULL
4408 : };
4409 : int i;
4410 :
4411 0 : for (i = 0; names[i] != NULL; i++) {
4412 0 : c = (struct smb2_create) {
4413 : .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
4414 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
4415 : .in.create_disposition = NTCREATEX_DISP_OPEN,
4416 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
4417 0 : .in.fname = names[i],
4418 : };
4419 :
4420 0 : status = smb2_create(tree, tctx, &c);
4421 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_INVALID)) {
4422 0 : torture_comment(
4423 : tctx, "Expected NT_STATUS_OBJECT_NAME_INVALID, "
4424 : "got %s, name: '%s'\n",
4425 : nt_errstr(status), names[i]);
4426 0 : torture_fail_goto(tctx, done, "Bad create result\n");
4427 : }
4428 : }
4429 0 : done:
4430 0 : return ret;
4431 : }
4432 :
4433 966 : struct torture_suite *torture_smb2_create_no_streams_init(TALLOC_CTX *ctx)
4434 : {
4435 966 : struct torture_suite *suite = torture_suite_create(ctx, "create_no_streams");
4436 :
4437 966 : torture_suite_add_1smb2_test(suite, "no_stream", test_no_stream);
4438 :
4439 966 : suite->description = talloc_strdup(suite, "SMB2-CREATE stream test on share without streams support");
4440 :
4441 966 : return suite;
4442 : }
|