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 0 : 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 51 : 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 : CHECK_VAL(io.smb2.out.alloc_size, 0);
1197 1 : smb2_util_unlink(tree, fname);
1198 :
1199 1 : done:
1200 1 : smb2_util_close(tree, h1);
1201 1 : smb2_util_unlink(tree, fname);
1202 1 : smb2_deltree(tree, DNAME);
1203 1 : return ret;
1204 : }
1205 :
1206 : /*
1207 : test with an already opened and byte range locked file
1208 : */
1209 :
1210 2 : static bool test_smb2_open_brlocked(struct torture_context *tctx,
1211 : struct smb2_tree *tree)
1212 : {
1213 : union smb_open io, io1;
1214 : union smb_lock io2;
1215 : struct smb2_lock_element lock[1];
1216 2 : const char *fname = DNAME "\\torture_ntcreatex.txt";
1217 : NTSTATUS status;
1218 2 : bool ret = true;
1219 : struct smb2_handle h;
1220 2 : char b = 42;
1221 :
1222 2 : torture_comment(tctx,
1223 : "Testing SMB2 open with a byte range locked file\n");
1224 :
1225 2 : smb2_util_unlink(tree, fname);
1226 :
1227 2 : status = torture_smb2_testdir(tree, DNAME, &h);
1228 2 : CHECK_STATUS(status, NT_STATUS_OK);
1229 :
1230 2 : ZERO_STRUCT(io.smb2);
1231 2 : io.generic.level = RAW_OPEN_SMB2;
1232 2 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1233 2 : io.smb2.in.desired_access = 0x2019f;
1234 2 : io.smb2.in.alloc_size = 0;
1235 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1236 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1237 : NTCREATEX_SHARE_ACCESS_WRITE;
1238 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1239 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1240 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1241 2 : io.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
1242 2 : io.smb2.in.fname = fname;
1243 :
1244 2 : status = smb2_create(tree, tctx, &(io.smb2));
1245 2 : CHECK_STATUS(status, NT_STATUS_OK);
1246 :
1247 2 : status = smb2_util_write(tree, io.smb2.out.file.handle, &b, 0, 1);
1248 2 : CHECK_STATUS(status, NT_STATUS_OK);
1249 :
1250 2 : ZERO_STRUCT(io2.smb2);
1251 2 : io2.smb2.level = RAW_LOCK_SMB2;
1252 2 : io2.smb2.in.file.handle = io.smb2.out.file.handle;
1253 2 : io2.smb2.in.lock_count = 1;
1254 :
1255 2 : ZERO_STRUCT(lock);
1256 2 : lock[0].offset = 0;
1257 2 : lock[0].length = 1;
1258 2 : lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1259 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1260 2 : io2.smb2.in.locks = &lock[0];
1261 2 : status = smb2_lock(tree, &(io2.smb2));
1262 2 : CHECK_STATUS(status, NT_STATUS_OK);
1263 :
1264 2 : ZERO_STRUCT(io1.smb2);
1265 2 : io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1266 2 : io1.smb2.in.desired_access = 0x20196;
1267 2 : io1.smb2.in.alloc_size = 0;
1268 2 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1269 2 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1270 : NTCREATEX_SHARE_ACCESS_WRITE;
1271 2 : io1.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1272 2 : io1.smb2.in.create_options = 0;
1273 2 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1274 2 : io1.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
1275 2 : io1.smb2.in.fname = fname;
1276 :
1277 2 : status = smb2_create(tree, tctx, &(io1.smb2));
1278 2 : CHECK_STATUS(status, NT_STATUS_OK);
1279 :
1280 2 : smb2_util_close(tree, io.smb2.out.file.handle);
1281 2 : smb2_util_close(tree, io1.smb2.out.file.handle);
1282 2 : smb2_util_unlink(tree, fname);
1283 2 : smb2_deltree(tree, DNAME);
1284 :
1285 2 : return ret;
1286 : }
1287 :
1288 : /* A little torture test to expose a race condition in Samba 3.0.20 ... :-) */
1289 :
1290 2 : static bool test_smb2_open_multi(struct torture_context *tctx,
1291 : struct smb2_tree *tree)
1292 : {
1293 2 : const char *fname = "test_oplock.dat";
1294 : NTSTATUS status;
1295 2 : bool ret = true;
1296 : union smb_open io;
1297 : struct smb2_tree **trees;
1298 : struct smb2_request **requests;
1299 : union smb_open *ios;
1300 2 : int i, num_files = 3;
1301 2 : int num_ok = 0;
1302 2 : int num_collision = 0;
1303 :
1304 2 : torture_comment(tctx,
1305 : "Testing SMB2 Open with multiple connections\n");
1306 2 : trees = talloc_array(tctx, struct smb2_tree *, num_files);
1307 2 : requests = talloc_array(tctx, struct smb2_request *, num_files);
1308 2 : ios = talloc_array(tctx, union smb_open, num_files);
1309 2 : if ((tctx->ev == NULL) || (trees == NULL) || (requests == NULL) ||
1310 : (ios == NULL)) {
1311 0 : torture_comment(tctx, ("talloc failed\n"));
1312 0 : ret = false;
1313 0 : goto done;
1314 : }
1315 :
1316 2 : tree->session->transport->options.request_timeout = 60;
1317 :
1318 8 : for (i=0; i<num_files; i++) {
1319 6 : if (!torture_smb2_connection(tctx, &(trees[i]))) {
1320 0 : torture_comment(tctx,
1321 : "Could not open %d'th connection\n", i);
1322 0 : ret = false;
1323 0 : goto done;
1324 : }
1325 6 : trees[i]->session->transport->options.request_timeout = 60;
1326 : }
1327 :
1328 : /* cleanup */
1329 2 : smb2_util_unlink(tree, fname);
1330 :
1331 : /*
1332 : base ntcreatex parms
1333 : */
1334 2 : ZERO_STRUCT(io.smb2);
1335 2 : io.generic.level = RAW_OPEN_SMB2;
1336 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1337 2 : io.smb2.in.alloc_size = 0;
1338 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1339 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1340 : NTCREATEX_SHARE_ACCESS_WRITE|
1341 : NTCREATEX_SHARE_ACCESS_DELETE;
1342 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1343 2 : io.smb2.in.create_options = 0;
1344 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1345 2 : io.smb2.in.security_flags = 0;
1346 2 : io.smb2.in.fname = fname;
1347 2 : io.smb2.in.create_flags = 0;
1348 :
1349 8 : for (i=0; i<num_files; i++) {
1350 6 : ios[i] = io;
1351 6 : requests[i] = smb2_create_send(trees[i], &(ios[i].smb2));
1352 6 : if (requests[i] == NULL) {
1353 0 : torture_comment(tctx,
1354 : "could not send %d'th request\n", i);
1355 0 : ret = false;
1356 0 : goto done;
1357 : }
1358 : }
1359 :
1360 2 : torture_comment(tctx, "waiting for replies\n");
1361 24 : while (1) {
1362 26 : bool unreplied = false;
1363 47 : for (i=0; i<num_files; i++) {
1364 45 : if (requests[i] == NULL) {
1365 15 : continue;
1366 : }
1367 30 : if (requests[i]->state < SMB2_REQUEST_DONE) {
1368 24 : unreplied = true;
1369 24 : break;
1370 : }
1371 6 : status = smb2_create_recv(requests[i], tctx,
1372 6 : &(ios[i].smb2));
1373 :
1374 6 : torture_comment(tctx,
1375 : "File %d returned status %s\n", i,
1376 : nt_errstr(status));
1377 :
1378 6 : if (NT_STATUS_IS_OK(status)) {
1379 2 : num_ok += 1;
1380 : }
1381 :
1382 6 : if (NT_STATUS_EQUAL(status,
1383 : NT_STATUS_OBJECT_NAME_COLLISION)) {
1384 4 : num_collision += 1;
1385 : }
1386 :
1387 6 : requests[i] = NULL;
1388 : }
1389 26 : if (!unreplied) {
1390 2 : break;
1391 : }
1392 :
1393 24 : if (tevent_loop_once(tctx->ev) != 0) {
1394 0 : torture_comment(tctx, "tevent_loop_once failed\n");
1395 0 : ret = false;
1396 0 : goto done;
1397 : }
1398 : }
1399 :
1400 2 : if ((num_ok != 1) || (num_ok + num_collision != num_files)) {
1401 0 : ret = false;
1402 : }
1403 4 : done:
1404 2 : smb2_deltree(tree, fname);
1405 :
1406 2 : return ret;
1407 : }
1408 :
1409 : /*
1410 : test opening for delete on a read-only attribute file.
1411 : */
1412 :
1413 2 : static bool test_smb2_open_for_delete(struct torture_context *tctx,
1414 : struct smb2_tree *tree)
1415 : {
1416 : union smb_open io;
1417 : union smb_fileinfo finfo;
1418 2 : const char *fname = DNAME "\\torture_open_for_delete.txt";
1419 : NTSTATUS status;
1420 : struct smb2_handle h, h1;
1421 2 : bool ret = true;
1422 :
1423 2 : torture_comment(tctx,
1424 : "Checking SMB2_OPEN for delete on a readonly file.\n");
1425 2 : smb2_util_unlink(tree, fname);
1426 2 : smb2_deltree(tree, fname);
1427 :
1428 2 : status = torture_smb2_testdir(tree, DNAME, &h);
1429 2 : CHECK_STATUS(status, NT_STATUS_OK);
1430 :
1431 : /* reasonable default parameters */
1432 2 : ZERO_STRUCT(io.smb2);
1433 2 : io.generic.level = RAW_OPEN_SMB2;
1434 2 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1435 2 : io.smb2.in.alloc_size = 0;
1436 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1437 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_READONLY;
1438 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1439 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1440 2 : io.smb2.in.create_options = 0;
1441 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1442 2 : io.smb2.in.security_flags = 0;
1443 2 : io.smb2.in.fname = fname;
1444 :
1445 : /* Create the readonly file. */
1446 :
1447 2 : status = smb2_create(tree, tctx, &(io.smb2));
1448 2 : CHECK_STATUS(status, NT_STATUS_OK);
1449 2 : h1 = io.smb2.out.file.handle;
1450 :
1451 2 : CHECK_VAL(io.smb2.out.oplock_level, 0);
1452 2 : io.smb2.in.create_options = 0;
1453 2 : CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
1454 2 : CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
1455 2 : smb2_util_close(tree, h1);
1456 :
1457 : /* Now try and open for delete only - should succeed. */
1458 2 : io.smb2.in.desired_access = SEC_STD_DELETE;
1459 2 : io.smb2.in.file_attributes = 0;
1460 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1461 : NTCREATEX_SHARE_ACCESS_WRITE |
1462 : NTCREATEX_SHARE_ACCESS_DELETE;
1463 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1464 2 : status = smb2_create(tree, tctx, &(io.smb2));
1465 2 : CHECK_STATUS(status, NT_STATUS_OK);
1466 2 : smb2_util_close(tree, io.smb2.out.file.handle);
1467 :
1468 : /* Clear readonly flag to allow file deletion */
1469 2 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1470 : SEC_FILE_WRITE_ATTRIBUTE;
1471 2 : status = smb2_create(tree, tctx, &(io.smb2));
1472 2 : CHECK_STATUS(status, NT_STATUS_OK);
1473 2 : h1 = io.smb2.out.file.handle;
1474 2 : SET_ATTRIB(FILE_ATTRIBUTE_ARCHIVE);
1475 2 : smb2_util_close(tree, h1);
1476 :
1477 2 : smb2_util_close(tree, h);
1478 2 : smb2_util_unlink(tree, fname);
1479 2 : smb2_deltree(tree, DNAME);
1480 :
1481 2 : return ret;
1482 : }
1483 :
1484 : /*
1485 : test SMB2 open with a leading slash on the path.
1486 : Trying to create a directory with a leading slash
1487 : should give NT_STATUS_INVALID_PARAMETER error
1488 : */
1489 2 : static bool test_smb2_leading_slash(struct torture_context *tctx,
1490 : struct smb2_tree *tree)
1491 : {
1492 : union smb_open io;
1493 2 : const char *dnameslash = "\\"DNAME;
1494 : NTSTATUS status;
1495 2 : bool ret = true;
1496 :
1497 2 : torture_comment(tctx,
1498 : "Trying to create a directory with leading slash on path\n");
1499 2 : smb2_deltree(tree, dnameslash);
1500 :
1501 2 : ZERO_STRUCT(io.smb2);
1502 2 : io.generic.level = RAW_OPEN_SMB2;
1503 2 : io.smb2.in.oplock_level = 0;
1504 2 : io.smb2.in.desired_access = SEC_RIGHTS_DIR_ALL;
1505 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1506 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1507 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1508 : NTCREATEX_SHARE_ACCESS_WRITE |
1509 : NTCREATEX_SHARE_ACCESS_DELETE;
1510 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1511 2 : io.smb2.in.fname = dnameslash;
1512 :
1513 2 : status = smb2_create(tree, tree, &(io.smb2));
1514 2 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1515 :
1516 2 : smb2_deltree(tree, dnameslash);
1517 2 : return ret;
1518 : }
1519 :
1520 : /*
1521 : test SMB2 open with an invalid impersonation level.
1522 : Should give NT_STATUS_BAD_IMPERSONATION_LEVEL error
1523 : */
1524 2 : static bool test_smb2_impersonation_level(struct torture_context *tctx,
1525 : struct smb2_tree *tree)
1526 : {
1527 : union smb_open io;
1528 2 : const char *fname = DNAME "\\torture_invalid_impersonation_level.txt";
1529 : NTSTATUS status;
1530 : struct smb2_handle h;
1531 2 : bool ret = true;
1532 :
1533 2 : torture_comment(tctx,
1534 : "Testing SMB2 open with an invalid impersonation level.\n");
1535 :
1536 2 : smb2_util_unlink(tree, fname);
1537 2 : smb2_util_rmdir(tree, DNAME);
1538 :
1539 2 : status = torture_smb2_testdir(tree, DNAME, &h);
1540 2 : CHECK_STATUS(status, NT_STATUS_OK);
1541 :
1542 2 : ZERO_STRUCT(io.smb2);
1543 2 : io.generic.level = RAW_OPEN_SMB2;
1544 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1545 2 : io.smb2.in.alloc_size = 0;
1546 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1547 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1548 : NTCREATEX_SHARE_ACCESS_WRITE|
1549 : NTCREATEX_SHARE_ACCESS_DELETE;
1550 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1551 2 : io.smb2.in.create_options = 0;
1552 2 : io.smb2.in.impersonation_level = 0x12345678;
1553 2 : io.smb2.in.security_flags = 0;
1554 2 : io.smb2.in.fname = fname;
1555 2 : io.smb2.in.create_flags = 0;
1556 :
1557 2 : status = smb2_create(tree, tree, &(io.smb2));
1558 2 : CHECK_STATUS(status, NT_STATUS_BAD_IMPERSONATION_LEVEL);
1559 :
1560 1 : smb2_util_close(tree, h);
1561 1 : smb2_util_unlink(tree, fname);
1562 1 : smb2_deltree(tree, DNAME);
1563 1 : return ret;
1564 : }
1565 :
1566 2 : static bool test_create_acl_file(struct torture_context *tctx,
1567 : struct smb2_tree *tree)
1568 : {
1569 2 : torture_comment(tctx, "Testing nttrans create with sec_desc on files\n");
1570 :
1571 2 : return test_create_acl_ext(tctx, tree, false);
1572 : }
1573 :
1574 2 : static bool test_create_acl_dir(struct torture_context *tctx,
1575 : struct smb2_tree *tree)
1576 : {
1577 2 : torture_comment(tctx, "Testing nttrans create with sec_desc on directories\n");
1578 :
1579 2 : return test_create_acl_ext(tctx, tree, true);
1580 : }
1581 :
1582 : #define CHECK_ACCESS_FLAGS(_fh, flags) do { \
1583 : union smb_fileinfo _q; \
1584 : _q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; \
1585 : _q.access_information.in.file.handle = (_fh); \
1586 : status = smb2_getinfo_file(tree, tctx, &_q); \
1587 : CHECK_STATUS(status, NT_STATUS_OK); \
1588 : if (_q.access_information.out.access_flags != (flags)) { \
1589 : torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect access_flags 0x%08x - should be 0x%08x\n", \
1590 : __location__, _q.access_information.out.access_flags, (flags)); \
1591 : ret = false; \
1592 : goto done; \
1593 : } \
1594 : } while (0)
1595 :
1596 : /*
1597 : * Test creating a file with a NULL DACL.
1598 : */
1599 2 : static bool test_create_null_dacl(struct torture_context *tctx,
1600 : struct smb2_tree *tree)
1601 : {
1602 : NTSTATUS status;
1603 : struct smb2_create io;
1604 2 : const char *fname = "nulldacl.txt";
1605 2 : bool ret = true;
1606 : struct smb2_handle handle;
1607 : union smb_fileinfo q;
1608 : union smb_setfileinfo s;
1609 2 : struct security_descriptor *sd = security_descriptor_initialise(tctx);
1610 : struct security_acl dacl;
1611 :
1612 2 : torture_comment(tctx, "TESTING SEC_DESC WITH A NULL DACL\n");
1613 :
1614 2 : smb2_util_unlink(tree, fname);
1615 :
1616 2 : ZERO_STRUCT(io);
1617 2 : io.level = RAW_OPEN_SMB2;
1618 2 : io.in.create_flags = 0;
1619 2 : io.in.desired_access = SEC_STD_READ_CONTROL | SEC_STD_WRITE_DAC
1620 : | SEC_STD_WRITE_OWNER;
1621 2 : io.in.create_options = 0;
1622 2 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1623 2 : io.in.share_access =
1624 : NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1625 2 : io.in.alloc_size = 0;
1626 2 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
1627 2 : io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
1628 2 : io.in.security_flags = 0;
1629 2 : io.in.fname = fname;
1630 2 : io.in.sec_desc = sd;
1631 : /* XXX create_options ? */
1632 2 : io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
1633 : NTCREATEX_OPTIONS_ASYNC_ALERT |
1634 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
1635 : 0x00200000;
1636 :
1637 2 : torture_comment(tctx, "creating a file with a empty sd\n");
1638 2 : status = smb2_create(tree, tctx, &io);
1639 2 : CHECK_STATUS(status, NT_STATUS_OK);
1640 2 : handle = io.out.file.handle;
1641 :
1642 2 : torture_comment(tctx, "get the original sd\n");
1643 2 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1644 2 : q.query_secdesc.in.file.handle = handle;
1645 2 : q.query_secdesc.in.secinfo_flags =
1646 : SECINFO_OWNER |
1647 : SECINFO_GROUP |
1648 : SECINFO_DACL;
1649 2 : status = smb2_getinfo_file(tree, tctx, &q);
1650 2 : CHECK_STATUS(status, NT_STATUS_OK);
1651 :
1652 : /*
1653 : * Testing the created DACL,
1654 : * the server should add the inherited DACL
1655 : * when SEC_DESC_DACL_PRESENT isn't specified
1656 : */
1657 2 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1658 0 : ret = false;
1659 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1660 : }
1661 2 : if (q.query_secdesc.out.sd->dacl == NULL) {
1662 0 : ret = false;
1663 0 : torture_fail_goto(tctx, done, "no DACL has been created on the server!\n");
1664 : }
1665 :
1666 2 : torture_comment(tctx, "set NULL DACL\n");
1667 2 : sd->type |= SEC_DESC_DACL_PRESENT;
1668 :
1669 2 : s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
1670 2 : s.set_secdesc.in.file.handle = handle;
1671 2 : s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
1672 2 : s.set_secdesc.in.sd = sd;
1673 2 : status = smb2_setinfo_file(tree, &s);
1674 2 : CHECK_STATUS(status, NT_STATUS_OK);
1675 :
1676 2 : torture_comment(tctx, "get the sd\n");
1677 2 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1678 2 : q.query_secdesc.in.file.handle = handle;
1679 2 : q.query_secdesc.in.secinfo_flags =
1680 : SECINFO_OWNER |
1681 : SECINFO_GROUP |
1682 : SECINFO_DACL;
1683 2 : status = smb2_getinfo_file(tree, tctx, &q);
1684 2 : CHECK_STATUS(status, NT_STATUS_OK);
1685 :
1686 : /* Testing the modified DACL */
1687 2 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1688 0 : ret = false;
1689 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1690 : }
1691 2 : if (q.query_secdesc.out.sd->dacl != NULL) {
1692 0 : ret = false;
1693 0 : torture_fail_goto(tctx, done, "DACL has been created on the server!\n");
1694 : }
1695 :
1696 2 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
1697 :
1698 2 : torture_comment(tctx, "try open for read control\n");
1699 2 : io.in.desired_access = SEC_STD_READ_CONTROL;
1700 2 : status = smb2_create(tree, tctx, &io);
1701 2 : CHECK_STATUS(status, NT_STATUS_OK);
1702 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1703 : SEC_STD_READ_CONTROL);
1704 2 : smb2_util_close(tree, io.out.file.handle);
1705 :
1706 2 : torture_comment(tctx, "try open for write\n");
1707 2 : io.in.desired_access = SEC_FILE_WRITE_DATA;
1708 2 : status = smb2_create(tree, tctx, &io);
1709 2 : CHECK_STATUS(status, NT_STATUS_OK);
1710 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1711 : SEC_FILE_WRITE_DATA);
1712 2 : smb2_util_close(tree, io.out.file.handle);
1713 :
1714 2 : torture_comment(tctx, "try open for read\n");
1715 2 : io.in.desired_access = SEC_FILE_READ_DATA;
1716 2 : status = smb2_create(tree, tctx, &io);
1717 2 : CHECK_STATUS(status, NT_STATUS_OK);
1718 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1719 : SEC_FILE_READ_DATA);
1720 2 : smb2_util_close(tree, io.out.file.handle);
1721 :
1722 2 : torture_comment(tctx, "try open for generic write\n");
1723 2 : io.in.desired_access = SEC_GENERIC_WRITE;
1724 2 : status = smb2_create(tree, tctx, &io);
1725 2 : CHECK_STATUS(status, NT_STATUS_OK);
1726 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1727 : SEC_RIGHTS_FILE_WRITE);
1728 2 : smb2_util_close(tree, io.out.file.handle);
1729 :
1730 2 : torture_comment(tctx, "try open for generic read\n");
1731 2 : io.in.desired_access = SEC_GENERIC_READ;
1732 2 : status = smb2_create(tree, tctx, &io);
1733 2 : CHECK_STATUS(status, NT_STATUS_OK);
1734 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1735 : SEC_RIGHTS_FILE_READ);
1736 2 : smb2_util_close(tree, io.out.file.handle);
1737 :
1738 2 : torture_comment(tctx, "set DACL with 0 aces\n");
1739 2 : ZERO_STRUCT(dacl);
1740 2 : dacl.revision = SECURITY_ACL_REVISION_NT4;
1741 2 : dacl.num_aces = 0;
1742 2 : sd->dacl = &dacl;
1743 :
1744 2 : s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
1745 2 : s.set_secdesc.in.file.handle = handle;
1746 2 : s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
1747 2 : s.set_secdesc.in.sd = sd;
1748 2 : status = smb2_setinfo_file(tree, &s);
1749 2 : CHECK_STATUS(status, NT_STATUS_OK);
1750 :
1751 2 : torture_comment(tctx, "get the sd\n");
1752 2 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1753 2 : q.query_secdesc.in.file.handle = handle;
1754 2 : q.query_secdesc.in.secinfo_flags =
1755 : SECINFO_OWNER |
1756 : SECINFO_GROUP |
1757 : SECINFO_DACL;
1758 2 : status = smb2_getinfo_file(tree, tctx, &q);
1759 2 : CHECK_STATUS(status, NT_STATUS_OK);
1760 :
1761 : /* Testing the modified DACL */
1762 2 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1763 0 : ret = false;
1764 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1765 : }
1766 2 : if (q.query_secdesc.out.sd->dacl == NULL) {
1767 0 : ret = false;
1768 0 : torture_fail_goto(tctx, done, "no DACL has been created on the server!\n");
1769 : }
1770 2 : if (q.query_secdesc.out.sd->dacl->num_aces != 0) {
1771 0 : torture_result(tctx, TORTURE_FAIL, "DACL has %u aces!\n",
1772 0 : q.query_secdesc.out.sd->dacl->num_aces);
1773 0 : ret = false;
1774 0 : goto done;
1775 : }
1776 :
1777 2 : torture_comment(tctx, "try open for read control\n");
1778 2 : io.in.desired_access = SEC_STD_READ_CONTROL;
1779 2 : status = smb2_create(tree, tctx, &io);
1780 2 : CHECK_STATUS(status, NT_STATUS_OK);
1781 2 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1782 : SEC_STD_READ_CONTROL);
1783 2 : smb2_util_close(tree, io.out.file.handle);
1784 :
1785 2 : torture_comment(tctx, "try open for write => access_denied\n");
1786 2 : io.in.desired_access = SEC_FILE_WRITE_DATA;
1787 2 : status = smb2_create(tree, tctx, &io);
1788 2 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1789 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1790 : } else {
1791 2 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1792 : }
1793 :
1794 2 : torture_comment(tctx, "try open for read => access_denied\n");
1795 2 : io.in.desired_access = SEC_FILE_READ_DATA;
1796 2 : status = smb2_create(tree, tctx, &io);
1797 2 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1798 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1799 : } else {
1800 2 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1801 : }
1802 :
1803 2 : torture_comment(tctx, "try open for generic write => access_denied\n");
1804 2 : io.in.desired_access = SEC_GENERIC_WRITE;
1805 2 : status = smb2_create(tree, tctx, &io);
1806 2 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1807 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1808 : } else {
1809 2 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1810 : }
1811 :
1812 2 : torture_comment(tctx, "try open for generic read => access_denied\n");
1813 2 : io.in.desired_access = SEC_GENERIC_READ;
1814 2 : status = smb2_create(tree, tctx, &io);
1815 2 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1816 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1817 : } else {
1818 2 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1819 : }
1820 :
1821 2 : torture_comment(tctx, "set empty sd\n");
1822 2 : sd->type &= ~SEC_DESC_DACL_PRESENT;
1823 2 : sd->dacl = NULL;
1824 :
1825 2 : s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
1826 2 : s.set_secdesc.in.file.handle = handle;
1827 2 : s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
1828 2 : s.set_secdesc.in.sd = sd;
1829 2 : status = smb2_setinfo_file(tree, &s);
1830 2 : CHECK_STATUS(status, NT_STATUS_OK);
1831 :
1832 2 : torture_comment(tctx, "get the sd\n");
1833 2 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1834 2 : q.query_secdesc.in.file.handle = handle;
1835 2 : q.query_secdesc.in.secinfo_flags =
1836 : SECINFO_OWNER |
1837 : SECINFO_GROUP |
1838 : SECINFO_DACL;
1839 2 : status = smb2_getinfo_file(tree, tctx, &q);
1840 2 : CHECK_STATUS(status, NT_STATUS_OK);
1841 :
1842 : /* Testing the modified DACL */
1843 2 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1844 0 : ret = false;
1845 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1846 : }
1847 2 : if (q.query_secdesc.out.sd->dacl != NULL) {
1848 0 : ret = false;
1849 0 : torture_fail_goto(tctx, done, "DACL has been created on the server!\n");
1850 : }
1851 4 : done:
1852 2 : smb2_util_close(tree, handle);
1853 2 : smb2_util_unlink(tree, fname);
1854 2 : smb2_tdis(tree);
1855 2 : smb2_logoff(tree->session);
1856 2 : return ret;
1857 : }
1858 :
1859 : /*
1860 : test SMB2 mkdir with OPEN_IF on the same name twice.
1861 : Must use 2 connections to hit the race.
1862 : */
1863 :
1864 2 : static bool test_mkdir_dup(struct torture_context *tctx,
1865 : struct smb2_tree *tree)
1866 : {
1867 2 : const char *fname = "mkdir_dup";
1868 : NTSTATUS status;
1869 2 : bool ret = true;
1870 : union smb_open io;
1871 : struct smb2_tree **trees;
1872 : struct smb2_request **requests;
1873 : union smb_open *ios;
1874 2 : int i, num_files = 2;
1875 2 : int num_ok = 0;
1876 2 : int num_created = 0;
1877 2 : int num_existed = 0;
1878 :
1879 2 : torture_comment(tctx,
1880 : "Testing SMB2 Create Directory with multiple connections\n");
1881 2 : trees = talloc_array(tctx, struct smb2_tree *, num_files);
1882 2 : requests = talloc_array(tctx, struct smb2_request *, num_files);
1883 2 : ios = talloc_array(tctx, union smb_open, num_files);
1884 2 : if ((tctx->ev == NULL) || (trees == NULL) || (requests == NULL) ||
1885 : (ios == NULL)) {
1886 0 : torture_fail(tctx, ("talloc failed\n"));
1887 : ret = false;
1888 : goto done;
1889 : }
1890 :
1891 2 : tree->session->transport->options.request_timeout = 60;
1892 :
1893 6 : for (i=0; i<num_files; i++) {
1894 4 : if (!torture_smb2_connection(tctx, &(trees[i]))) {
1895 0 : torture_fail(tctx,
1896 : talloc_asprintf(tctx,
1897 : "Could not open %d'th connection\n", i));
1898 : ret = false;
1899 : goto done;
1900 : }
1901 4 : trees[i]->session->transport->options.request_timeout = 60;
1902 : }
1903 :
1904 : /* cleanup */
1905 2 : smb2_util_unlink(tree, fname);
1906 2 : smb2_util_rmdir(tree, fname);
1907 :
1908 : /*
1909 : base ntcreatex parms
1910 : */
1911 2 : ZERO_STRUCT(io.smb2);
1912 2 : io.generic.level = RAW_OPEN_SMB2;
1913 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1914 2 : io.smb2.in.alloc_size = 0;
1915 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1916 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1917 : NTCREATEX_SHARE_ACCESS_WRITE|
1918 : NTCREATEX_SHARE_ACCESS_DELETE;
1919 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1920 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1921 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1922 2 : io.smb2.in.security_flags = 0;
1923 2 : io.smb2.in.fname = fname;
1924 2 : io.smb2.in.create_flags = 0;
1925 :
1926 6 : for (i=0; i<num_files; i++) {
1927 4 : ios[i] = io;
1928 4 : requests[i] = smb2_create_send(trees[i], &(ios[i].smb2));
1929 4 : if (requests[i] == NULL) {
1930 0 : torture_fail(tctx,
1931 : talloc_asprintf(tctx,
1932 : "could not send %d'th request\n", i));
1933 : ret = false;
1934 : goto done;
1935 : }
1936 : }
1937 :
1938 2 : torture_comment(tctx, "waiting for replies\n");
1939 16 : while (1) {
1940 18 : bool unreplied = false;
1941 24 : for (i=0; i<num_files; i++) {
1942 22 : if (requests[i] == NULL) {
1943 2 : continue;
1944 : }
1945 20 : if (requests[i]->state < SMB2_REQUEST_DONE) {
1946 16 : unreplied = true;
1947 16 : break;
1948 : }
1949 4 : status = smb2_create_recv(requests[i], tctx,
1950 4 : &(ios[i].smb2));
1951 :
1952 4 : if (NT_STATUS_IS_OK(status)) {
1953 4 : num_ok += 1;
1954 :
1955 4 : if (ios[i].smb2.out.create_action ==
1956 : NTCREATEX_ACTION_CREATED) {
1957 2 : num_created++;
1958 : }
1959 4 : if (ios[i].smb2.out.create_action ==
1960 : NTCREATEX_ACTION_EXISTED) {
1961 2 : num_existed++;
1962 : }
1963 : } else {
1964 0 : torture_fail(tctx,
1965 : talloc_asprintf(tctx,
1966 : "File %d returned status %s\n", i,
1967 : nt_errstr(status)));
1968 : }
1969 :
1970 :
1971 4 : requests[i] = NULL;
1972 : }
1973 18 : if (!unreplied) {
1974 2 : break;
1975 : }
1976 :
1977 16 : if (tevent_loop_once(tctx->ev) != 0) {
1978 0 : torture_fail(tctx, "tevent_loop_once failed\n");
1979 : ret = false;
1980 : goto done;
1981 : }
1982 : }
1983 :
1984 2 : if (num_ok != 2) {
1985 0 : torture_fail(tctx,
1986 : talloc_asprintf(tctx,
1987 : "num_ok == %d\n", num_ok));
1988 : ret = false;
1989 : }
1990 2 : if (num_created != 1) {
1991 0 : torture_fail(tctx,
1992 : talloc_asprintf(tctx,
1993 : "num_created == %d\n", num_created));
1994 : ret = false;
1995 : }
1996 2 : if (num_existed != 1) {
1997 0 : torture_fail(tctx,
1998 : talloc_asprintf(tctx,
1999 : "num_existed == %d\n", num_existed));
2000 : ret = false;
2001 : }
2002 2 : done:
2003 2 : smb2_deltree(tree, fname);
2004 :
2005 2 : return ret;
2006 : }
2007 :
2008 : /*
2009 : test directory creation with an initial allocation size > 0
2010 : */
2011 2 : static bool test_dir_alloc_size(struct torture_context *tctx,
2012 : struct smb2_tree *tree)
2013 : {
2014 2 : bool ret = true;
2015 2 : const char *dname = DNAME "\\torture_alloc_size.dir";
2016 : NTSTATUS status;
2017 : struct smb2_create c;
2018 2 : struct smb2_handle h1 = {{0}}, h2;
2019 :
2020 2 : torture_comment(tctx, "Checking initial allocation size on directories\n");
2021 :
2022 2 : smb2_deltree(tree, dname);
2023 :
2024 2 : status = torture_smb2_testdir(tree, DNAME, &h1);
2025 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed");
2026 :
2027 2 : ZERO_STRUCT(c);
2028 2 : c.in.create_disposition = NTCREATEX_DISP_CREATE;
2029 2 : c.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
2030 2 : c.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
2031 2 : c.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2032 2 : c.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2033 2 : c.in.fname = dname;
2034 : /*
2035 : * An insanely large value so we can check the value is
2036 : * ignored: Samba either returns 0 (current behaviour), or,
2037 : * once vfswrap_get_alloc_size() is fixed to allow retrieving
2038 : * the allocated size for directories, returns
2039 : * smb_roundup(..., stat.st_size) which would be 1 MB by
2040 : * default.
2041 : *
2042 : * Windows returns 0 for empty directories, once directories
2043 : * have a few entries it starts replying with values > 0.
2044 : */
2045 2 : c.in.alloc_size = 1024*1024*1024;
2046 :
2047 2 : status = smb2_create(tree, tctx, &c);
2048 2 : h2 = c.out.file.handle;
2049 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2050 : "dir create with initial alloc size failed");
2051 :
2052 2 : smb2_util_close(tree, h2);
2053 :
2054 2 : torture_comment(tctx, "Got directory alloc size: %ju\n", (uintmax_t)c.out.alloc_size);
2055 :
2056 : /*
2057 : * See above for the rational for this test
2058 : */
2059 2 : if (c.out.alloc_size > 1024*1024) {
2060 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "bad alloc size: %ju",
2061 : (uintmax_t)c.out.alloc_size));
2062 : }
2063 :
2064 4 : done:
2065 2 : if (!smb2_util_handle_empty(h1)) {
2066 2 : smb2_util_close(tree, h1);
2067 : }
2068 2 : smb2_deltree(tree, DNAME);
2069 2 : return ret;
2070 : }
2071 :
2072 0 : static bool test_twrp_write(struct torture_context *tctx, struct smb2_tree *tree)
2073 : {
2074 : struct smb2_create io;
2075 0 : struct smb2_handle h1 = {{0}};
2076 : NTSTATUS status;
2077 0 : bool ret = true;
2078 0 : char *p = NULL;
2079 : struct tm tm;
2080 : time_t t;
2081 : uint64_t nttime;
2082 0 : const char *file = NULL;
2083 0 : const char *snapshot = NULL;
2084 :
2085 0 : file = torture_setting_string(tctx, "twrp_file", NULL);
2086 0 : if (file == NULL) {
2087 0 : torture_skip(tctx, "missing 'twrp_file' option\n");
2088 : }
2089 :
2090 0 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
2091 0 : if (snapshot == NULL) {
2092 0 : torture_skip(tctx, "missing 'twrp_snapshot' option\n");
2093 : }
2094 :
2095 0 : torture_comment(tctx, "Testing timewarp (%s) (%s)\n", file, snapshot);
2096 :
2097 0 : setenv("TZ", "GMT", 1);
2098 :
2099 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2100 : * effect if it is greather than 1. */
2101 0 : ZERO_STRUCT(tm);
2102 :
2103 0 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
2104 0 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
2105 0 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
2106 :
2107 0 : t = mktime(&tm);
2108 0 : unix_to_nt_time(&nttime, t);
2109 :
2110 0 : io = (struct smb2_create) {
2111 : .in.desired_access = SEC_FILE_READ_DATA,
2112 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2113 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2114 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2115 : .in.fname = file,
2116 : .in.query_maximal_access = true,
2117 : .in.timewarp = nttime,
2118 : };
2119 :
2120 0 : status = smb2_create(tree, tctx, &io);
2121 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2122 : "smb2_create\n");
2123 0 : smb2_util_close(tree, io.out.file.handle);
2124 :
2125 0 : ret = io.out.maximal_access & (SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA);
2126 0 : torture_assert_goto(tctx, ret, ret, done, "Bad access\n");
2127 :
2128 0 : io = (struct smb2_create) {
2129 : .in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA,
2130 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2131 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2132 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2133 : .in.fname = file,
2134 : .in.timewarp = nttime,
2135 : };
2136 :
2137 0 : status = smb2_create(tree, tctx, &io);
2138 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2139 : "smb2_create\n");
2140 0 : h1 = io.out.file.handle;
2141 :
2142 0 : status = smb2_util_write(tree, h1, "123", 0, 3);
2143 0 : torture_assert_ntstatus_equal_goto(tctx, status,
2144 : NT_STATUS_MEDIA_WRITE_PROTECTED,
2145 : ret, done, "smb2_create\n");
2146 :
2147 0 : smb2_util_close(tree, h1);
2148 :
2149 0 : done:
2150 0 : return ret;
2151 : }
2152 :
2153 0 : static bool test_twrp_stream(struct torture_context *tctx,
2154 : struct smb2_tree *tree)
2155 : {
2156 : struct smb2_create io;
2157 : NTSTATUS status;
2158 0 : bool ret = true;
2159 0 : char *p = NULL;
2160 : struct tm tm;
2161 : time_t t;
2162 : uint64_t nttime;
2163 0 : const char *file = NULL;
2164 0 : const char *stream = NULL;
2165 0 : const char *snapshot = NULL;
2166 : int stream_size;
2167 0 : char *path = NULL;
2168 0 : uint8_t *buf = NULL;
2169 0 : struct smb2_handle h1 = {{0}};
2170 : struct smb2_read r;
2171 :
2172 0 : file = torture_setting_string(tctx, "twrp_file", NULL);
2173 0 : if (file == NULL) {
2174 0 : torture_skip(tctx, "missing 'twrp_file' option\n");
2175 : }
2176 :
2177 0 : stream = torture_setting_string(tctx, "twrp_stream", NULL);
2178 0 : if (stream == NULL) {
2179 0 : torture_skip(tctx, "missing 'twrp_stream' option\n");
2180 : }
2181 :
2182 0 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
2183 0 : if (snapshot == NULL) {
2184 0 : torture_skip(tctx, "missing 'twrp_snapshot' option\n");
2185 : }
2186 :
2187 0 : stream_size = torture_setting_int(tctx, "twrp_stream_size", 0);
2188 0 : if (stream_size == 0) {
2189 0 : torture_skip(tctx, "missing 'twrp_stream_size' option\n");
2190 : }
2191 :
2192 0 : torture_comment(tctx, "Testing timewarp on stream (%s) (%s)\n",
2193 : file, snapshot);
2194 :
2195 0 : path = talloc_asprintf(tree, "%s:%s", file, stream);
2196 0 : torture_assert_not_null_goto(tctx, path, ret, done, "path\n");
2197 :
2198 0 : buf = talloc_zero_array(tree, uint8_t, stream_size);
2199 0 : torture_assert_not_null_goto(tctx, buf, ret, done, "buf\n");
2200 :
2201 0 : setenv("TZ", "GMT", 1);
2202 :
2203 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2204 : * effect if it is greather than 1. */
2205 0 : ZERO_STRUCT(tm);
2206 :
2207 0 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
2208 0 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
2209 0 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
2210 :
2211 0 : t = mktime(&tm);
2212 0 : unix_to_nt_time(&nttime, t);
2213 :
2214 0 : io = (struct smb2_create) {
2215 : .in.desired_access = SEC_FILE_READ_DATA,
2216 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2217 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2218 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2219 : .in.fname = path,
2220 : .in.timewarp = nttime,
2221 : };
2222 :
2223 0 : status = smb2_create(tree, tctx, &io);
2224 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2225 : "smb2_create\n");
2226 0 : h1 = io.out.file.handle;
2227 :
2228 0 : r = (struct smb2_read) {
2229 : .in.file.handle = h1,
2230 : .in.length = stream_size,
2231 : .in.offset = 0,
2232 : };
2233 :
2234 0 : status = smb2_read(tree, tree, &r);
2235 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2236 : "smb2_create\n");
2237 :
2238 0 : smb2_util_close(tree, h1);
2239 :
2240 0 : done:
2241 0 : return ret;
2242 : }
2243 :
2244 0 : static bool test_twrp_openroot(struct torture_context *tctx, struct smb2_tree *tree)
2245 : {
2246 : struct smb2_create io;
2247 : NTSTATUS status;
2248 0 : bool ret = true;
2249 0 : char *p = NULL;
2250 : struct tm tm;
2251 : time_t t;
2252 : uint64_t nttime;
2253 0 : const char *snapshot = NULL;
2254 :
2255 0 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
2256 0 : if (snapshot == NULL) {
2257 0 : torture_skip(tctx, "missing 'twrp_snapshot' option\n");
2258 : }
2259 :
2260 0 : torture_comment(tctx, "Testing open of root of "
2261 : "share with timewarp (%s)\n",
2262 : snapshot);
2263 :
2264 0 : setenv("TZ", "GMT", 1);
2265 :
2266 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2267 : * effect if it is greather than 1. */
2268 0 : ZERO_STRUCT(tm);
2269 :
2270 0 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
2271 0 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
2272 0 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
2273 :
2274 0 : t = mktime(&tm);
2275 0 : unix_to_nt_time(&nttime, t);
2276 :
2277 0 : io = (struct smb2_create) {
2278 : .in.desired_access = SEC_FILE_READ_DATA,
2279 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2280 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2281 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2282 : .in.fname = "",
2283 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2284 : .in.timewarp = nttime,
2285 : };
2286 :
2287 0 : status = smb2_create(tree, tctx, &io);
2288 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2289 : "smb2_create\n");
2290 0 : smb2_util_close(tree, io.out.file.handle);
2291 :
2292 0 : done:
2293 0 : return ret;
2294 : }
2295 :
2296 0 : static bool test_twrp_listdir(struct torture_context *tctx,
2297 : struct smb2_tree *tree)
2298 : {
2299 : struct smb2_create create;
2300 0 : struct smb2_handle h = {{0}};
2301 : struct smb2_find find;
2302 : unsigned int count;
2303 : union smb_search_data *d;
2304 0 : char *p = NULL;
2305 : struct tm tm;
2306 : time_t t;
2307 : uint64_t nttime;
2308 0 : const char *snapshot = NULL;
2309 : uint64_t normal_fileid;
2310 : uint64_t snapshot_fileid;
2311 : NTSTATUS status;
2312 0 : bool ret = true;
2313 :
2314 0 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
2315 0 : if (snapshot == NULL) {
2316 0 : torture_fail(tctx, "missing 'twrp_snapshot' option\n");
2317 : }
2318 :
2319 0 : torture_comment(tctx, "Testing File-Ids of directory listing "
2320 : "with timewarp (%s)\n",
2321 : snapshot);
2322 :
2323 0 : setenv("TZ", "GMT", 1);
2324 :
2325 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2326 : * effect if it is greather than 1. */
2327 0 : ZERO_STRUCT(tm);
2328 :
2329 0 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
2330 0 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
2331 0 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
2332 :
2333 0 : t = mktime(&tm);
2334 0 : unix_to_nt_time(&nttime, t);
2335 :
2336 : /*
2337 : * 1: Query the file's File-Id
2338 : */
2339 0 : create = (struct smb2_create) {
2340 : .in.desired_access = SEC_FILE_READ_DATA,
2341 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2342 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2343 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2344 : .in.fname = "subdir/hardlink",
2345 : .in.query_on_disk_id = true,
2346 : };
2347 :
2348 0 : status = smb2_create(tree, tctx, &create);
2349 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2350 : "test file could not be created\n");
2351 0 : smb2_util_close(tree, create.out.file.handle);
2352 0 : normal_fileid = BVAL(&create.out.on_disk_id, 0);
2353 :
2354 : /*
2355 : * 2: check directory listing of the file returns same File-Id
2356 : */
2357 :
2358 0 : create = (struct smb2_create) {
2359 : .in.desired_access = SEC_DIR_LIST,
2360 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2361 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2362 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2363 : .in.fname = "subdir",
2364 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2365 : };
2366 :
2367 0 : status = smb2_create(tree, tctx, &create);
2368 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2369 : "smb2_create\n");
2370 0 : h = create.out.file.handle;
2371 :
2372 0 : find = (struct smb2_find) {
2373 : .in.file.handle = h,
2374 : .in.pattern = "*",
2375 : .in.max_response_size = 0x1000,
2376 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
2377 : };
2378 :
2379 0 : status = smb2_find_level(tree, tree, &find, &count, &d);
2380 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2381 : "smb2_find_level failed\n");
2382 :
2383 0 : smb2_util_close(tree, h);
2384 :
2385 0 : torture_assert_int_equal_goto(tctx, count, 3, ret, done, "Bad count\n");
2386 0 : torture_assert_str_equal_goto(tctx,
2387 : d[2].id_both_directory_info.name.s,
2388 : "hardlink",
2389 : ret, done, "bad name");
2390 0 : torture_assert_u64_equal_goto(tctx,
2391 : d[2].id_both_directory_info.file_id,
2392 : normal_fileid,
2393 : ret, done, "bad fileid\n");
2394 :
2395 : /*
2396 : * 3: Query File-Id of snapshot of the file and check the File-Id is
2397 : * different compared to the basefile
2398 : */
2399 :
2400 0 : create = (struct smb2_create) {
2401 : .in.desired_access = SEC_FILE_READ_DATA,
2402 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2403 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2404 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2405 : .in.fname = "subdir/hardlink",
2406 : .in.query_on_disk_id = true,
2407 : .in.timewarp = nttime,
2408 : };
2409 :
2410 0 : status = smb2_create(tree, tctx, &create);
2411 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2412 : "test file could not be created\n");
2413 0 : smb2_util_close(tree, create.out.file.handle);
2414 :
2415 0 : snapshot_fileid = BVAL(&create.out.on_disk_id, 0);
2416 :
2417 : /*
2418 : * 4: List directory of the snapshot and check the File-Id returned here
2419 : * is the same as in 3.
2420 : */
2421 :
2422 0 : create = (struct smb2_create) {
2423 : .in.desired_access = SEC_DIR_LIST,
2424 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2425 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2426 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2427 : .in.fname = "subdir",
2428 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2429 : .in.timewarp = nttime,
2430 : };
2431 :
2432 0 : status = smb2_create(tree, tctx, &create);
2433 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2434 : "smb2_create\n");
2435 0 : h = create.out.file.handle;
2436 :
2437 0 : find = (struct smb2_find) {
2438 : .in.file.handle = h,
2439 : .in.pattern = "*",
2440 : .in.max_response_size = 0x1000,
2441 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
2442 : };
2443 :
2444 0 : status = smb2_find_level(tree, tree, &find, &count, &d);
2445 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2446 : "smb2_find_level failed\n");
2447 0 : smb2_util_close(tree, h);
2448 :
2449 0 : torture_assert_int_equal_goto(tctx, count, 3, ret, done, "Bad count\n");
2450 0 : torture_assert_str_equal_goto(tctx,
2451 : d[2].id_both_directory_info.name.s,
2452 : "hardlink",
2453 : ret, done, "bad name");
2454 0 : torture_assert_u64_equal_goto(tctx,
2455 : snapshot_fileid,
2456 : d[2].id_both_directory_info.file_id,
2457 : ret, done, "bad fileid\n");
2458 :
2459 0 : done:
2460 0 : return ret;
2461 : }
2462 :
2463 0 : static bool test_fileid(struct torture_context *tctx,
2464 : struct smb2_tree *tree)
2465 : {
2466 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2467 0 : const char *fname = DNAME "\\foo";
2468 0 : const char *sname = DNAME "\\foo:bar";
2469 : struct smb2_handle testdirh;
2470 : struct smb2_handle h1;
2471 : struct smb2_create create;
2472 : union smb_fileinfo finfo;
2473 : union smb_setfileinfo sinfo;
2474 : struct smb2_find f;
2475 : unsigned int count;
2476 : union smb_search_data *d;
2477 : uint64_t expected_fileid;
2478 : uint64_t returned_fileid;
2479 : NTSTATUS status;
2480 0 : bool ret = true;
2481 :
2482 0 : smb2_deltree(tree, DNAME);
2483 :
2484 0 : status = torture_smb2_testdir(tree, DNAME, &testdirh);
2485 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2486 : "torture_smb2_testdir failed\n");
2487 :
2488 : /*
2489 : * Initial create with QFID
2490 : */
2491 0 : create = (struct smb2_create) {
2492 : .in.desired_access = SEC_FILE_ALL,
2493 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2494 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2495 : .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
2496 : .in.fname = fname,
2497 : .in.query_on_disk_id = true,
2498 : };
2499 :
2500 0 : status = smb2_create(tree, tctx, &create);
2501 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2502 : "test file could not be created\n");
2503 0 : h1 = create.out.file.handle;
2504 0 : expected_fileid = BVAL(&create.out.on_disk_id, 0);
2505 :
2506 : /*
2507 : * Getinfo the File-ID on the just opened handle
2508 : */
2509 0 : finfo = (union smb_fileinfo) {
2510 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2511 : .generic.in.file.handle = h1,
2512 : };
2513 :
2514 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2515 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2516 : "torture_smb2_testdir\n");
2517 0 : smb2_util_close(tree, h1);
2518 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2519 : expected_fileid,
2520 : ret, done, "bad fileid\n");
2521 :
2522 : /*
2523 : * Open existing with QFID
2524 : */
2525 0 : create = (struct smb2_create) {
2526 : .in.desired_access = SEC_FILE_ALL,
2527 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2528 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2529 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2530 : .in.fname = fname,
2531 : .in.query_on_disk_id = true,
2532 : };
2533 :
2534 0 : status = smb2_create(tree, tctx, &create);
2535 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2536 : "test file could not be created\n");
2537 0 : h1 = create.out.file.handle;
2538 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2539 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2540 : ret, done, "bad fileid\n");
2541 :
2542 : /*
2543 : * Getinfo the File-ID on the just opened handle
2544 : */
2545 0 : finfo = (union smb_fileinfo) {
2546 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2547 : .generic.in.file.handle = h1,
2548 : };
2549 :
2550 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2551 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2552 : "torture_smb2_testdir\n");
2553 0 : smb2_util_close(tree, h1);
2554 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2555 : expected_fileid,
2556 : ret, done, "bad fileid\n");
2557 :
2558 : /*
2559 : * Overwrite with QFID
2560 : */
2561 0 : create = (struct smb2_create) {
2562 : .in.desired_access = SEC_FILE_ALL,
2563 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2564 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2565 : .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
2566 : .in.fname = fname,
2567 : .in.query_on_disk_id = true,
2568 : };
2569 :
2570 0 : status = smb2_create(tree, tctx, &create);
2571 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2572 : "test file could not be created\n");
2573 0 : h1 = create.out.file.handle;
2574 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2575 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2576 : ret, done, "bad fileid\n");
2577 :
2578 : /*
2579 : * Getinfo the File-ID on the open with overwrite handle
2580 : */
2581 0 : finfo = (union smb_fileinfo) {
2582 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2583 : .generic.in.file.handle = h1,
2584 : };
2585 :
2586 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2587 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2588 : "torture_smb2_testdir\n");
2589 0 : smb2_util_close(tree, h1);
2590 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2591 : expected_fileid,
2592 : ret, done, "bad fileid\n");
2593 :
2594 : /*
2595 : * Do some modifications on the basefile (IO, setinfo), verifying
2596 : * File-ID after each step.
2597 : */
2598 0 : create = (struct smb2_create) {
2599 : .in.desired_access = SEC_FILE_ALL,
2600 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2601 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2602 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2603 : .in.fname = fname,
2604 : .in.query_on_disk_id = true,
2605 : };
2606 :
2607 0 : status = smb2_create(tree, tctx, &create);
2608 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2609 : "test file could not be created\n");
2610 0 : h1 = create.out.file.handle;
2611 :
2612 0 : status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
2613 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2614 : "smb2_util_write failed\n");
2615 :
2616 0 : finfo = (union smb_fileinfo) {
2617 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2618 : .generic.in.file.handle = h1,
2619 : };
2620 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2621 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2622 : "smb2_getinfo_file failed\n");
2623 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2624 : expected_fileid,
2625 : ret, done, "bad fileid\n");
2626 :
2627 0 : sinfo = (union smb_setfileinfo) {
2628 : .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
2629 : .basic_info.in.file.handle = h1,
2630 : };
2631 0 : unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
2632 :
2633 0 : status = smb2_setinfo_file(tree, &sinfo);
2634 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2635 : "smb2_setinfo_file failed\n");
2636 :
2637 0 : finfo = (union smb_fileinfo) {
2638 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2639 : .generic.in.file.handle = h1,
2640 : };
2641 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2642 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2643 : "smb2_getinfo_file failed\n");
2644 0 : smb2_util_close(tree, h1);
2645 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2646 : expected_fileid,
2647 : ret, done, "bad fileid\n");
2648 :
2649 : /*
2650 : * Create stream, check the stream's File-ID, should be the same as the
2651 : * base file (sic!, tested against Windows).
2652 : */
2653 0 : create = (struct smb2_create) {
2654 : .in.desired_access = SEC_FILE_ALL,
2655 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2656 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2657 : .in.create_disposition = NTCREATEX_DISP_CREATE,
2658 : .in.fname = sname,
2659 : .in.query_on_disk_id = true,
2660 : };
2661 :
2662 0 : status = smb2_create(tree, tctx, &create);
2663 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2664 : "test file could not be created\n");
2665 0 : h1 = create.out.file.handle;
2666 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2667 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2668 : ret, done, "bad fileid\n");
2669 :
2670 : /*
2671 : * Getinfo the File-ID on the created stream
2672 : */
2673 0 : finfo = (union smb_fileinfo) {
2674 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2675 : .generic.in.file.handle = h1,
2676 : };
2677 :
2678 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2679 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2680 : "smb2_getinfo_file failed\n");
2681 0 : smb2_util_close(tree, h1);
2682 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2683 : expected_fileid,
2684 : ret, done, "bad fileid\n");
2685 :
2686 : /*
2687 : * Open stream, check the stream's File-ID, should be the same as the
2688 : * base file (sic!, tested against Windows).
2689 : */
2690 0 : create = (struct smb2_create) {
2691 : .in.desired_access = SEC_FILE_ALL,
2692 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2693 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2694 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2695 : .in.fname = sname,
2696 : .in.query_on_disk_id = true,
2697 : };
2698 :
2699 0 : status = smb2_create(tree, tctx, &create);
2700 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2701 : "test file could not be created\n");
2702 0 : h1 = create.out.file.handle;
2703 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2704 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2705 : ret, done, "bad fileid\n");
2706 :
2707 : /*
2708 : * Getinfo the File-ID on the opened stream
2709 : */
2710 0 : finfo = (union smb_fileinfo) {
2711 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2712 : .generic.in.file.handle = h1,
2713 : };
2714 :
2715 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2716 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2717 : "smb2_getinfo_file failed\n");
2718 0 : smb2_util_close(tree, h1);
2719 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2720 : expected_fileid,
2721 : ret, done, "bad fileid\n");
2722 :
2723 : /*
2724 : * Overwrite stream, check the stream's File-ID, should be the same as
2725 : * the base file (sic!, tested against Windows).
2726 : */
2727 0 : create = (struct smb2_create) {
2728 : .in.desired_access = SEC_FILE_ALL,
2729 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2730 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2731 : .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
2732 : .in.fname = sname,
2733 : .in.query_on_disk_id = true,
2734 : };
2735 :
2736 0 : status = smb2_create(tree, tctx, &create);
2737 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2738 : "test file could not be created\n");
2739 0 : h1 = create.out.file.handle;
2740 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2741 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2742 : ret, done, "bad fileid\n");
2743 :
2744 : /*
2745 : * Getinfo the File-ID on the overwritten stream
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 : "smb2_getinfo_file failed\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 : * Do some modifications on the stream (IO, setinfo), verifying File-ID
2762 : * after earch step.
2763 : */
2764 0 : create = (struct smb2_create) {
2765 : .in.desired_access = SEC_FILE_ALL,
2766 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2767 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2768 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2769 : .in.fname = sname,
2770 : .in.query_on_disk_id = true,
2771 : };
2772 :
2773 0 : status = smb2_create(tree, tctx, &create);
2774 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2775 : "test file could not be created\n");
2776 0 : h1 = create.out.file.handle;
2777 :
2778 0 : status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
2779 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2780 : "smb2_util_write failed\n");
2781 :
2782 0 : finfo = (union smb_fileinfo) {
2783 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2784 : .generic.in.file.handle = h1,
2785 : };
2786 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2787 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2788 : "smb2_getinfo_file failed\n");
2789 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2790 : expected_fileid,
2791 : ret, done, "bad fileid\n");
2792 :
2793 0 : sinfo = (union smb_setfileinfo) {
2794 : .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
2795 : .basic_info.in.file.handle = h1,
2796 : };
2797 0 : unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
2798 :
2799 0 : status = smb2_setinfo_file(tree, &sinfo);
2800 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2801 : "smb2_setinfo_file failed\n");
2802 :
2803 0 : finfo = (union smb_fileinfo) {
2804 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2805 : .generic.in.file.handle = h1,
2806 : };
2807 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2808 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2809 : "smb2_getinfo_file failed\n");
2810 0 : smb2_util_close(tree, h1);
2811 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2812 : expected_fileid,
2813 : ret, done, "bad fileid\n");
2814 :
2815 : /*
2816 : * Final open of the basefile with QFID
2817 : */
2818 0 : create = (struct smb2_create) {
2819 : .in.desired_access = SEC_FILE_ALL,
2820 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2821 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2822 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2823 : .in.fname = fname,
2824 : .in.query_on_disk_id = true,
2825 : };
2826 :
2827 0 : status = smb2_create(tree, tctx, &create);
2828 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2829 : "test file could not be created\n");
2830 0 : h1 = create.out.file.handle;
2831 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2832 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2833 : ret, done, "bad fileid\n");
2834 :
2835 : /*
2836 : * Final Getinfo checking File-ID
2837 : */
2838 0 : finfo = (union smb_fileinfo) {
2839 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2840 : .generic.in.file.handle = h1,
2841 : };
2842 :
2843 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2844 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2845 : "torture_smb2_testdir\n");
2846 0 : smb2_util_close(tree, h1);
2847 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2848 : expected_fileid,
2849 : ret, done, "bad fileid\n");
2850 :
2851 : /*
2852 : * Final list directory, verifying the operations on basefile and stream
2853 : * didn't modify the base file metadata.
2854 : */
2855 0 : f = (struct smb2_find) {
2856 : .in.file.handle = testdirh,
2857 : .in.pattern = "foo",
2858 : .in.max_response_size = 0x1000,
2859 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
2860 : .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART,
2861 : };
2862 :
2863 0 : status = smb2_find_level(tree, tree, &f, &count, &d);
2864 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2865 : "smb2_find_level failed\n");
2866 0 : torture_assert_u64_equal_goto(tctx,
2867 : d->id_both_directory_info.file_id,
2868 : expected_fileid,
2869 : ret, done, "bad fileid\n");
2870 :
2871 0 : done:
2872 0 : smb2_util_close(tree, testdirh);
2873 0 : smb2_deltree(tree, DNAME);
2874 0 : talloc_free(mem_ctx);
2875 0 : return ret;
2876 : }
2877 :
2878 0 : static bool test_fileid_dir(struct torture_context *tctx,
2879 : struct smb2_tree *tree)
2880 : {
2881 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2882 0 : const char *dname = DNAME "\\foo";
2883 0 : const char *sname = DNAME "\\foo:bar";
2884 : struct smb2_handle testdirh;
2885 : struct smb2_handle h1;
2886 : struct smb2_create create;
2887 : union smb_fileinfo finfo;
2888 : union smb_setfileinfo sinfo;
2889 : struct smb2_find f;
2890 : unsigned int count;
2891 : union smb_search_data *d;
2892 : uint64_t expected_fileid;
2893 : uint64_t returned_fileid;
2894 : NTSTATUS status;
2895 0 : bool ret = true;
2896 :
2897 0 : smb2_deltree(tree, DNAME);
2898 :
2899 0 : status = torture_smb2_testdir(tree, DNAME, &testdirh);
2900 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2901 : "torture_smb2_testdir failed\n");
2902 :
2903 : /*
2904 : * Initial directory create with QFID
2905 : */
2906 0 : create = (struct smb2_create) {
2907 : .in.desired_access = SEC_FILE_ALL,
2908 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2909 : .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
2910 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2911 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2912 : .in.fname = dname,
2913 : .in.query_on_disk_id = true,
2914 : };
2915 :
2916 0 : status = smb2_create(tree, tctx, &create);
2917 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2918 : "test file could not be created\n");
2919 0 : h1 = create.out.file.handle;
2920 0 : expected_fileid = BVAL(&create.out.on_disk_id, 0);
2921 :
2922 : /*
2923 : * Getinfo the File-ID on the just opened handle
2924 : */
2925 0 : finfo = (union smb_fileinfo) {
2926 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2927 : .generic.in.file.handle = h1,
2928 : };
2929 :
2930 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2931 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2932 : "torture_smb2_testdir\n");
2933 0 : smb2_util_close(tree, h1);
2934 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2935 : expected_fileid,
2936 : ret, done, "bad fileid\n");
2937 :
2938 : /*
2939 : * Open existing directory with QFID
2940 : */
2941 0 : create = (struct smb2_create) {
2942 : .in.desired_access = SEC_FILE_ALL,
2943 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2944 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2945 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2946 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2947 : .in.fname = dname,
2948 : .in.query_on_disk_id = true,
2949 : };
2950 :
2951 0 : status = smb2_create(tree, tctx, &create);
2952 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2953 : "test file could not be created\n");
2954 0 : h1 = create.out.file.handle;
2955 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2956 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2957 : ret, done, "bad fileid\n");
2958 :
2959 : /*
2960 : * Getinfo the File-ID on the just opened handle
2961 : */
2962 0 : finfo = (union smb_fileinfo) {
2963 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2964 : .generic.in.file.handle = h1,
2965 : };
2966 :
2967 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
2968 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2969 : "torture_smb2_testdir\n");
2970 0 : smb2_util_close(tree, h1);
2971 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2972 : expected_fileid,
2973 : ret, done, "bad fileid\n");
2974 :
2975 : /*
2976 : * Create stream, check the stream's File-ID, should be the same as the
2977 : * base file (sic!, tested against Windows).
2978 : */
2979 0 : create = (struct smb2_create) {
2980 : .in.desired_access = SEC_FILE_ALL,
2981 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2982 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2983 : .in.create_disposition = NTCREATEX_DISP_CREATE,
2984 : .in.fname = sname,
2985 : .in.query_on_disk_id = true,
2986 : };
2987 :
2988 0 : status = smb2_create(tree, tctx, &create);
2989 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2990 : "test file could not be created\n");
2991 0 : h1 = create.out.file.handle;
2992 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2993 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2994 : ret, done, "bad fileid\n");
2995 :
2996 : /*
2997 : * Getinfo the File-ID on the created stream
2998 : */
2999 0 : finfo = (union smb_fileinfo) {
3000 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3001 : .generic.in.file.handle = h1,
3002 : };
3003 :
3004 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3005 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3006 : "smb2_getinfo_file failed\n");
3007 0 : smb2_util_close(tree, h1);
3008 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3009 : expected_fileid,
3010 : ret, done, "bad fileid\n");
3011 :
3012 : /*
3013 : * Open stream, check the stream's File-ID, should be the same as the
3014 : * base file (sic!, tested against Windows).
3015 : */
3016 0 : create = (struct smb2_create) {
3017 : .in.desired_access = SEC_FILE_ALL,
3018 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3019 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3020 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3021 : .in.fname = sname,
3022 : .in.query_on_disk_id = true,
3023 : };
3024 :
3025 0 : status = smb2_create(tree, tctx, &create);
3026 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3027 : "test file could not be created\n");
3028 0 : h1 = create.out.file.handle;
3029 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
3030 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
3031 : ret, done, "bad fileid\n");
3032 :
3033 : /*
3034 : * Getinfo the File-ID on the opened stream
3035 : */
3036 0 : finfo = (union smb_fileinfo) {
3037 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3038 : .generic.in.file.handle = h1,
3039 : };
3040 :
3041 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3042 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3043 : "smb2_getinfo_file failed\n");
3044 0 : smb2_util_close(tree, h1);
3045 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3046 : expected_fileid,
3047 : ret, done, "bad fileid\n");
3048 :
3049 : /*
3050 : * Overwrite stream, check the stream's File-ID, should be the same as
3051 : * the base file (sic!, tested against Windows).
3052 : */
3053 0 : create = (struct smb2_create) {
3054 : .in.desired_access = SEC_FILE_ALL,
3055 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3056 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3057 : .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
3058 : .in.fname = sname,
3059 : .in.query_on_disk_id = true,
3060 : };
3061 :
3062 0 : status = smb2_create(tree, tctx, &create);
3063 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3064 : "test file could not be created\n");
3065 0 : h1 = create.out.file.handle;
3066 0 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
3067 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
3068 : ret, done, "bad fileid\n");
3069 :
3070 : /*
3071 : * Getinfo the File-ID on the overwritten stream
3072 : */
3073 0 : finfo = (union smb_fileinfo) {
3074 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3075 : .generic.in.file.handle = h1,
3076 : };
3077 :
3078 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3079 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3080 : "smb2_getinfo_file failed\n");
3081 0 : smb2_util_close(tree, h1);
3082 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3083 : expected_fileid,
3084 : ret, done, "bad fileid\n");
3085 :
3086 : /*
3087 : * Do some modifications on the stream (IO, setinfo), verifying File-ID
3088 : * after earch step.
3089 : */
3090 0 : create = (struct smb2_create) {
3091 : .in.desired_access = SEC_FILE_ALL,
3092 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3093 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3094 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3095 : .in.fname = sname,
3096 : .in.query_on_disk_id = true,
3097 : };
3098 :
3099 0 : status = smb2_create(tree, tctx, &create);
3100 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3101 : "test file could not be created\n");
3102 0 : h1 = create.out.file.handle;
3103 :
3104 0 : status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
3105 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3106 : "smb2_util_write failed\n");
3107 :
3108 0 : finfo = (union smb_fileinfo) {
3109 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3110 : .generic.in.file.handle = h1,
3111 : };
3112 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3113 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3114 : "smb2_getinfo_file failed\n");
3115 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3116 : expected_fileid,
3117 : ret, done, "bad fileid\n");
3118 :
3119 0 : sinfo = (union smb_setfileinfo) {
3120 : .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
3121 : .basic_info.in.file.handle = h1,
3122 : };
3123 0 : unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
3124 :
3125 0 : status = smb2_setinfo_file(tree, &sinfo);
3126 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3127 : "smb2_setinfo_file failed\n");
3128 :
3129 0 : finfo = (union smb_fileinfo) {
3130 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3131 : .generic.in.file.handle = h1,
3132 : };
3133 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3134 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3135 : "smb2_getinfo_file failed\n");
3136 0 : smb2_util_close(tree, h1);
3137 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3138 : expected_fileid,
3139 : ret, done, "bad fileid\n");
3140 :
3141 : /*
3142 : * Final open of the directory 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.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
3148 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
3149 : .in.create_disposition = NTCREATEX_DISP_OPEN,
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 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
3159 0 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
3160 : ret, done, "bad fileid\n");
3161 :
3162 : /*
3163 : * Final Getinfo checking File-ID
3164 : */
3165 0 : finfo = (union smb_fileinfo) {
3166 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3167 : .generic.in.file.handle = h1,
3168 : };
3169 :
3170 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3171 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3172 : "torture_smb2_testdir\n");
3173 0 : smb2_util_close(tree, h1);
3174 0 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
3175 : expected_fileid,
3176 : ret, done, "bad fileid\n");
3177 :
3178 : /*
3179 : * Final list directory, verifying the operations on basefile and stream
3180 : * didn't modify the base file metadata.
3181 : */
3182 0 : f = (struct smb2_find) {
3183 : .in.file.handle = testdirh,
3184 : .in.pattern = "foo",
3185 : .in.max_response_size = 0x1000,
3186 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
3187 : .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART,
3188 : };
3189 :
3190 0 : status = smb2_find_level(tree, tree, &f, &count, &d);
3191 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3192 : "smb2_find_level failed\n");
3193 0 : torture_assert_u64_equal_goto(tctx,
3194 : d->id_both_directory_info.file_id,
3195 : expected_fileid,
3196 : ret, done, "bad fileid\n");
3197 :
3198 0 : done:
3199 0 : smb2_util_close(tree, testdirh);
3200 0 : smb2_deltree(tree, DNAME);
3201 0 : talloc_free(mem_ctx);
3202 0 : return ret;
3203 : }
3204 :
3205 0 : static bool test_fileid_unique_object(
3206 : struct torture_context *tctx,
3207 : struct smb2_tree *tree,
3208 : unsigned int num_objs,
3209 : bool create_dirs)
3210 0 : {
3211 0 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
3212 0 : char *fname = NULL;
3213 : struct smb2_handle testdirh;
3214 : struct smb2_handle h1;
3215 : struct smb2_create create;
3216 : unsigned int i;
3217 0 : uint64_t fileid_array[num_objs];
3218 : NTSTATUS status;
3219 0 : bool ret = true;
3220 :
3221 0 : smb2_deltree(tree, DNAME);
3222 :
3223 0 : status = torture_smb2_testdir(tree, DNAME, &testdirh);
3224 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3225 : "test_fileid_unique failed\n");
3226 0 : smb2_util_close(tree, testdirh);
3227 :
3228 : /* Create num_obj files as rapidly as we can. */
3229 0 : for (i = 0; i < num_objs; i++) {
3230 0 : fname = talloc_asprintf(mem_ctx,
3231 : "%s\\testfile.%u",
3232 : DNAME,
3233 : i);
3234 0 : torture_assert_goto(tctx,
3235 : fname != NULL,
3236 : ret,
3237 : done,
3238 : "talloc failed\n");
3239 :
3240 0 : create = (struct smb2_create) {
3241 : .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
3242 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3243 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3244 : .in.create_disposition = NTCREATEX_DISP_CREATE,
3245 : .in.fname = fname,
3246 : };
3247 :
3248 0 : if (create_dirs) {
3249 0 : create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
3250 0 : create.in.create_options = FILE_DIRECTORY_FILE;
3251 : }
3252 :
3253 0 : status = smb2_create(tree, tctx, &create);
3254 0 : if (!NT_STATUS_IS_OK(status)) {
3255 0 : torture_fail(tctx,
3256 : talloc_asprintf(tctx,
3257 : "test file %s could not be created\n",
3258 : fname));
3259 : TALLOC_FREE(fname);
3260 : ret = false;
3261 : goto done;
3262 : }
3263 :
3264 0 : h1 = create.out.file.handle;
3265 0 : smb2_util_close(tree, h1);
3266 0 : TALLOC_FREE(fname);
3267 : }
3268 :
3269 : /*
3270 : * Get the file ids.
3271 : */
3272 0 : for (i = 0; i < num_objs; i++) {
3273 : union smb_fileinfo finfo;
3274 :
3275 0 : fname = talloc_asprintf(mem_ctx,
3276 : "%s\\testfile.%u",
3277 : DNAME,
3278 : i);
3279 0 : torture_assert_goto(tctx,
3280 : fname != NULL,
3281 : ret,
3282 : done,
3283 : "talloc failed\n");
3284 :
3285 0 : create = (struct smb2_create) {
3286 : .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
3287 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3288 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3289 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3290 : .in.fname = fname,
3291 : };
3292 :
3293 0 : if (create_dirs) {
3294 0 : create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
3295 0 : create.in.create_options = FILE_DIRECTORY_FILE;
3296 : }
3297 :
3298 0 : status = smb2_create(tree, tctx, &create);
3299 0 : if (!NT_STATUS_IS_OK(status)) {
3300 0 : torture_fail(tctx,
3301 : talloc_asprintf(tctx,
3302 : "test file %s could not "
3303 : "be opened: %s\n",
3304 : fname,
3305 : nt_errstr(status)));
3306 : TALLOC_FREE(fname);
3307 : ret = false;
3308 : goto done;
3309 : }
3310 :
3311 0 : h1 = create.out.file.handle;
3312 :
3313 0 : finfo = (union smb_fileinfo) {
3314 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
3315 : .generic.in.file.handle = h1,
3316 : };
3317 :
3318 0 : status = smb2_getinfo_file(tree, tctx, &finfo);
3319 0 : if (!NT_STATUS_IS_OK(status)) {
3320 0 : torture_fail(tctx,
3321 : talloc_asprintf(tctx,
3322 : "failed to get fileid for "
3323 : "test file %s: %s\n",
3324 : fname,
3325 : nt_errstr(status)));
3326 : TALLOC_FREE(fname);
3327 : ret = false;
3328 : goto done;
3329 : }
3330 0 : smb2_util_close(tree, h1);
3331 :
3332 0 : fileid_array[i] = finfo.all_info2.out.file_id;
3333 0 : TALLOC_FREE(fname);
3334 : }
3335 :
3336 : /* All returned fileids must be unique. 100 is small so brute force. */
3337 0 : for (i = 0; i < num_objs - 1; i++) {
3338 : unsigned int j;
3339 0 : for (j = i + 1; j < num_objs; j++) {
3340 0 : if (fileid_array[i] == fileid_array[j]) {
3341 0 : torture_fail(tctx,
3342 : talloc_asprintf(tctx,
3343 : "fileid %u == fileid %u (0x%"PRIu64")\n",
3344 : i,
3345 : j,
3346 : fileid_array[i]));
3347 : ret = false;
3348 : goto done;
3349 : }
3350 : }
3351 : }
3352 :
3353 0 : done:
3354 :
3355 0 : smb2_util_close(tree, testdirh);
3356 0 : smb2_deltree(tree, DNAME);
3357 0 : talloc_free(mem_ctx);
3358 0 : return ret;
3359 : }
3360 :
3361 0 : static bool test_fileid_unique(
3362 : struct torture_context *tctx,
3363 : struct smb2_tree *tree)
3364 : {
3365 0 : return test_fileid_unique_object(tctx, tree, 100, false);
3366 : }
3367 :
3368 0 : static bool test_fileid_unique_dir(
3369 : struct torture_context *tctx,
3370 : struct smb2_tree *tree)
3371 : {
3372 0 : return test_fileid_unique_object(tctx, tree, 100, true);
3373 : }
3374 :
3375 2 : static bool test_dosattr_tmp_dir(struct torture_context *tctx,
3376 : struct smb2_tree *tree)
3377 : {
3378 2 : bool ret = true;
3379 : NTSTATUS status;
3380 : struct smb2_create c;
3381 2 : struct smb2_handle h1 = {{0}};
3382 2 : const char *fname = DNAME;
3383 :
3384 2 : smb2_deltree(tree, fname);
3385 2 : smb2_util_rmdir(tree, fname);
3386 :
3387 2 : c = (struct smb2_create) {
3388 : .in.desired_access = SEC_RIGHTS_DIR_ALL,
3389 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
3390 : .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
3391 : .in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3392 : NTCREATEX_SHARE_ACCESS_WRITE |
3393 : NTCREATEX_SHARE_ACCESS_DELETE,
3394 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
3395 : .in.fname = DNAME,
3396 : };
3397 :
3398 2 : status = smb2_create(tree, tctx, &c);
3399 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3400 : "smb2_create\n");
3401 2 : h1 = c.out.file.handle;
3402 :
3403 : /* Try to set temporary attribute on directory */
3404 2 : SET_ATTRIB(FILE_ATTRIBUTE_TEMPORARY);
3405 :
3406 2 : torture_assert_ntstatus_equal_goto(tctx, status,
3407 : NT_STATUS_INVALID_PARAMETER,
3408 : ret, done,
3409 : "Unexpected setinfo result\n");
3410 :
3411 2 : done:
3412 2 : if (!smb2_util_handle_empty(h1)) {
3413 2 : smb2_util_close(tree, h1);
3414 : }
3415 2 : smb2_util_unlink(tree, fname);
3416 2 : smb2_deltree(tree, fname);
3417 :
3418 2 : return ret;
3419 : }
3420 :
3421 : /*
3422 : test opening quota fakefile handle and returned attributes
3423 : */
3424 2 : static bool test_smb2_open_quota_fake_file(struct torture_context *tctx,
3425 : struct smb2_tree *tree)
3426 : {
3427 2 : const char *fname = "$Extend\\$Quota:$Q:$INDEX_ALLOCATION";
3428 : struct smb2_create create;
3429 2 : struct smb2_handle h = {{0}};
3430 : NTSTATUS status;
3431 2 : bool ret = true;
3432 :
3433 2 : create = (struct smb2_create) {
3434 : .in.desired_access = SEC_RIGHTS_FILE_READ,
3435 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3436 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3437 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3438 : .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
3439 : .in.fname = fname,
3440 : };
3441 :
3442 2 : status = smb2_create(tree, tree, &create);
3443 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3444 : "smb2_create failed\n");
3445 1 : h = create.out.file.handle;
3446 :
3447 1 : torture_assert_u64_equal_goto(tctx,
3448 : create.out.file_attr,
3449 : FILE_ATTRIBUTE_HIDDEN
3450 : | FILE_ATTRIBUTE_SYSTEM
3451 : | FILE_ATTRIBUTE_DIRECTORY
3452 : | FILE_ATTRIBUTE_ARCHIVE,
3453 : ret,
3454 : done,
3455 : "Wrong attributes\n");
3456 :
3457 1 : torture_assert_u64_equal_goto(tctx,
3458 : create.out.create_time, 0,
3459 : ret,
3460 : done,
3461 : "create_time is not 0\n");
3462 1 : torture_assert_u64_equal_goto(tctx,
3463 : create.out.access_time, 0,
3464 : ret,
3465 : done,
3466 : "access_time is not 0\n");
3467 1 : torture_assert_u64_equal_goto(tctx,
3468 : create.out.write_time, 0,
3469 : ret,
3470 : done,
3471 : "write_time is not 0\n");
3472 1 : torture_assert_u64_equal_goto(tctx,
3473 : create.out.change_time, 0,
3474 : ret,
3475 : done,
3476 : "change_time is not 0\n");
3477 :
3478 3 : done:
3479 2 : smb2_util_close(tree, h);
3480 2 : return ret;
3481 : }
3482 :
3483 : /*
3484 : stress testing path base operations
3485 : e.g. contention on lockting.tdb records
3486 : */
3487 :
3488 : struct test_smb2_bench_path_contention_shared_conn;
3489 : struct test_smb2_bench_path_contention_shared_loop;
3490 :
3491 : struct test_smb2_bench_path_contention_shared_state {
3492 : struct torture_context *tctx;
3493 : size_t num_conns;
3494 : struct test_smb2_bench_path_contention_shared_conn *conns;
3495 : size_t num_loops;
3496 : struct test_smb2_bench_path_contention_shared_loop *loops;
3497 : struct timeval starttime;
3498 : int timecount;
3499 : int timelimit;
3500 : struct {
3501 : uint64_t num_finished;
3502 : double total_latency;
3503 : double min_latency;
3504 : double max_latency;
3505 : } opens;
3506 : struct {
3507 : uint64_t num_finished;
3508 : double total_latency;
3509 : double min_latency;
3510 : double max_latency;
3511 : } closes;
3512 : bool ok;
3513 : bool stop;
3514 : };
3515 :
3516 : struct test_smb2_bench_path_contention_shared_conn {
3517 : struct test_smb2_bench_path_contention_shared_state *state;
3518 : int idx;
3519 : struct smb2_tree *tree;
3520 : };
3521 :
3522 : struct test_smb2_bench_path_contention_shared_loop {
3523 : struct test_smb2_bench_path_contention_shared_state *state;
3524 : struct test_smb2_bench_path_contention_shared_conn *conn;
3525 : int idx;
3526 : struct tevent_immediate *im;
3527 : struct {
3528 : struct smb2_create io;
3529 : struct smb2_request *req;
3530 : struct timeval starttime;
3531 : uint64_t num_started;
3532 : uint64_t num_finished;
3533 : double total_latency;
3534 : double min_latency;
3535 : double max_latency;
3536 : } opens;
3537 : struct {
3538 : struct smb2_close io;
3539 : struct smb2_request *req;
3540 : struct timeval starttime;
3541 : uint64_t num_started;
3542 : uint64_t num_finished;
3543 : double total_latency;
3544 : double min_latency;
3545 : double max_latency;
3546 : } closes;
3547 : NTSTATUS error;
3548 : };
3549 :
3550 : static void test_smb2_bench_path_contention_loop_open(
3551 : struct test_smb2_bench_path_contention_shared_loop *loop);
3552 :
3553 8 : static void test_smb2_bench_path_contention_loop_start(struct tevent_context *ctx,
3554 : struct tevent_immediate *im,
3555 : void *private_data)
3556 : {
3557 8 : struct test_smb2_bench_path_contention_shared_loop *loop =
3558 : (struct test_smb2_bench_path_contention_shared_loop *)
3559 : private_data;
3560 :
3561 8 : test_smb2_bench_path_contention_loop_open(loop);
3562 8 : }
3563 :
3564 : static void test_smb2_bench_path_contention_loop_opened(struct smb2_request *req);
3565 :
3566 8653 : static void test_smb2_bench_path_contention_loop_open(
3567 : struct test_smb2_bench_path_contention_shared_loop *loop)
3568 : {
3569 8653 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
3570 :
3571 8653 : loop->opens.num_started += 1;
3572 8653 : loop->opens.starttime = timeval_current();
3573 8653 : loop->opens.req = smb2_create_send(loop->conn->tree, &loop->opens.io);
3574 8653 : torture_assert_goto(state->tctx, loop->opens.req != NULL,
3575 : state->ok, asserted, "smb2_create_send");
3576 :
3577 8653 : loop->opens.req->async.fn = test_smb2_bench_path_contention_loop_opened;
3578 8653 : loop->opens.req->async.private_data = loop;
3579 8653 : return;
3580 0 : asserted:
3581 0 : state->stop = true;
3582 : }
3583 :
3584 : static void test_smb2_bench_path_contention_loop_close(
3585 : struct test_smb2_bench_path_contention_shared_loop *loop);
3586 :
3587 8650 : static void test_smb2_bench_path_contention_loop_opened(struct smb2_request *req)
3588 : {
3589 8650 : struct test_smb2_bench_path_contention_shared_loop *loop =
3590 : (struct test_smb2_bench_path_contention_shared_loop *)
3591 : req->async.private_data;
3592 8650 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
3593 8650 : double latency = timeval_elapsed(&loop->opens.starttime);
3594 8650 : TALLOC_CTX *frame = talloc_stackframe();
3595 :
3596 8650 : torture_assert_goto(state->tctx, loop->opens.req == req,
3597 : state->ok, asserted, __location__);
3598 8650 : loop->error = smb2_create_recv(req, frame, &loop->opens.io);
3599 8650 : torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
3600 : state->ok, asserted, __location__);
3601 8650 : ZERO_STRUCT(loop->opens.io.out.blobs);
3602 8650 : SMB_ASSERT(latency >= 0.000001);
3603 :
3604 8650 : if (loop->opens.num_finished == 0) {
3605 : /* first round */
3606 8 : loop->opens.min_latency = latency;
3607 8 : loop->opens.max_latency = latency;
3608 : }
3609 :
3610 8650 : loop->opens.num_finished += 1;
3611 8650 : loop->opens.total_latency += latency;
3612 :
3613 8650 : if (latency < loop->opens.min_latency) {
3614 45 : loop->opens.min_latency = latency;
3615 : }
3616 :
3617 8650 : if (latency > loop->opens.max_latency) {
3618 21 : loop->opens.max_latency = latency;
3619 : }
3620 :
3621 8650 : TALLOC_FREE(frame);
3622 8650 : test_smb2_bench_path_contention_loop_close(loop);
3623 8650 : return;
3624 0 : asserted:
3625 0 : state->stop = true;
3626 0 : TALLOC_FREE(frame);
3627 : }
3628 :
3629 : static void test_smb2_bench_path_contention_loop_closed(struct smb2_request *req);
3630 :
3631 8650 : static void test_smb2_bench_path_contention_loop_close(
3632 : struct test_smb2_bench_path_contention_shared_loop *loop)
3633 : {
3634 8650 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
3635 :
3636 8650 : loop->closes.num_started += 1;
3637 8650 : loop->closes.starttime = timeval_current();
3638 8650 : loop->closes.io.in.file = loop->opens.io.out.file;
3639 8650 : loop->closes.req = smb2_close_send(loop->conn->tree, &loop->closes.io);
3640 8650 : torture_assert_goto(state->tctx, loop->closes.req != NULL,
3641 : state->ok, asserted, "smb2_close_send");
3642 :
3643 8650 : loop->closes.req->async.fn = test_smb2_bench_path_contention_loop_closed;
3644 8650 : loop->closes.req->async.private_data = loop;
3645 8650 : return;
3646 0 : asserted:
3647 0 : state->stop = true;
3648 : }
3649 :
3650 8645 : static void test_smb2_bench_path_contention_loop_closed(struct smb2_request *req)
3651 : {
3652 8645 : struct test_smb2_bench_path_contention_shared_loop *loop =
3653 : (struct test_smb2_bench_path_contention_shared_loop *)
3654 : req->async.private_data;
3655 8645 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
3656 8645 : double latency = timeval_elapsed(&loop->closes.starttime);
3657 :
3658 8645 : torture_assert_goto(state->tctx, loop->closes.req == req,
3659 : state->ok, asserted, __location__);
3660 8645 : loop->error = smb2_close_recv(req, &loop->closes.io);
3661 8645 : torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
3662 : state->ok, asserted, __location__);
3663 8645 : SMB_ASSERT(latency >= 0.000001);
3664 8645 : if (loop->closes.num_finished == 0) {
3665 : /* first round */
3666 8 : loop->closes.min_latency = latency;
3667 8 : loop->closes.max_latency = latency;
3668 : }
3669 8645 : loop->closes.num_finished += 1;
3670 :
3671 8645 : loop->closes.total_latency += latency;
3672 :
3673 8645 : if (latency < loop->closes.min_latency) {
3674 39 : loop->closes.min_latency = latency;
3675 : }
3676 :
3677 8645 : if (latency > loop->closes.max_latency) {
3678 31 : loop->closes.max_latency = latency;
3679 : }
3680 :
3681 8645 : test_smb2_bench_path_contention_loop_open(loop);
3682 8645 : return;
3683 0 : asserted:
3684 0 : state->stop = true;
3685 : }
3686 :
3687 2 : static void test_smb2_bench_path_contention_progress(struct tevent_context *ev,
3688 : struct tevent_timer *te,
3689 : struct timeval current_time,
3690 : void *private_data)
3691 : {
3692 2 : struct test_smb2_bench_path_contention_shared_state *state =
3693 : (struct test_smb2_bench_path_contention_shared_state *)private_data;
3694 2 : uint64_t num_opens = 0;
3695 2 : double total_open_latency = 0;
3696 2 : double min_open_latency = 0;
3697 2 : double max_open_latency = 0;
3698 2 : double avs_open_latency = 0;
3699 2 : uint64_t num_closes = 0;
3700 2 : double total_close_latency = 0;
3701 2 : double min_close_latency = 0;
3702 2 : double max_close_latency = 0;
3703 2 : double avs_close_latency = 0;
3704 : size_t i;
3705 :
3706 2 : state->timecount += 1;
3707 :
3708 10 : for (i=0;i<state->num_loops;i++) {
3709 8 : struct test_smb2_bench_path_contention_shared_loop *loop =
3710 8 : &state->loops[i];
3711 :
3712 8 : num_opens += loop->opens.num_finished;
3713 8 : total_open_latency += loop->opens.total_latency;
3714 8 : if (min_open_latency == 0.0 && loop->opens.min_latency != 0.0) {
3715 2 : min_open_latency = loop->opens.min_latency;
3716 : }
3717 8 : if (loop->opens.min_latency < min_open_latency) {
3718 1 : min_open_latency = loop->opens.min_latency;
3719 : }
3720 8 : if (max_open_latency == 0.0) {
3721 2 : max_open_latency = loop->opens.max_latency;
3722 : }
3723 8 : if (loop->opens.max_latency > max_open_latency) {
3724 2 : max_open_latency = loop->opens.max_latency;
3725 : }
3726 8 : loop->opens.num_finished = 0;
3727 8 : loop->opens.total_latency = 0.0;
3728 :
3729 8 : num_closes += loop->closes.num_finished;
3730 8 : total_close_latency += loop->closes.total_latency;
3731 8 : if (min_close_latency == 0.0 && loop->closes.min_latency != 0.0) {
3732 2 : min_close_latency = loop->closes.min_latency;
3733 : }
3734 8 : if (loop->closes.min_latency < min_close_latency) {
3735 0 : min_close_latency = loop->closes.min_latency;
3736 : }
3737 8 : if (max_close_latency == 0.0) {
3738 2 : max_close_latency = loop->closes.max_latency;
3739 : }
3740 8 : if (loop->closes.max_latency > max_close_latency) {
3741 3 : max_close_latency = loop->closes.max_latency;
3742 : }
3743 8 : loop->closes.num_finished = 0;
3744 8 : loop->closes.total_latency = 0.0;
3745 : }
3746 :
3747 2 : state->opens.num_finished += num_opens;
3748 2 : state->opens.total_latency += total_open_latency;
3749 2 : if (state->opens.min_latency == 0.0 && min_open_latency != 0.0) {
3750 2 : state->opens.min_latency = min_open_latency;
3751 : }
3752 2 : if (min_open_latency < state->opens.min_latency) {
3753 0 : state->opens.min_latency = min_open_latency;
3754 : }
3755 2 : if (state->opens.max_latency == 0.0) {
3756 2 : state->opens.max_latency = max_open_latency;
3757 : }
3758 2 : if (max_open_latency > state->opens.max_latency) {
3759 0 : state->opens.max_latency = max_open_latency;
3760 : }
3761 :
3762 2 : state->closes.num_finished += num_closes;
3763 2 : state->closes.total_latency += total_close_latency;
3764 2 : if (state->closes.min_latency == 0.0 && min_close_latency != 0.0) {
3765 2 : state->closes.min_latency = min_close_latency;
3766 : }
3767 2 : if (min_close_latency < state->closes.min_latency) {
3768 0 : state->closes.min_latency = min_close_latency;
3769 : }
3770 2 : if (state->closes.max_latency == 0.0) {
3771 2 : state->closes.max_latency = max_close_latency;
3772 : }
3773 2 : if (max_close_latency > state->closes.max_latency) {
3774 0 : state->closes.max_latency = max_close_latency;
3775 : }
3776 :
3777 2 : if (state->timecount < state->timelimit) {
3778 0 : te = tevent_add_timer(state->tctx->ev,
3779 : state,
3780 : timeval_current_ofs(1, 0),
3781 : test_smb2_bench_path_contention_progress,
3782 : state);
3783 0 : torture_assert_goto(state->tctx, te != NULL,
3784 : state->ok, asserted, "tevent_add_timer");
3785 :
3786 0 : if (!torture_setting_bool(state->tctx, "progress", true)) {
3787 0 : return;
3788 : }
3789 :
3790 0 : avs_open_latency = total_open_latency / num_opens;
3791 0 : avs_close_latency = total_close_latency / num_closes;
3792 :
3793 0 : torture_comment(state->tctx,
3794 : "%.2f second: "
3795 : "open[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
3796 : "close[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] \r",
3797 0 : timeval_elapsed(&state->starttime),
3798 : (unsigned long long)num_opens,
3799 : avs_open_latency,
3800 : min_open_latency,
3801 : max_open_latency,
3802 : (unsigned long long)num_closes,
3803 : avs_close_latency,
3804 : min_close_latency,
3805 : max_close_latency);
3806 0 : return;
3807 : }
3808 :
3809 2 : avs_open_latency = state->opens.total_latency / state->opens.num_finished;
3810 2 : avs_close_latency = state->closes.total_latency / state->closes.num_finished;
3811 2 : num_opens = state->opens.num_finished / state->timelimit;
3812 2 : num_closes = state->closes.num_finished / state->timelimit;
3813 :
3814 4 : torture_comment(state->tctx,
3815 : "%.2f second: "
3816 : "open[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
3817 : "close[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
3818 2 : timeval_elapsed(&state->starttime),
3819 : (unsigned long long)num_opens,
3820 : avs_open_latency,
3821 : state->opens.min_latency,
3822 : state->opens.max_latency,
3823 : (unsigned long long)num_closes,
3824 : avs_close_latency,
3825 : state->closes.min_latency,
3826 : state->closes.max_latency);
3827 :
3828 2 : asserted:
3829 2 : state->stop = true;
3830 : }
3831 :
3832 2 : static bool test_smb2_bench_path_contention_shared(struct torture_context *tctx,
3833 : struct smb2_tree *tree)
3834 : {
3835 2 : struct test_smb2_bench_path_contention_shared_state *state = NULL;
3836 2 : bool ret = true;
3837 2 : int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
3838 2 : int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
3839 : size_t i;
3840 2 : size_t li = 0;
3841 2 : int timelimit = torture_setting_int(tctx, "timelimit", 10);
3842 2 : const char *path = torture_setting_string(tctx, "bench_path", "");
3843 2 : struct smb2_create open_io = { .level = RAW_OPEN_SMB2, };
3844 2 : struct smb2_close close_io = { .level = RAW_CLOSE_SMB2, };
3845 2 : struct tevent_timer *te = NULL;
3846 : uint32_t timeout_msec;
3847 :
3848 2 : state = talloc_zero(tctx, struct test_smb2_bench_path_contention_shared_state);
3849 2 : torture_assert(tctx, state != NULL, __location__);
3850 2 : state->tctx = tctx;
3851 2 : state->num_conns = torture_nprocs;
3852 2 : state->conns = talloc_zero_array(state,
3853 : struct test_smb2_bench_path_contention_shared_conn,
3854 : state->num_conns);
3855 2 : torture_assert(tctx, state->conns != NULL, __location__);
3856 2 : state->num_loops = torture_nprocs * torture_qdepth;
3857 2 : state->loops = talloc_zero_array(state,
3858 : struct test_smb2_bench_path_contention_shared_loop,
3859 : state->num_loops);
3860 2 : torture_assert(tctx, state->loops != NULL, __location__);
3861 2 : state->ok = true;
3862 2 : state->timelimit = MAX(timelimit, 1);
3863 :
3864 2 : open_io.in.desired_access = SEC_DIR_READ_ATTRIBUTE;
3865 2 : open_io.in.alloc_size = 0;
3866 2 : open_io.in.file_attributes = 0;
3867 2 : open_io.in.share_access = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
3868 2 : open_io.in.create_disposition = FILE_OPEN;
3869 2 : open_io.in.create_options = FILE_OPEN_REPARSE_POINT;
3870 2 : open_io.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3871 2 : open_io.in.security_flags = 0;
3872 2 : open_io.in.fname = path;
3873 2 : open_io.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3874 2 : open_io.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
3875 :
3876 2 : timeout_msec = tree->session->transport->options.request_timeout * 1000;
3877 :
3878 2 : torture_comment(tctx, "Opening %zd connections\n", state->num_conns);
3879 :
3880 20 : for (i=0;i<state->num_conns;i++) {
3881 8 : struct smb2_tree *ct = NULL;
3882 8 : DATA_BLOB out_input_buffer = data_blob_null;
3883 8 : DATA_BLOB out_output_buffer = data_blob_null;
3884 : size_t pcli;
3885 :
3886 8 : state->conns[i].state = state;
3887 8 : state->conns[i].idx = i;
3888 :
3889 8 : if (!torture_smb2_connection(tctx, &ct)) {
3890 0 : torture_comment(tctx, "Failed opening %zd/%zd connections\n", i, state->num_conns);
3891 0 : return false;
3892 : }
3893 8 : state->conns[i].tree = talloc_steal(state->conns, ct);
3894 :
3895 8 : smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
3896 24 : smb2cli_ioctl(ct->session->transport->conn,
3897 : timeout_msec,
3898 8 : ct->session->smbXcli,
3899 8 : ct->smbXcli,
3900 : UINT64_MAX, /* in_fid_persistent */
3901 : UINT64_MAX, /* in_fid_volatile */
3902 : UINT32_MAX,
3903 : 0, /* in_max_input_length */
3904 : NULL, /* in_input_buffer */
3905 : 1, /* in_max_output_length */
3906 : NULL, /* in_output_buffer */
3907 : SMB2_IOCTL_FLAG_IS_FSCTL,
3908 : ct,
3909 : &out_input_buffer,
3910 : &out_output_buffer);
3911 8 : torture_assert(tctx,
3912 : smbXcli_conn_is_connected(ct->session->transport->conn),
3913 : "smbXcli_conn_is_connected");
3914 16 : for (pcli = 0; pcli < torture_qdepth; pcli++) {
3915 8 : struct test_smb2_bench_path_contention_shared_loop *loop = &state->loops[li];
3916 :
3917 8 : loop->idx = li++;
3918 8 : loop->state = state;
3919 8 : loop->conn = &state->conns[i];
3920 8 : loop->im = tevent_create_immediate(state->loops);
3921 8 : torture_assert(tctx, loop->im != NULL, __location__);
3922 8 : loop->opens.io = open_io;
3923 8 : loop->closes.io = close_io;
3924 :
3925 8 : tevent_schedule_immediate(loop->im,
3926 : tctx->ev,
3927 : test_smb2_bench_path_contention_loop_start,
3928 : loop);
3929 : }
3930 : }
3931 :
3932 2 : torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
3933 : state->num_conns, torture_qdepth, state->num_loops);
3934 :
3935 2 : torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
3936 :
3937 2 : state->starttime = timeval_current();
3938 :
3939 2 : te = tevent_add_timer(tctx->ev,
3940 : state,
3941 : timeval_current_ofs(1, 0),
3942 : test_smb2_bench_path_contention_progress,
3943 : state);
3944 2 : torture_assert(tctx, te != NULL, __location__);
3945 :
3946 61759 : while (!state->stop) {
3947 61755 : int rc = tevent_loop_once(tctx->ev);
3948 61755 : torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
3949 : }
3950 :
3951 2 : torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
3952 2 : TALLOC_FREE(state);
3953 2 : return ret;
3954 : }
3955 :
3956 : /*
3957 : basic testing of SMB2 read
3958 : */
3959 964 : struct torture_suite *torture_smb2_create_init(TALLOC_CTX *ctx)
3960 : {
3961 964 : struct torture_suite *suite = torture_suite_create(ctx, "create");
3962 :
3963 964 : torture_suite_add_1smb2_test(suite, "gentest", test_create_gentest);
3964 964 : torture_suite_add_1smb2_test(suite, "blob", test_create_blob);
3965 964 : torture_suite_add_1smb2_test(suite, "open", test_smb2_open);
3966 964 : torture_suite_add_1smb2_test(suite, "brlocked", test_smb2_open_brlocked);
3967 964 : torture_suite_add_1smb2_test(suite, "multi", test_smb2_open_multi);
3968 964 : torture_suite_add_1smb2_test(suite, "delete", test_smb2_open_for_delete);
3969 964 : torture_suite_add_1smb2_test(suite, "leading-slash", test_smb2_leading_slash);
3970 964 : torture_suite_add_1smb2_test(suite, "impersonation", test_smb2_impersonation_level);
3971 964 : torture_suite_add_1smb2_test(suite, "aclfile", test_create_acl_file);
3972 964 : torture_suite_add_1smb2_test(suite, "acldir", test_create_acl_dir);
3973 964 : torture_suite_add_1smb2_test(suite, "nulldacl", test_create_null_dacl);
3974 964 : torture_suite_add_1smb2_test(suite, "mkdir-dup", test_mkdir_dup);
3975 964 : torture_suite_add_1smb2_test(suite, "dir-alloc-size", test_dir_alloc_size);
3976 964 : torture_suite_add_1smb2_test(suite, "dosattr_tmp_dir", test_dosattr_tmp_dir);
3977 964 : torture_suite_add_1smb2_test(suite, "quota-fake-file", test_smb2_open_quota_fake_file);
3978 :
3979 964 : torture_suite_add_1smb2_test(suite, "bench-path-contention-shared", test_smb2_bench_path_contention_shared);
3980 :
3981 964 : suite->description = talloc_strdup(suite, "SMB2-CREATE tests");
3982 :
3983 964 : return suite;
3984 : }
3985 :
3986 964 : struct torture_suite *torture_smb2_twrp_init(TALLOC_CTX *ctx)
3987 : {
3988 964 : struct torture_suite *suite = torture_suite_create(ctx, "twrp");
3989 :
3990 964 : torture_suite_add_1smb2_test(suite, "write", test_twrp_write);
3991 964 : torture_suite_add_1smb2_test(suite, "stream", test_twrp_stream);
3992 964 : torture_suite_add_1smb2_test(suite, "openroot", test_twrp_openroot);
3993 964 : torture_suite_add_1smb2_test(suite, "listdir", test_twrp_listdir);
3994 :
3995 964 : suite->description = talloc_strdup(suite, "SMB2-TWRP tests");
3996 :
3997 964 : return suite;
3998 : }
3999 :
4000 : /*
4001 : basic testing of SMB2 File-IDs
4002 : */
4003 964 : struct torture_suite *torture_smb2_fileid_init(TALLOC_CTX *ctx)
4004 : {
4005 964 : struct torture_suite *suite = torture_suite_create(ctx, "fileid");
4006 :
4007 964 : torture_suite_add_1smb2_test(suite, "fileid", test_fileid);
4008 964 : torture_suite_add_1smb2_test(suite, "fileid-dir", test_fileid_dir);
4009 964 : torture_suite_add_1smb2_test(suite, "unique", test_fileid_unique);
4010 964 : torture_suite_add_1smb2_test(suite, "unique-dir", test_fileid_unique_dir);
4011 :
4012 964 : suite->description = talloc_strdup(suite, "SMB2-FILEID tests");
4013 :
4014 964 : return suite;
4015 : }
4016 :
4017 964 : struct torture_suite *torture_smb2_bench_init(TALLOC_CTX *ctx)
4018 : {
4019 964 : struct torture_suite *suite = torture_suite_create(ctx, "bench");
4020 :
4021 964 : torture_suite_add_1smb2_test(suite, "oplock1", test_smb2_bench_oplock);
4022 964 : torture_suite_add_1smb2_test(suite, "path-contention-shared", test_smb2_bench_path_contention_shared);
4023 964 : torture_suite_add_1smb2_test(suite, "echo", test_smb2_bench_echo);
4024 :
4025 964 : suite->description = talloc_strdup(suite, "SMB2-BENCH tests");
4026 :
4027 964 : return suite;
4028 : }
4029 :
4030 0 : static bool test_no_stream(struct torture_context *tctx,
4031 : struct smb2_tree *tree)
4032 : {
4033 : struct smb2_create c;
4034 : NTSTATUS status;
4035 0 : bool ret = true;
4036 0 : const char *names[] = {
4037 : "test_no_stream::$DATA",
4038 : "test_no_stream::foooooooooooo",
4039 : "test_no_stream:stream",
4040 : "test_no_stream:stream:$DATA",
4041 : NULL
4042 : };
4043 : int i;
4044 :
4045 0 : for (i = 0; names[i] != NULL; i++) {
4046 0 : c = (struct smb2_create) {
4047 : .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
4048 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
4049 : .in.create_disposition = NTCREATEX_DISP_OPEN,
4050 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
4051 0 : .in.fname = names[i],
4052 : };
4053 :
4054 0 : status = smb2_create(tree, tctx, &c);
4055 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_INVALID)) {
4056 0 : torture_comment(
4057 : tctx, "Expected NT_STATUS_OBJECT_NAME_INVALID, "
4058 : "got %s, name: '%s'\n",
4059 : nt_errstr(status), names[i]);
4060 0 : torture_fail_goto(tctx, done, "Bad create result\n");
4061 : }
4062 : }
4063 0 : done:
4064 0 : return ret;
4065 : }
4066 :
4067 964 : struct torture_suite *torture_smb2_create_no_streams_init(TALLOC_CTX *ctx)
4068 : {
4069 964 : struct torture_suite *suite = torture_suite_create(ctx, "create_no_streams");
4070 :
4071 964 : torture_suite_add_1smb2_test(suite, "no_stream", test_no_stream);
4072 :
4073 964 : suite->description = talloc_strdup(suite, "SMB2-CREATE stream test on share without streams support");
4074 :
4075 964 : return suite;
4076 : }
|