doc: clarify "winbind max clients"
[Samba.git] / source4 / torture / smb2 / session.c
blob798230b2df612199c86b35f2d12e166d217eca66
1 /*
2 Unix SMB/CIFS implementation.
4 test suite for SMB2 session setups
6 Copyright (C) Michael Adam 2012
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.
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.
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/>.
22 #include "includes.h"
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25 #include "torture/torture.h"
26 #include "torture/smb2/proto.h"
27 #include "../libcli/smb/smbXcli_base.h"
28 #include "lib/cmdline/popt_common.h"
29 #include "auth/credentials/credentials.h"
30 #include "libcli/security/security.h"
31 #include "libcli/resolve/resolve.h"
32 #include "lib/param/param.h"
34 #define CHECK_VAL(v, correct) do { \
35 if ((v) != (correct)) { \
36 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
37 __location__, #v, (int)v, (int)correct); \
38 ret = false; \
39 }} while (0)
41 #define CHECK_STATUS(status, correct) do { \
42 if (!NT_STATUS_EQUAL(status, correct)) { \
43 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
44 nt_errstr(status), nt_errstr(correct)); \
45 ret = false; \
46 goto done; \
47 }} while (0)
49 #define CHECK_CREATED(__io, __created, __attribute) \
50 do { \
51 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
52 CHECK_VAL((__io)->out.alloc_size, 0); \
53 CHECK_VAL((__io)->out.size, 0); \
54 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
55 CHECK_VAL((__io)->out.reserved2, 0); \
56 } while(0)
59 /**
60 * basic test for doing a session reconnect
62 bool test_session_reconnect1(struct torture_context *tctx, struct smb2_tree *tree)
64 NTSTATUS status;
65 TALLOC_CTX *mem_ctx = talloc_new(tctx);
66 char fname[256];
67 struct smb2_handle _h1;
68 struct smb2_handle *h1 = NULL;
69 struct smb2_handle _h2;
70 struct smb2_handle *h2 = NULL;
71 struct smb2_create io1, io2;
72 uint64_t previous_session_id;
73 bool ret = true;
74 struct smb2_tree *tree2 = NULL;
75 union smb_fileinfo qfinfo;
77 /* Add some random component to the file name. */
78 snprintf(fname, sizeof(fname), "session_reconnect_%s.dat",
79 generate_random_str(tctx, 8));
81 smb2_util_unlink(tree, fname);
83 smb2_oplock_create_share(&io1, fname,
84 smb2_util_share_access(""),
85 smb2_util_oplock_level("b"));
87 status = smb2_create(tree, mem_ctx, &io1);
88 CHECK_STATUS(status, NT_STATUS_OK);
89 _h1 = io1.out.file.handle;
90 h1 = &_h1;
91 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
92 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
94 /* disconnect, reconnect and then do durable reopen */
95 previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
97 torture_assert_goto(tctx, torture_smb2_connection_ext(tctx, previous_session_id,
98 &tree->session->transport->options, &tree2),
99 ret, done,
100 "session reconnect failed\n");
102 /* try to access the file via the old handle */
104 ZERO_STRUCT(qfinfo);
105 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
106 qfinfo.generic.in.file.handle = _h1;
107 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
108 CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
109 h1 = NULL;
111 smb2_oplock_create_share(&io2, fname,
112 smb2_util_share_access(""),
113 smb2_util_oplock_level("b"));
115 status = smb2_create(tree2, mem_ctx, &io2);
116 CHECK_STATUS(status, NT_STATUS_OK);
117 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
118 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
119 _h2 = io2.out.file.handle;
120 h2 = &_h2;
122 done:
123 if (h1 != NULL) {
124 smb2_util_close(tree, *h1);
126 if (h2 != NULL) {
127 smb2_util_close(tree2, *h2);
130 if (tree2 != NULL) {
131 smb2_util_unlink(tree2, fname);
133 smb2_util_unlink(tree, fname);
135 talloc_free(tree);
136 talloc_free(tree2);
138 talloc_free(mem_ctx);
140 return ret;
144 * basic test for doing a session reconnect on one connection
146 bool test_session_reconnect2(struct torture_context *tctx, struct smb2_tree *tree)
148 NTSTATUS status;
149 TALLOC_CTX *mem_ctx = talloc_new(tctx);
150 char fname[256];
151 struct smb2_handle _h1;
152 struct smb2_handle *h1 = NULL;
153 struct smb2_create io1;
154 uint64_t previous_session_id;
155 bool ret = true;
156 struct smb2_session *session2 = NULL;
157 union smb_fileinfo qfinfo;
159 /* Add some random component to the file name. */
160 snprintf(fname, sizeof(fname), "session_reconnect_%s.dat",
161 generate_random_str(tctx, 8));
163 smb2_util_unlink(tree, fname);
165 smb2_oplock_create_share(&io1, fname,
166 smb2_util_share_access(""),
167 smb2_util_oplock_level("b"));
168 io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
170 status = smb2_create(tree, mem_ctx, &io1);
171 CHECK_STATUS(status, NT_STATUS_OK);
172 _h1 = io1.out.file.handle;
173 h1 = &_h1;
174 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
175 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
177 /* disconnect, reconnect and then do durable reopen */
178 previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
180 torture_assert(tctx, torture_smb2_session_setup(tctx, tree->session->transport,
181 previous_session_id, tctx, &session2),
182 "session reconnect (on the same connection) failed");
184 /* try to access the file via the old handle */
186 ZERO_STRUCT(qfinfo);
187 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
188 qfinfo.generic.in.file.handle = _h1;
189 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
190 CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
191 h1 = NULL;
193 done:
194 if (h1 != NULL) {
195 smb2_util_close(tree, *h1);
198 talloc_free(tree);
199 talloc_free(session2);
201 talloc_free(mem_ctx);
203 return ret;
206 bool test_session_reauth1(struct torture_context *tctx, struct smb2_tree *tree)
208 NTSTATUS status;
209 TALLOC_CTX *mem_ctx = talloc_new(tctx);
210 char fname[256];
211 struct smb2_handle _h1;
212 struct smb2_handle *h1 = NULL;
213 struct smb2_create io1;
214 bool ret = true;
215 union smb_fileinfo qfinfo;
217 /* Add some random component to the file name. */
218 snprintf(fname, sizeof(fname), "session_reauth1_%s.dat",
219 generate_random_str(tctx, 8));
221 smb2_util_unlink(tree, fname);
223 smb2_oplock_create_share(&io1, fname,
224 smb2_util_share_access(""),
225 smb2_util_oplock_level("b"));
227 status = smb2_create(tree, mem_ctx, &io1);
228 CHECK_STATUS(status, NT_STATUS_OK);
229 _h1 = io1.out.file.handle;
230 h1 = &_h1;
231 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
232 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
234 status = smb2_session_setup_spnego(tree->session,
235 cmdline_credentials,
236 0 /* previous_session_id */);
237 CHECK_STATUS(status, NT_STATUS_OK);
239 /* try to access the file via the old handle */
241 ZERO_STRUCT(qfinfo);
242 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
243 qfinfo.generic.in.file.handle = _h1;
244 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
245 CHECK_STATUS(status, NT_STATUS_OK);
247 status = smb2_session_setup_spnego(tree->session,
248 cmdline_credentials,
249 0 /* previous_session_id */);
250 CHECK_STATUS(status, NT_STATUS_OK);
252 /* try to access the file via the old handle */
254 ZERO_STRUCT(qfinfo);
255 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
256 qfinfo.generic.in.file.handle = _h1;
257 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
258 CHECK_STATUS(status, NT_STATUS_OK);
260 done:
261 if (h1 != NULL) {
262 smb2_util_close(tree, *h1);
265 smb2_util_unlink(tree, fname);
267 talloc_free(tree);
269 talloc_free(mem_ctx);
271 return ret;
274 bool test_session_reauth2(struct torture_context *tctx, struct smb2_tree *tree)
276 NTSTATUS status;
277 TALLOC_CTX *mem_ctx = talloc_new(tctx);
278 char fname[256];
279 struct smb2_handle _h1;
280 struct smb2_handle *h1 = NULL;
281 struct smb2_create io1;
282 bool ret = true;
283 union smb_fileinfo qfinfo;
284 struct cli_credentials *anon_creds = NULL;
286 /* Add some random component to the file name. */
287 snprintf(fname, sizeof(fname), "session_reauth2_%s.dat",
288 generate_random_str(tctx, 8));
290 smb2_util_unlink(tree, fname);
292 smb2_oplock_create_share(&io1, fname,
293 smb2_util_share_access(""),
294 smb2_util_oplock_level("b"));
296 status = smb2_create(tree, mem_ctx, &io1);
297 CHECK_STATUS(status, NT_STATUS_OK);
298 _h1 = io1.out.file.handle;
299 h1 = &_h1;
300 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
301 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
303 /* re-authenticate as anonymous */
305 anon_creds = cli_credentials_init_anon(mem_ctx);
306 torture_assert(tctx, (anon_creds != NULL), "talloc error");
308 status = smb2_session_setup_spnego(tree->session,
309 anon_creds,
310 0 /* previous_session_id */);
311 CHECK_STATUS(status, NT_STATUS_OK);
313 /* try to access the file via the old handle */
315 ZERO_STRUCT(qfinfo);
316 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
317 qfinfo.generic.in.file.handle = _h1;
318 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
319 CHECK_STATUS(status, NT_STATUS_OK);
321 /* re-authenticate as original user again */
323 status = smb2_session_setup_spnego(tree->session,
324 cmdline_credentials,
325 0 /* previous_session_id */);
326 CHECK_STATUS(status, NT_STATUS_OK);
328 /* try to access the file via the old handle */
330 ZERO_STRUCT(qfinfo);
331 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
332 qfinfo.generic.in.file.handle = _h1;
333 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
334 CHECK_STATUS(status, NT_STATUS_OK);
336 done:
337 if (h1 != NULL) {
338 smb2_util_close(tree, *h1);
341 smb2_util_unlink(tree, fname);
343 talloc_free(tree);
345 talloc_free(mem_ctx);
347 return ret;
351 * test getting security descriptor after reauth
353 bool test_session_reauth3(struct torture_context *tctx, struct smb2_tree *tree)
355 NTSTATUS status;
356 TALLOC_CTX *mem_ctx = talloc_new(tctx);
357 char fname[256];
358 struct smb2_handle _h1;
359 struct smb2_handle *h1 = NULL;
360 struct smb2_create io1;
361 bool ret = true;
362 union smb_fileinfo qfinfo;
363 struct cli_credentials *anon_creds = NULL;
364 uint32_t secinfo_flags = SECINFO_OWNER
365 | SECINFO_GROUP
366 | SECINFO_DACL
367 | SECINFO_PROTECTED_DACL
368 | SECINFO_UNPROTECTED_DACL;
370 /* Add some random component to the file name. */
371 snprintf(fname, sizeof(fname), "session_reauth3_%s.dat",
372 generate_random_str(tctx, 8));
374 smb2_util_unlink(tree, fname);
376 smb2_oplock_create_share(&io1, fname,
377 smb2_util_share_access(""),
378 smb2_util_oplock_level("b"));
380 status = smb2_create(tree, mem_ctx, &io1);
381 CHECK_STATUS(status, NT_STATUS_OK);
382 _h1 = io1.out.file.handle;
383 h1 = &_h1;
384 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
385 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
387 /* get the security descriptor */
389 ZERO_STRUCT(qfinfo);
391 qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
392 qfinfo.query_secdesc.in.file.handle = _h1;
393 qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
395 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
396 CHECK_STATUS(status, NT_STATUS_OK);
397 /* re-authenticate as anonymous */
399 anon_creds = cli_credentials_init_anon(mem_ctx);
400 torture_assert(tctx, (anon_creds != NULL), "talloc error");
402 status = smb2_session_setup_spnego(tree->session,
403 anon_creds,
404 0 /* previous_session_id */);
405 CHECK_STATUS(status, NT_STATUS_OK);
407 /* try to access the file via the old handle */
409 ZERO_STRUCT(qfinfo);
411 qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
412 qfinfo.query_secdesc.in.file.handle = _h1;
413 qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
415 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
416 CHECK_STATUS(status, NT_STATUS_OK);
418 /* re-authenticate as original user again */
420 status = smb2_session_setup_spnego(tree->session,
421 cmdline_credentials,
422 0 /* previous_session_id */);
423 CHECK_STATUS(status, NT_STATUS_OK);
425 /* try to access the file via the old handle */
427 ZERO_STRUCT(qfinfo);
429 qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
430 qfinfo.query_secdesc.in.file.handle = _h1;
431 qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
433 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
434 CHECK_STATUS(status, NT_STATUS_OK);
436 done:
437 if (h1 != NULL) {
438 smb2_util_close(tree, *h1);
441 smb2_util_unlink(tree, fname);
443 talloc_free(tree);
445 talloc_free(mem_ctx);
447 return ret;
451 * test setting security descriptor after reauth.
453 bool test_session_reauth4(struct torture_context *tctx, struct smb2_tree *tree)
455 NTSTATUS status;
456 TALLOC_CTX *mem_ctx = talloc_new(tctx);
457 char fname[256];
458 struct smb2_handle _h1;
459 struct smb2_handle *h1 = NULL;
460 struct smb2_create io1;
461 bool ret = true;
462 union smb_fileinfo qfinfo;
463 union smb_setfileinfo sfinfo;
464 struct cli_credentials *anon_creds = NULL;
465 uint32_t secinfo_flags = SECINFO_OWNER
466 | SECINFO_GROUP
467 | SECINFO_DACL
468 | SECINFO_PROTECTED_DACL
469 | SECINFO_UNPROTECTED_DACL;
470 struct security_descriptor *sd1;
471 struct security_ace ace;
472 struct dom_sid *extra_sid;
474 /* Add some random component to the file name. */
475 snprintf(fname, sizeof(fname), "session_reauth4_%s.dat",
476 generate_random_str(tctx, 8));
478 smb2_util_unlink(tree, fname);
480 smb2_oplock_create_share(&io1, fname,
481 smb2_util_share_access(""),
482 smb2_util_oplock_level("b"));
484 status = smb2_create(tree, mem_ctx, &io1);
485 CHECK_STATUS(status, NT_STATUS_OK);
486 _h1 = io1.out.file.handle;
487 h1 = &_h1;
488 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
489 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
491 /* get the security descriptor */
493 ZERO_STRUCT(qfinfo);
495 qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
496 qfinfo.query_secdesc.in.file.handle = _h1;
497 qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
499 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
500 CHECK_STATUS(status, NT_STATUS_OK);
502 sd1 = qfinfo.query_secdesc.out.sd;
504 /* re-authenticate as anonymous */
506 anon_creds = cli_credentials_init_anon(mem_ctx);
507 torture_assert(tctx, (anon_creds != NULL), "talloc error");
509 status = smb2_session_setup_spnego(tree->session,
510 anon_creds,
511 0 /* previous_session_id */);
512 CHECK_STATUS(status, NT_STATUS_OK);
514 /* give full access on the file to anonymous */
516 extra_sid = dom_sid_parse_talloc(tctx, SID_NT_ANONYMOUS);
518 ZERO_STRUCT(ace);
519 ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
520 ace.flags = 0;
521 ace.access_mask = SEC_STD_ALL | SEC_FILE_ALL;
522 ace.trustee = *extra_sid;
524 status = security_descriptor_dacl_add(sd1, &ace);
525 CHECK_STATUS(status, NT_STATUS_OK);
527 ZERO_STRUCT(sfinfo);
528 sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
529 sfinfo.set_secdesc.in.file.handle = _h1;
530 sfinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL;
531 sfinfo.set_secdesc.in.sd = sd1;
533 status = smb2_setinfo_file(tree, &sfinfo);
534 CHECK_STATUS(status, NT_STATUS_OK);
536 /* re-authenticate as original user again */
538 status = smb2_session_setup_spnego(tree->session,
539 cmdline_credentials,
540 0 /* previous_session_id */);
541 CHECK_STATUS(status, NT_STATUS_OK);
543 /* re-get the security descriptor */
545 ZERO_STRUCT(qfinfo);
547 qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
548 qfinfo.query_secdesc.in.file.handle = _h1;
549 qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
551 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
552 CHECK_STATUS(status, NT_STATUS_OK);
554 ret = true;
556 done:
557 if (h1 != NULL) {
558 smb2_util_close(tree, *h1);
561 smb2_util_unlink(tree, fname);
563 talloc_free(tree);
565 talloc_free(mem_ctx);
567 return ret;
571 * test renaming after reauth.
572 * compare security descriptors before and after rename/reauth
574 bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
576 NTSTATUS status;
577 TALLOC_CTX *mem_ctx = talloc_new(tctx);
578 char dname[256];
579 char fname[256];
580 char fname2[256];
581 struct smb2_handle _dh1;
582 struct smb2_handle *dh1 = NULL;
583 struct smb2_handle _h1;
584 struct smb2_handle *h1 = NULL;
585 struct smb2_create io1;
586 bool ret = true;
587 bool ok;
588 union smb_fileinfo qfinfo;
589 union smb_setfileinfo sfinfo;
590 struct cli_credentials *anon_creds = NULL;
591 uint32_t secinfo_flags = SECINFO_OWNER
592 | SECINFO_GROUP
593 | SECINFO_DACL
594 | SECINFO_PROTECTED_DACL
595 | SECINFO_UNPROTECTED_DACL;
596 struct security_descriptor *f_sd1;
597 struct security_descriptor *d_sd1 = NULL;
598 struct security_ace ace;
599 struct dom_sid *extra_sid;
601 /* Add some random component to the file name. */
602 snprintf(dname, sizeof(dname), "session_reauth5_%s.d",
603 generate_random_str(tctx, 8));
604 snprintf(fname, sizeof(fname), "%s\\file.dat", dname);
606 ok = smb2_util_setup_dir(tctx, tree, dname);
607 CHECK_VAL(ok, true);
609 status = torture_smb2_testdir(tree, dname, &_dh1);
610 CHECK_STATUS(status, NT_STATUS_OK);
611 dh1 = &_dh1;
613 smb2_oplock_create_share(&io1, fname,
614 smb2_util_share_access(""),
615 smb2_util_oplock_level("b"));
617 status = smb2_create(tree, mem_ctx, &io1);
618 CHECK_STATUS(status, NT_STATUS_OK);
619 _h1 = io1.out.file.handle;
620 h1 = &_h1;
621 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
622 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
624 /* get the security descriptor */
626 ZERO_STRUCT(qfinfo);
628 qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
629 qfinfo.query_secdesc.in.file.handle = _h1;
630 qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
632 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
633 CHECK_STATUS(status, NT_STATUS_OK);
635 f_sd1 = qfinfo.query_secdesc.out.sd;
637 /* re-authenticate as anonymous */
639 anon_creds = cli_credentials_init_anon(mem_ctx);
640 torture_assert(tctx, (anon_creds != NULL), "talloc error");
642 status = smb2_session_setup_spnego(tree->session,
643 anon_creds,
644 0 /* previous_session_id */);
645 CHECK_STATUS(status, NT_STATUS_OK);
647 /* try to rename the file: fails */
649 snprintf(fname2, sizeof(fname2), "%s\\file2.dat", dname);
651 smb2_util_unlink(tree, fname2);
653 ZERO_STRUCT(sfinfo);
654 sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
655 sfinfo.rename_information.in.file.handle = _h1;
656 sfinfo.rename_information.in.overwrite = true;
657 sfinfo.rename_information.in.new_name = fname2;
659 status = smb2_setinfo_file(tree, &sfinfo);
660 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
662 /* re-authenticate as original user again */
664 status = smb2_session_setup_spnego(tree->session,
665 cmdline_credentials,
666 0 /* previous_session_id */);
667 CHECK_STATUS(status, NT_STATUS_OK);
669 /* give full access on the file to anonymous */
671 extra_sid = dom_sid_parse_talloc(tctx, SID_NT_ANONYMOUS);
673 ZERO_STRUCT(ace);
674 ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
675 ace.flags = 0;
676 ace.access_mask = SEC_RIGHTS_FILE_ALL;
677 ace.trustee = *extra_sid;
679 status = security_descriptor_dacl_add(f_sd1, &ace);
680 CHECK_STATUS(status, NT_STATUS_OK);
682 ZERO_STRUCT(sfinfo);
683 sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
684 sfinfo.set_secdesc.in.file.handle = _h1;
685 sfinfo.set_secdesc.in.secinfo_flags = secinfo_flags;
686 sfinfo.set_secdesc.in.sd = f_sd1;
688 status = smb2_setinfo_file(tree, &sfinfo);
689 CHECK_STATUS(status, NT_STATUS_OK);
691 /* re-get the security descriptor */
693 ZERO_STRUCT(qfinfo);
695 qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
696 qfinfo.query_secdesc.in.file.handle = _h1;
697 qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
699 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
700 CHECK_STATUS(status, NT_STATUS_OK);
702 /* re-authenticate as anonymous - again */
704 anon_creds = cli_credentials_init_anon(mem_ctx);
705 torture_assert(tctx, (anon_creds != NULL), "talloc error");
707 status = smb2_session_setup_spnego(tree->session,
708 anon_creds,
709 0 /* previous_session_id */);
710 CHECK_STATUS(status, NT_STATUS_OK);
712 /* try to rename the file: fails */
714 ZERO_STRUCT(sfinfo);
715 sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
716 sfinfo.rename_information.in.file.handle = _h1;
717 sfinfo.rename_information.in.overwrite = true;
718 sfinfo.rename_information.in.new_name = fname2;
720 status = smb2_setinfo_file(tree, &sfinfo);
721 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
723 /* give full access on the parent dir to anonymous */
725 ZERO_STRUCT(qfinfo);
727 qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
728 qfinfo.query_secdesc.in.file.handle = _dh1;
729 qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
731 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
732 CHECK_STATUS(status, NT_STATUS_OK);
734 d_sd1 = qfinfo.query_secdesc.out.sd;
736 ZERO_STRUCT(ace);
737 ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
738 ace.flags = 0;
739 ace.access_mask = SEC_RIGHTS_FILE_ALL;
740 ace.trustee = *extra_sid;
742 status = security_descriptor_dacl_add(d_sd1, &ace);
743 CHECK_STATUS(status, NT_STATUS_OK);
745 ZERO_STRUCT(sfinfo);
746 sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
747 sfinfo.set_secdesc.in.file.handle = _dh1;
748 sfinfo.set_secdesc.in.secinfo_flags = secinfo_flags;
749 sfinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL;
750 sfinfo.set_secdesc.in.sd = d_sd1;
752 status = smb2_setinfo_file(tree, &sfinfo);
753 CHECK_STATUS(status, NT_STATUS_OK);
755 ZERO_STRUCT(qfinfo);
757 qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
758 qfinfo.query_secdesc.in.file.handle = _dh1;
759 qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
761 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
762 CHECK_STATUS(status, NT_STATUS_OK);
764 smb2_util_close(tree, _dh1);
765 dh1 = NULL;
767 /* try to rename the file: still fails */
769 ZERO_STRUCT(sfinfo);
770 sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
771 sfinfo.rename_information.in.file.handle = _h1;
772 sfinfo.rename_information.in.overwrite = true;
773 sfinfo.rename_information.in.new_name = fname2;
775 status = smb2_setinfo_file(tree, &sfinfo);
776 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
778 /* re-authenticate as original user - again */
780 status = smb2_session_setup_spnego(tree->session,
781 cmdline_credentials,
782 0 /* previous_session_id */);
783 CHECK_STATUS(status, NT_STATUS_OK);
785 /* rename the file - for verification that it works */
787 ZERO_STRUCT(sfinfo);
788 sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
789 sfinfo.rename_information.in.file.handle = _h1;
790 sfinfo.rename_information.in.overwrite = true;
791 sfinfo.rename_information.in.new_name = fname2;
793 status = smb2_setinfo_file(tree, &sfinfo);
794 CHECK_STATUS(status, NT_STATUS_OK);
796 /* closs the file, check it is gone and reopen under the new name */
798 smb2_util_close(tree, _h1);
800 ZERO_STRUCT(io1);
802 smb2_generic_create_share(&io1,
803 NULL /* lease */, false /* dir */,
804 fname,
805 NTCREATEX_DISP_OPEN,
806 smb2_util_share_access(""),
807 smb2_util_oplock_level("b"),
808 0 /* leasekey */, 0 /* leasestate */);
810 status = smb2_create(tree, mem_ctx, &io1);
811 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
813 ZERO_STRUCT(io1);
815 smb2_generic_create_share(&io1,
816 NULL /* lease */, false /* dir */,
817 fname2,
818 NTCREATEX_DISP_OPEN,
819 smb2_util_share_access(""),
820 smb2_util_oplock_level("b"),
821 0 /* leasekey */, 0 /* leasestate */);
823 status = smb2_create(tree, mem_ctx, &io1);
824 CHECK_STATUS(status, NT_STATUS_OK);
825 _h1 = io1.out.file.handle;
826 h1 = &_h1;
827 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
828 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
830 /* try to access the file via the old handle */
832 ZERO_STRUCT(qfinfo);
834 qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
835 qfinfo.query_secdesc.in.file.handle = _h1;
836 qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
838 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
839 CHECK_STATUS(status, NT_STATUS_OK);
841 done:
842 if (dh1 != NULL) {
843 smb2_util_close(tree, *dh1);
845 if (h1 != NULL) {
846 smb2_util_close(tree, *h1);
849 smb2_deltree(tree, dname);
851 talloc_free(tree);
853 talloc_free(mem_ctx);
855 return ret;
859 * do reauth with wrong credentials,
860 * hence triggering the error path in reauth.
861 * The invalid reauth deletes the session.
863 bool test_session_reauth6(struct torture_context *tctx, struct smb2_tree *tree)
865 NTSTATUS status;
866 TALLOC_CTX *mem_ctx = talloc_new(tctx);
867 char fname[256];
868 struct smb2_handle _h1;
869 struct smb2_handle *h1 = NULL;
870 struct smb2_create io1;
871 bool ret = true;
872 char *corrupted_password;
873 struct cli_credentials *broken_creds;
874 bool ok;
875 bool encrypted;
876 NTSTATUS expected;
877 enum credentials_use_kerberos krb_state;
879 krb_state = cli_credentials_get_kerberos_state(cmdline_credentials);
880 if (krb_state == CRED_MUST_USE_KERBEROS) {
881 torture_skip(tctx,
882 "Can't test failing session setup with kerberos.");
885 encrypted = smb2cli_tcon_is_encryption_on(tree->smbXcli);
887 /* Add some random component to the file name. */
888 snprintf(fname, sizeof(fname), "session_reauth1_%s.dat",
889 generate_random_str(tctx, 8));
891 smb2_util_unlink(tree, fname);
893 smb2_oplock_create_share(&io1, fname,
894 smb2_util_share_access(""),
895 smb2_util_oplock_level("b"));
896 io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
898 status = smb2_create(tree, mem_ctx, &io1);
899 CHECK_STATUS(status, NT_STATUS_OK);
900 _h1 = io1.out.file.handle;
901 h1 = &_h1;
902 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
903 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
906 * reauthentication with invalid credentials:
909 broken_creds = cli_credentials_shallow_copy(mem_ctx,
910 cmdline_credentials);
911 torture_assert(tctx, (broken_creds != NULL), "talloc error");
913 corrupted_password = talloc_asprintf(mem_ctx, "%s%s",
914 cli_credentials_get_password(broken_creds),
915 "corrupt");
916 torture_assert(tctx, (corrupted_password != NULL), "talloc error");
918 ok = cli_credentials_set_password(broken_creds, corrupted_password,
919 CRED_SPECIFIED);
920 CHECK_VAL(ok, true);
922 status = smb2_session_setup_spnego(tree->session,
923 broken_creds,
924 0 /* previous_session_id */);
925 CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
927 torture_comment(tctx, "did failed reauth\n");
929 * now verify that the invalid session reauth has closed our session
932 if (encrypted) {
933 expected = NT_STATUS_CONNECTION_DISCONNECTED;
934 } else {
935 expected = NT_STATUS_USER_SESSION_DELETED;
938 smb2_oplock_create_share(&io1, fname,
939 smb2_util_share_access(""),
940 smb2_util_oplock_level("b"));
942 status = smb2_create(tree, mem_ctx, &io1);
943 CHECK_STATUS(status, expected);
945 done:
946 if (h1 != NULL) {
947 smb2_util_close(tree, *h1);
950 smb2_util_unlink(tree, fname);
952 talloc_free(tree);
954 talloc_free(mem_ctx);
956 return ret;
960 static bool test_session_expire1(struct torture_context *tctx)
962 NTSTATUS status;
963 bool ret = false;
964 struct smbcli_options options;
965 const char *host = torture_setting_string(tctx, "host", NULL);
966 const char *share = torture_setting_string(tctx, "share", NULL);
967 struct cli_credentials *credentials = cmdline_credentials;
968 struct smb2_tree *tree = NULL;
969 enum credentials_use_kerberos use_kerberos;
970 char fname[256];
971 struct smb2_handle _h1;
972 struct smb2_handle *h1 = NULL;
973 struct smb2_create io1;
974 union smb_fileinfo qfinfo;
975 size_t i;
977 use_kerberos = cli_credentials_get_kerberos_state(credentials);
978 if (use_kerberos != CRED_MUST_USE_KERBEROS) {
979 torture_warning(tctx, "smb2.session.expire1 requires -k yes!");
980 torture_skip(tctx, "smb2.session.expire1 requires -k yes!");
983 torture_assert_int_equal(tctx, use_kerberos, CRED_MUST_USE_KERBEROS,
984 "please use -k yes");
986 lpcfg_set_option(tctx->lp_ctx, "gensec_gssapi:requested_life_time=4");
988 lpcfg_smbcli_options(tctx->lp_ctx, &options);
990 status = smb2_connect(tctx,
991 host,
992 lpcfg_smb_ports(tctx->lp_ctx),
993 share,
994 lpcfg_resolve_context(tctx->lp_ctx),
995 credentials,
996 &tree,
997 tctx->ev,
998 &options,
999 lpcfg_socket_options(tctx->lp_ctx),
1000 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
1002 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1003 "smb2_connect failed");
1005 /* Add some random component to the file name. */
1006 snprintf(fname, sizeof(fname), "session_expire1_%s.dat",
1007 generate_random_str(tctx, 8));
1009 smb2_util_unlink(tree, fname);
1011 smb2_oplock_create_share(&io1, fname,
1012 smb2_util_share_access(""),
1013 smb2_util_oplock_level("b"));
1014 io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1016 status = smb2_create(tree, tctx, &io1);
1017 CHECK_STATUS(status, NT_STATUS_OK);
1018 _h1 = io1.out.file.handle;
1019 h1 = &_h1;
1020 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1021 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
1023 /* get the security descriptor */
1025 ZERO_STRUCT(qfinfo);
1027 qfinfo.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
1028 qfinfo.access_information.in.file.handle = _h1;
1030 for (i=0; i < 2; i++) {
1031 torture_comment(tctx, "query info => OK\n");
1033 ZERO_STRUCT(qfinfo.access_information.out);
1034 status = smb2_getinfo_file(tree, tctx, &qfinfo);
1035 CHECK_STATUS(status, NT_STATUS_OK);
1037 torture_comment(tctx, "sleep 5 seconds\n");
1038 smb_msleep(5*1000);
1040 torture_comment(tctx, "query info => EXPIRED\n");
1041 ZERO_STRUCT(qfinfo.access_information.out);
1042 status = smb2_getinfo_file(tree, tctx, &qfinfo);
1043 CHECK_STATUS(status, NT_STATUS_NETWORK_SESSION_EXPIRED);
1046 * the krb5 library may not handle expired creds
1047 * well, lets start with an empty ccache.
1049 cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
1051 torture_comment(tctx, "reauth => OK\n");
1052 status = smb2_session_setup_spnego(tree->session,
1053 credentials,
1054 0 /* previous_session_id */);
1055 CHECK_STATUS(status, NT_STATUS_OK);
1058 ZERO_STRUCT(qfinfo.access_information.out);
1059 status = smb2_getinfo_file(tree, tctx, &qfinfo);
1060 CHECK_STATUS(status, NT_STATUS_OK);
1062 ret = true;
1063 done:
1064 if (h1 != NULL) {
1065 smb2_util_close(tree, *h1);
1068 talloc_free(tree);
1069 lpcfg_set_option(tctx->lp_ctx, "gensec_gssapi:requested_life_time=0");
1070 return ret;
1073 bool test_session_bind1(struct torture_context *tctx, struct smb2_tree *tree1)
1075 const char *host = torture_setting_string(tctx, "host", NULL);
1076 const char *share = torture_setting_string(tctx, "share", NULL);
1077 struct cli_credentials *credentials = cmdline_credentials;
1078 NTSTATUS status;
1079 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1080 char fname[256];
1081 struct smb2_handle _h1;
1082 struct smb2_handle *h1 = NULL;
1083 struct smb2_create io1;
1084 union smb_fileinfo qfinfo;
1085 bool ret = false;
1086 struct smb2_tree *tree2 = NULL;
1087 struct smb2_transport *transport1 = tree1->session->transport;
1088 struct smb2_transport *transport2 = NULL;
1089 struct smb2_session *session1_1 = tree1->session;
1090 struct smb2_session *session1_2 = NULL;
1091 struct smb2_session *session2_1 = NULL;
1092 struct smb2_session *session2_2 = NULL;
1093 uint32_t caps;
1095 caps = smb2cli_conn_server_capabilities(transport1->conn);
1096 if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
1097 torture_skip(tctx, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
1100 /* Add some random component to the file name. */
1101 snprintf(fname, sizeof(fname), "session_bind1_%s.dat",
1102 generate_random_str(tctx, 8));
1104 smb2_util_unlink(tree1, fname);
1106 smb2_oplock_create_share(&io1, fname,
1107 smb2_util_share_access(""),
1108 smb2_util_oplock_level("b"));
1110 status = smb2_create(tree1, mem_ctx, &io1);
1111 CHECK_STATUS(status, NT_STATUS_OK);
1112 _h1 = io1.out.file.handle;
1113 h1 = &_h1;
1114 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1115 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
1117 status = smb2_connect(tctx,
1118 host,
1119 lpcfg_smb_ports(tctx->lp_ctx),
1120 share,
1121 lpcfg_resolve_context(tctx->lp_ctx),
1122 credentials,
1123 &tree2,
1124 tctx->ev,
1125 &transport1->options,
1126 lpcfg_socket_options(tctx->lp_ctx),
1127 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
1129 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1130 "smb2_connect failed");
1131 session2_2 = tree2->session;
1132 transport2 = tree2->session->transport;
1135 * Now bind the 2nd transport connection to the 1st session
1137 session1_2 = smb2_session_channel(transport2,
1138 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
1139 tree2,
1140 session1_1);
1141 torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
1143 status = smb2_session_setup_spnego(session1_2,
1144 cmdline_credentials,
1145 0 /* previous_session_id */);
1146 CHECK_STATUS(status, NT_STATUS_OK);
1148 /* use the 1st connection, 1st session */
1149 ZERO_STRUCT(qfinfo);
1150 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
1151 qfinfo.generic.in.file.handle = _h1;
1152 tree1->session = session1_1;
1153 status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
1154 CHECK_STATUS(status, NT_STATUS_OK);
1156 /* use the 2nd connection, 1st session */
1157 ZERO_STRUCT(qfinfo);
1158 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
1159 qfinfo.generic.in.file.handle = _h1;
1160 tree1->session = session1_2;
1161 status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
1162 CHECK_STATUS(status, NT_STATUS_OK);
1164 tree1->session = session1_1;
1165 smb2_util_close(tree1, *h1);
1166 h1 = NULL;
1169 * Now bind the 1st transport connection to the 2nd session
1171 session2_1 = smb2_session_channel(transport1,
1172 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
1173 tree1,
1174 session2_2);
1175 torture_assert(tctx, session2_1 != NULL, "smb2_session_channel failed");
1177 status = smb2_session_setup_spnego(session2_1,
1178 cmdline_credentials,
1179 0 /* previous_session_id */);
1180 CHECK_STATUS(status, NT_STATUS_OK);
1182 tree2->session = session2_1;
1183 status = smb2_util_unlink(tree2, fname);
1184 CHECK_STATUS(status, NT_STATUS_OK);
1186 ret = true;
1187 done:
1188 talloc_free(tree2);
1189 tree1->session = session1_1;
1191 if (h1 != NULL) {
1192 smb2_util_close(tree1, *h1);
1195 smb2_util_unlink(tree1, fname);
1197 talloc_free(tree1);
1199 talloc_free(mem_ctx);
1201 return ret;
1204 struct torture_suite *torture_smb2_session_init(void)
1206 struct torture_suite *suite =
1207 torture_suite_create(talloc_autofree_context(), "session");
1209 torture_suite_add_1smb2_test(suite, "reconnect1", test_session_reconnect1);
1210 torture_suite_add_1smb2_test(suite, "reconnect2", test_session_reconnect2);
1211 torture_suite_add_1smb2_test(suite, "reauth1", test_session_reauth1);
1212 torture_suite_add_1smb2_test(suite, "reauth2", test_session_reauth2);
1213 torture_suite_add_1smb2_test(suite, "reauth3", test_session_reauth3);
1214 torture_suite_add_1smb2_test(suite, "reauth4", test_session_reauth4);
1215 torture_suite_add_1smb2_test(suite, "reauth5", test_session_reauth5);
1216 torture_suite_add_1smb2_test(suite, "reauth6", test_session_reauth6);
1217 torture_suite_add_simple_test(suite, "expire1", test_session_expire1);
1218 torture_suite_add_1smb2_test(suite, "bind1", test_session_bind1);
1220 suite->description = talloc_strdup(suite, "SMB2-SESSION tests");
1222 return suite;