/* Unix SMB/CIFS implementation. test suite for SMB2 session setups Copyright (C) Michael Adam 2012 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "includes.h" #include "libcli/smb2/smb2.h" #include "libcli/smb2/smb2_calls.h" #include "torture/torture.h" #include "torture/util.h" #include "torture/smb2/proto.h" #include "../libcli/smb/smbXcli_base.h" #include "lib/cmdline/cmdline.h" #include "auth/credentials/credentials.h" #include "auth/credentials/credentials_krb5.h" #include "libcli/security/security.h" #include "libcli/resolve/resolve.h" #include "lib/param/param.h" #include "lib/util/tevent_ntstatus.h" /* Ticket lifetime we want to request in seconds */ #define KRB5_TICKET_LIFETIME 5 /* Allowed clock skew in seconds */ #define KRB5_CLOCKSKEW 5 /* Time till ticket fully expired in seconds */ #define KRB5_TICKET_EXPIRETIME KRB5_TICKET_LIFETIME + KRB5_CLOCKSKEW #define texpand(x) #x #define GENSEC_GSSAPI_REQUESTED_LIFETIME(x) \ "gensec_gssapi:requested_life_time=" texpand(x) #define CHECK_CREATED(tctx, __io, __created, __attribute) \ do { \ torture_assert_int_equal(tctx, (__io)->out.create_action, \ NTCREATEX_ACTION_ ## __created, \ "out.create_action incorrect"); \ torture_assert_int_equal(tctx, (__io)->out.size, 0, \ "out.size incorrect"); \ torture_assert_int_equal(tctx, (__io)->out.file_attr, \ (__attribute), \ "out.file_attr incorrect"); \ torture_assert_int_equal(tctx, (__io)->out.reserved2, 0, \ "out.reserverd2 incorrect"); \ } while(0) #define WAIT_FOR_ASYNC_RESPONSE(req) \ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \ if (tevent_loop_once(tctx->ev) != 0) { \ break; \ } \ } static void sleep_remaining(struct torture_context *tctx, const struct timeval *endtime) { struct timeval current = tevent_timeval_current(); double remaining_secs = timeval_elapsed2(¤t, endtime); remaining_secs = remaining_secs < 1.0 ? 1.0 : remaining_secs; torture_comment( tctx, "sleep for %2.f second(s) that the krb5 ticket expires", remaining_secs); smb_msleep((int)(remaining_secs * 1000)); } /** * basic test for doing a session reconnect */ bool test_session_reconnect1(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_handle _h2; struct smb2_handle *h2 = NULL; struct smb2_create io1, io2; uint64_t previous_session_id; bool ret = true; struct smb2_tree *tree2 = NULL; union smb_fileinfo qfinfo; /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_reconnect_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* disconnect, reconnect and then do durable reopen */ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli); torture_assert_goto(tctx, torture_smb2_connection_ext(tctx, previous_session_id, &tree->session->transport->options, &tree2), ret, done, "session reconnect failed\n"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_getinfo_file " "returned unexpected status"); h1 = NULL; smb2_oplock_create_share(&io2, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree2, mem_ctx, &io2); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); CHECK_CREATED(tctx, &io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); _h2 = io2.out.file.handle; h2 = &_h2; done: if (h1 != NULL) { smb2_util_close(tree, *h1); } if (h2 != NULL) { smb2_util_close(tree2, *h2); } if (tree2 != NULL) { smb2_util_unlink(tree2, fname); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(tree2); talloc_free(mem_ctx); return ret; } /** * basic test for doing a session reconnect on one connection */ bool test_session_reconnect2(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; uint64_t previous_session_id; bool ret = true; struct smb2_session *session2 = NULL; union smb_fileinfo qfinfo; /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_reconnect_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* disconnect, reconnect and then do durable reopen */ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli); torture_assert(tctx, torture_smb2_session_setup(tctx, tree->session->transport, previous_session_id, tctx, &session2), "session reconnect (on the same connection) failed"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_getinfo_file " "returned unexpected status"); h1 = NULL; done: if (h1 != NULL) { smb2_util_close(tree, *h1); } talloc_free(tree); talloc_free(session2); talloc_free(mem_ctx); return ret; } bool test_session_reauth1(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; union smb_fileinfo qfinfo; /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_reauth1_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); status = smb2_session_setup_spnego(tree->session, samba_cmdline_get_creds(), 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); status = smb2_session_setup_spnego(tree->session, samba_cmdline_get_creds(), 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); done: if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); return ret; } bool test_session_reauth2(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; union smb_fileinfo qfinfo; struct cli_credentials *anon_creds = NULL; /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_reauth2_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* re-authenticate as anonymous */ anon_creds = cli_credentials_init_anon(mem_ctx); torture_assert(tctx, (anon_creds != NULL), "talloc error"); status = smb2_session_setup_spnego(tree->session, anon_creds, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); /* re-authenticate as original user again */ status = smb2_session_setup_spnego(tree->session, samba_cmdline_get_creds(), 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); done: if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); return ret; } /** * test getting security descriptor after reauth */ bool test_session_reauth3(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; union smb_fileinfo qfinfo; struct cli_credentials *anon_creds = NULL; uint32_t secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL | SECINFO_PROTECTED_DACL | SECINFO_UNPROTECTED_DACL; /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_reauth3_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* get the security descriptor */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _h1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); /* re-authenticate as anonymous */ anon_creds = cli_credentials_init_anon(mem_ctx); torture_assert(tctx, (anon_creds != NULL), "talloc error"); status = smb2_session_setup_spnego(tree->session, anon_creds, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _h1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); /* re-authenticate as original user again */ status = smb2_session_setup_spnego(tree->session, samba_cmdline_get_creds(), 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _h1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); done: if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); return ret; } /** * test setting security descriptor after reauth. */ bool test_session_reauth4(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; union smb_fileinfo qfinfo; union smb_setfileinfo sfinfo; struct cli_credentials *anon_creds = NULL; uint32_t secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL | SECINFO_PROTECTED_DACL | SECINFO_UNPROTECTED_DACL; struct security_descriptor *sd1; struct security_ace ace; struct dom_sid *extra_sid; /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_reauth4_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* get the security descriptor */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _h1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); sd1 = qfinfo.query_secdesc.out.sd; /* re-authenticate as anonymous */ anon_creds = cli_credentials_init_anon(mem_ctx); torture_assert(tctx, (anon_creds != NULL), "talloc error"); status = smb2_session_setup_spnego(tree->session, anon_creds, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* give full access on the file to anonymous */ extra_sid = dom_sid_parse_talloc(tctx, SID_NT_ANONYMOUS); ZERO_STRUCT(ace); ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED; ace.flags = 0; ace.access_mask = SEC_STD_ALL | SEC_FILE_ALL; ace.trustee = *extra_sid; status = security_descriptor_dacl_add(sd1, &ace); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "security_descriptor_dacl_add failed"); ZERO_STRUCT(sfinfo); sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; sfinfo.set_secdesc.in.file.handle = _h1; sfinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL; sfinfo.set_secdesc.in.sd = sd1; status = smb2_setinfo_file(tree, &sfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file failed"); /* re-authenticate as original user again */ status = smb2_session_setup_spnego(tree->session, samba_cmdline_get_creds(), 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* re-get the security descriptor */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _h1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); ret = true; done: if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); return ret; } /** * test renaming after reauth. * compare security descriptors before and after rename/reauth */ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char dname[128]; char fname[256]; char fname2[256]; struct smb2_handle _dh1; struct smb2_handle *dh1 = NULL; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; bool ok; union smb_fileinfo qfinfo; union smb_setfileinfo sfinfo; struct cli_credentials *anon_creds = NULL; uint32_t secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL | SECINFO_PROTECTED_DACL | SECINFO_UNPROTECTED_DACL; struct security_descriptor *f_sd1; struct security_descriptor *d_sd1 = NULL; struct security_ace ace; struct dom_sid *extra_sid; /* Add some random component to the file name. */ snprintf(dname, sizeof(dname), "session_reauth5_%s.d", generate_random_str(tctx, 8)); snprintf(fname, sizeof(fname), "%s\\file.dat", dname); ok = smb2_util_setup_dir(tctx, tree, dname); torture_assert(tctx, ok, "smb2_util_setup_dir not ok"); status = torture_smb2_testdir(tree, dname, &_dh1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed"); dh1 = &_dh1; smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* get the security descriptor */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _h1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); f_sd1 = qfinfo.query_secdesc.out.sd; /* re-authenticate as anonymous */ anon_creds = cli_credentials_init_anon(mem_ctx); torture_assert(tctx, (anon_creds != NULL), "talloc error"); status = smb2_session_setup_spnego(tree->session, anon_creds, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* try to rename the file: fails */ snprintf(fname2, sizeof(fname2), "%s\\file2.dat", dname); status = smb2_util_unlink(tree, fname2); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_unlink failed"); ZERO_STRUCT(sfinfo); sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; sfinfo.rename_information.in.file.handle = _h1; sfinfo.rename_information.in.overwrite = true; sfinfo.rename_information.in.new_name = fname2; status = smb2_setinfo_file(tree, &sfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED, ret, done, "smb2_setinfo_file " "returned unexpected status"); /* re-authenticate as original user again */ status = smb2_session_setup_spnego(tree->session, samba_cmdline_get_creds(), 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* give full access on the file to anonymous */ extra_sid = dom_sid_parse_talloc(tctx, SID_NT_ANONYMOUS); ZERO_STRUCT(ace); ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED; ace.flags = 0; ace.access_mask = SEC_RIGHTS_FILE_ALL; ace.trustee = *extra_sid; status = security_descriptor_dacl_add(f_sd1, &ace); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "security_descriptor_dacl_add failed"); ZERO_STRUCT(sfinfo); sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; sfinfo.set_secdesc.in.file.handle = _h1; sfinfo.set_secdesc.in.secinfo_flags = secinfo_flags; sfinfo.set_secdesc.in.sd = f_sd1; status = smb2_setinfo_file(tree, &sfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file failed"); /* re-get the security descriptor */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _h1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); /* re-authenticate as anonymous - again */ anon_creds = cli_credentials_init_anon(mem_ctx); torture_assert(tctx, (anon_creds != NULL), "talloc error"); status = smb2_session_setup_spnego(tree->session, anon_creds, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* try to rename the file: fails */ ZERO_STRUCT(sfinfo); sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; sfinfo.rename_information.in.file.handle = _h1; sfinfo.rename_information.in.overwrite = true; sfinfo.rename_information.in.new_name = fname2; status = smb2_setinfo_file(tree, &sfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED, ret, done, "smb2_setinfo_file " "returned unexpected status"); /* give full access on the parent dir to anonymous */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _dh1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); d_sd1 = qfinfo.query_secdesc.out.sd; ZERO_STRUCT(ace); ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED; ace.flags = 0; ace.access_mask = SEC_RIGHTS_FILE_ALL; ace.trustee = *extra_sid; status = security_descriptor_dacl_add(d_sd1, &ace); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "security_descriptor_dacl_add failed"); ZERO_STRUCT(sfinfo); sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; sfinfo.set_secdesc.in.file.handle = _dh1; sfinfo.set_secdesc.in.secinfo_flags = secinfo_flags; sfinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL; sfinfo.set_secdesc.in.sd = d_sd1; status = smb2_setinfo_file(tree, &sfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file failed"); ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _dh1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); status = smb2_util_close(tree, _dh1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed"); dh1 = NULL; /* try to rename the file: still fails */ ZERO_STRUCT(sfinfo); sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; sfinfo.rename_information.in.file.handle = _h1; sfinfo.rename_information.in.overwrite = true; sfinfo.rename_information.in.new_name = fname2; status = smb2_setinfo_file(tree, &sfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED, ret, done, "smb2_setinfo_file " "returned unexpected status"); /* re-authenticate as original user - again */ status = smb2_session_setup_spnego(tree->session, samba_cmdline_get_creds(), 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* rename the file - for verification that it works */ ZERO_STRUCT(sfinfo); sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; sfinfo.rename_information.in.file.handle = _h1; sfinfo.rename_information.in.overwrite = true; sfinfo.rename_information.in.new_name = fname2; status = smb2_setinfo_file(tree, &sfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file failed"); /* closs the file, check it is gone and reopen under the new name */ status = smb2_util_close(tree, _h1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed"); ZERO_STRUCT(io1); smb2_generic_create_share(&io1, NULL /* lease */, false /* dir */, fname, NTCREATEX_DISP_OPEN, smb2_util_share_access(""), smb2_util_oplock_level("b"), 0 /* leasekey */, 0 /* leasestate */); status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_create " "returned unexpected status"); ZERO_STRUCT(io1); smb2_generic_create_share(&io1, NULL /* lease */, false /* dir */, fname2, NTCREATEX_DISP_OPEN, smb2_util_share_access(""), smb2_util_oplock_level("b"), 0 /* leasekey */, 0 /* leasestate */); status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _h1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); done: if (dh1 != NULL) { smb2_util_close(tree, *dh1); } if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_deltree(tree, dname); talloc_free(tree); talloc_free(mem_ctx); return ret; } /** * do reauth with wrong credentials, * hence triggering the error path in reauth. * The invalid reauth deletes the session. */ bool test_session_reauth6(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; char *corrupted_password; struct cli_credentials *broken_creds; bool ok; bool encrypted; NTSTATUS expected; enum credentials_use_kerberos krb_state; krb_state = cli_credentials_get_kerberos_state( samba_cmdline_get_creds()); if (krb_state == CRED_USE_KERBEROS_REQUIRED) { torture_skip(tctx, "Can't test failing session setup with kerberos."); } encrypted = smb2cli_tcon_is_encryption_on(tree->smbXcli); /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_reauth1_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* * reauthentication with invalid credentials: */ broken_creds = cli_credentials_shallow_copy(mem_ctx, samba_cmdline_get_creds()); torture_assert(tctx, (broken_creds != NULL), "talloc error"); corrupted_password = talloc_asprintf(mem_ctx, "%s%s", cli_credentials_get_password(broken_creds), "corrupt"); torture_assert(tctx, (corrupted_password != NULL), "talloc error"); ok = cli_credentials_set_password(broken_creds, corrupted_password, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_password not ok"); status = smb2_session_setup_spnego(tree->session, broken_creds, 0 /* previous_session_id */); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_LOGON_FAILURE, ret, done, "smb2_session_setup_spnego " "returned unexpected status"); torture_comment(tctx, "did failed reauth\n"); /* * now verify that the invalid session reauth has closed our session */ if (encrypted) { expected = NT_STATUS_CONNECTION_DISCONNECTED; } else { expected = NT_STATUS_USER_SESSION_DELETED; } smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_equal_goto(tctx, status, expected, ret, done, "smb2_create " "returned unexpected status"); done: if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); return ret; } static bool test_session_expire1i(struct torture_context *tctx, bool force_signing, bool force_encryption) { NTSTATUS status; bool ret = false; struct smbcli_options options; const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); struct cli_credentials *credentials = samba_cmdline_get_creds(); struct smb2_tree *tree = NULL; enum credentials_use_kerberos use_kerberos; char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; union smb_fileinfo qfinfo; size_t i; struct timeval endtime; bool ticket_expired = false; use_kerberos = cli_credentials_get_kerberos_state(credentials); if (use_kerberos != CRED_USE_KERBEROS_REQUIRED) { torture_warning(tctx, "smb2.session.expire1 requires " "--use-kerberos=required!"); torture_skip(tctx, "smb2.session.expire1 requires " "--use-kerberos=required!"); } torture_assert_int_equal(tctx, use_kerberos, CRED_USE_KERBEROS_REQUIRED, "please use --use-kerberos=required"); cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); lpcfg_set_option( tctx->lp_ctx, GENSEC_GSSAPI_REQUESTED_LIFETIME(KRB5_TICKET_LIFETIME)); lpcfg_smbcli_options(tctx->lp_ctx, &options); if (force_signing) { options.signing = SMB_SIGNING_REQUIRED; } status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials, &tree, tctx->ev, &options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); /* * We request a ticket lifetime of KRB5_TICKET_LIFETIME seconds. * Give the server at least KRB5_TICKET_LIFETIME + KRB5_CLOCKSKEW + a * few more milliseconds for this to kick in. */ endtime = timeval_current_ofs(KRB5_TICKET_EXPIRETIME, 500 * 1000); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect failed"); if (force_encryption) { status = smb2cli_session_encryption_on(tree->session->smbXcli); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2cli_session_encryption_on failed"); } /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_expire1_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; status = smb2_create(tree, tctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* get the security descriptor */ ZERO_STRUCT(qfinfo); qfinfo.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; qfinfo.access_information.in.file.handle = _h1; for (i=0; i < 2; i++) { torture_comment(tctx, "%s: query info => OK\n", current_timestring(tctx, true)); ZERO_STRUCT(qfinfo.access_information.out); status = smb2_getinfo_file(tree, tctx, &qfinfo); torture_comment(tctx, "%s: %s:%s: after smb2_getinfo_file() => %s\n", current_timestring(tctx, true), __location__, __func__, nt_errstr(status)); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); sleep_remaining(tctx, &endtime); torture_comment(tctx, "%s: query info => EXPIRED\n", current_timestring(tctx, true)); ZERO_STRUCT(qfinfo.access_information.out); status = smb2_getinfo_file(tree, tctx, &qfinfo); torture_comment(tctx, "%s: %s:%s: after smb2_getinfo_file() => %s\n", current_timestring(tctx, true), __location__, __func__, nt_errstr(status)); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_getinfo_file " "returned unexpected status"); /* * the krb5 library may not handle expired creds * well, lets start with an empty ccache. */ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); if (!force_encryption) { smb2cli_session_require_signed_response( tree->session->smbXcli, true); } torture_comment(tctx, "%s: reauth => OK\n", current_timestring(tctx, true)); status = smb2_session_setup_spnego(tree->session, credentials, 0 /* previous_session_id */); /* * We request a ticket lifetime of KRB5_TICKET_LIFETIME seconds. * Give the server at least KRB5_TICKET_LIFETIME + * KRB5_CLOCKSKEW + a few more milliseconds for this to kick in. */ endtime = timeval_current_ofs(KRB5_TICKET_EXPIRETIME, 500 * 1000); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); smb2cli_session_require_signed_response( tree->session->smbXcli, false); } ticket_expired = timeval_expired(&endtime); if (ticket_expired) { struct timeval current = timeval_current(); double remaining_secs = timeval_elapsed2(¤t, &endtime); remaining_secs = remaining_secs < 0.0 ? remaining_secs * -1.0 : remaining_secs; torture_warning( tctx, "The ticket already expired %.2f seconds ago. " "You might want to increase KRB5_TICKET_LIFETIME.", remaining_secs); } torture_assert(tctx, ticket_expired == false, "The kerberos ticket already expired"); ZERO_STRUCT(qfinfo.access_information.out); torture_comment(tctx, "%s: %s:%s: before smb2_getinfo_file()\n", current_timestring(tctx, true), __location__, __func__); status = smb2_getinfo_file(tree, tctx, &qfinfo); torture_comment(tctx, "%s: %s:%s: after smb2_getinfo_file() => %s\n", current_timestring(tctx, true), __location__, __func__, nt_errstr(status)); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); ret = true; done: cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); if (h1 != NULL) { smb2_util_close(tree, *h1); } talloc_free(tree); lpcfg_set_option(tctx->lp_ctx, GENSEC_GSSAPI_REQUESTED_LIFETIME(0)); return ret; } static bool test_session_expire1n(struct torture_context *tctx) { return test_session_expire1i(tctx, false, /* force_signing */ false); /* force_encryption */ } static bool test_session_expire1s(struct torture_context *tctx) { return test_session_expire1i(tctx, true, /* force_signing */ false); /* force_encryption */ } static bool test_session_expire1e(struct torture_context *tctx) { return test_session_expire1i(tctx, true, /* force_signing */ true); /* force_encryption */ } static bool test_session_expire2i(struct torture_context *tctx, bool force_encryption) { NTSTATUS status; bool ret = false; struct smbcli_options options; const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); struct cli_credentials *credentials = samba_cmdline_get_creds(); struct smb2_tree *tree = NULL; const char *unc = NULL; struct smb2_tree *tree2 = NULL; struct tevent_req *subreq = NULL; uint32_t timeout_msec; enum credentials_use_kerberos use_kerberos; uint32_t caps; char fname[256]; struct smb2_handle dh; struct smb2_handle dh2; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; union smb_fileinfo qfinfo; union smb_setfileinfo sfinfo; struct smb2_flush flsh; struct smb2_read rd; const uint8_t wd = 0; struct smb2_lock lck; struct smb2_lock_element el; struct smb2_ioctl ctl; struct smb2_break oack; struct smb2_lease_break_ack lack; struct smb2_find fnd; union smb_search_data *d = NULL; unsigned int count; struct smb2_request *req = NULL; struct smb2_notify ntf1; struct smb2_notify ntf2; struct timeval endtime; use_kerberos = cli_credentials_get_kerberos_state(credentials); if (use_kerberos != CRED_USE_KERBEROS_REQUIRED) { torture_warning(tctx, "smb2.session.expire1 requires " "--use-kerberos=required!"); torture_skip(tctx, "smb2.session.expire1 requires " "--use-kerberos=required!"); } torture_assert_int_equal(tctx, use_kerberos, CRED_USE_KERBEROS_REQUIRED, "please use --use-kerberos=required"); cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); lpcfg_set_option( tctx->lp_ctx, GENSEC_GSSAPI_REQUESTED_LIFETIME(KRB5_TICKET_LIFETIME)); lpcfg_smbcli_options(tctx->lp_ctx, &options); options.signing = SMB_SIGNING_REQUIRED; unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share); torture_assert(tctx, unc != NULL, "talloc_asprintf"); status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials, &tree, tctx->ev, &options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); /* * We request a ticket lifetime of KRB5_TICKET_LIFETIME seconds. * Give the server at least KRB5_TICKET_LIFETIME + KRB5_CLOCKSKEW + a * few more milliseconds for this to kick in. */ endtime = timeval_current_ofs(KRB5_TICKET_EXPIRETIME, 500 * 1000); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect failed"); if (force_encryption) { status = smb2cli_session_encryption_on(tree->session->smbXcli); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2cli_session_encryption_on failed"); } caps = smb2cli_conn_server_capabilities(tree->session->transport->conn); /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_expire2_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); status = smb2_util_roothandle(tree, &dh); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_roothandle failed"); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; status = smb2_create(tree, tctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* get the security descriptor */ ZERO_STRUCT(qfinfo); qfinfo.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; qfinfo.access_information.in.file.handle = _h1; torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb2_getinfo_file(tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); torture_comment(tctx, "lock => OK\n"); ZERO_STRUCT(lck); lck.in.locks = ⪙ lck.in.lock_count = 0x0001; lck.in.lock_sequence = 0x00000000; lck.in.file.handle = *h1; ZERO_STRUCT(el); el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY; el.offset = 0x0000000000000000; el.length = 0x0000000000000001; status = smb2_lock(tree, &lck); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_lock lock failed"); torture_comment(tctx, "1st notify => PENDING\n"); ZERO_STRUCT(ntf1); ntf1.in.file.handle = dh; ntf1.in.recursive = 0x0000; ntf1.in.buffer_size = 128; ntf1.in.completion_filter= FILE_NOTIFY_CHANGE_ATTRIBUTES; ntf1.in.unknown = 0x00000000; req = smb2_notify_send(tree, &ntf1); while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { if (tevent_loop_once(tctx->ev) != 0) { break; } } torture_assert_goto(tctx, req->state <= SMB2_REQUEST_RECV, ret, done, "smb2_notify finished"); sleep_remaining(tctx, &endtime); torture_comment(tctx, "query info => EXPIRED\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb2_getinfo_file(tree, tctx, &qfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_getinfo_file " "returned unexpected status"); torture_comment(tctx, "set info => EXPIRED\n"); ZERO_STRUCT(sfinfo); sfinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; sfinfo.end_of_file_info.in.file.handle = *h1; sfinfo.end_of_file_info.in.size = 1; status = smb2_setinfo_file(tree, &sfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_setinfo_file " "returned unexpected status"); torture_comment(tctx, "flush => EXPIRED\n"); ZERO_STRUCT(flsh); flsh.in.file.handle = *h1; status = smb2_flush(tree, &flsh); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_flush " "returned unexpected status"); torture_comment(tctx, "read => EXPIRED\n"); ZERO_STRUCT(rd); rd.in.file.handle = *h1; rd.in.length = 5; rd.in.offset = 0; status = smb2_read(tree, tctx, &rd); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_read " "returned unexpected status"); torture_comment(tctx, "write => EXPIRED\n"); status = smb2_util_write(tree, *h1, &wd, 0, 1); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_util_write " "returned unexpected status"); torture_comment(tctx, "ioctl => EXPIRED\n"); ZERO_STRUCT(ctl); ctl.in.file.handle = *h1; ctl.in.function = FSCTL_SRV_ENUM_SNAPS; ctl.in.max_output_response = 16; ctl.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL; status = smb2_ioctl(tree, tctx, &ctl); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_ioctl " "returned unexpected status"); torture_comment(tctx, "oplock ack => EXPIRED\n"); ZERO_STRUCT(oack); oack.in.file.handle = *h1; status = smb2_break(tree, &oack); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_break " "returned unexpected status"); if (caps & SMB2_CAP_LEASING) { torture_comment(tctx, "lease ack => EXPIRED\n"); ZERO_STRUCT(lack); lack.in.lease.lease_version = 1; lack.in.lease.lease_key.data[0] = 1; lack.in.lease.lease_key.data[1] = 2; status = smb2_lease_break_ack(tree, &lack); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_break " "returned unexpected status"); } torture_comment(tctx, "query directory => EXPIRED\n"); ZERO_STRUCT(fnd); fnd.in.file.handle = dh; fnd.in.pattern = "*"; fnd.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE; fnd.in.max_response_size= 0x100; fnd.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO; status = smb2_find_level(tree, tree, &fnd, &count, &d); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_find_level " "returned unexpected status"); torture_comment(tctx, "1st notify => CANCEL\n"); smb2_cancel(req); torture_comment(tctx, "2nd notify => EXPIRED\n"); ZERO_STRUCT(ntf2); ntf2.in.file.handle = dh; ntf2.in.recursive = 0x0000; ntf2.in.buffer_size = 128; ntf2.in.completion_filter= FILE_NOTIFY_CHANGE_ATTRIBUTES; ntf2.in.unknown = 0x00000000; status = smb2_notify(tree, tctx, &ntf2); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_notify " "returned unexpected status"); torture_assert_goto(tctx, req->state > SMB2_REQUEST_RECV, ret, done, "smb2_notify (1st) not finished"); status = smb2_notify_recv(req, tctx, &ntf1); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_CANCELLED, ret, done, "smb2_notify cancelled" "returned unexpected status"); torture_comment(tctx, "tcon => EXPIRED\n"); tree2 = smb2_tree_init(tree->session, tctx, false); torture_assert(tctx, tree2 != NULL, "smb2_tree_init"); timeout_msec = tree->session->transport->options.request_timeout * 1000; subreq = smb2cli_tcon_send(tree2, tctx->ev, tree2->session->transport->conn, timeout_msec, tree2->session->smbXcli, tree2->smbXcli, 0, /* flags */ unc); torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send"); torture_assert(tctx, tevent_req_poll_ntstatus(subreq, tctx->ev, &status), "tevent_req_poll_ntstatus"); status = smb2cli_tcon_recv(subreq); TALLOC_FREE(subreq); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2cli_tcon" "returned unexpected status"); torture_comment(tctx, "create => EXPIRED\n"); status = smb2_util_roothandle(tree, &dh2); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_util_roothandle" "returned unexpected status"); torture_comment(tctx, "tdis => EXPIRED\n"); status = smb2_tdis(tree); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2cli_tdis" "returned unexpected status"); /* * (Un)Lock, Close and Logoff are still possible */ torture_comment(tctx, "1st unlock => OK\n"); el.flags = SMB2_LOCK_FLAG_UNLOCK; status = smb2_lock(tree, &lck); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_lock unlock failed"); torture_comment(tctx, "2nd unlock => RANGE_NOT_LOCKED\n"); status = smb2_lock(tree, &lck); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_RANGE_NOT_LOCKED, ret, done, "smb2_lock 2nd unlock" "returned unexpected status"); torture_comment(tctx, "lock => EXPIRED\n"); el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY; status = smb2_lock(tree, &lck); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_util_roothandle" "returned unexpected status"); torture_comment(tctx, "close => OK\n"); status = smb2_util_close(tree, *h1); h1 = NULL; torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_close failed"); torture_comment(tctx, "echo without session => OK\n"); status = smb2_keepalive(tree->session->transport); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_keepalive without session failed"); torture_comment(tctx, "echo with session => OK\n"); req = smb2_keepalive_send(tree->session->transport, tree->session); status = smb2_keepalive_recv(req); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_keepalive with session failed"); torture_comment(tctx, "logoff => OK\n"); status = smb2_logoff(tree->session); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_logoff failed"); ret = true; done: cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); if (h1 != NULL) { smb2_util_close(tree, *h1); } talloc_free(tree); lpcfg_set_option(tctx->lp_ctx, GENSEC_GSSAPI_REQUESTED_LIFETIME(0)); return ret; } static bool test_session_expire2s(struct torture_context *tctx) { return test_session_expire2i(tctx, false); /* force_encryption */ } static bool test_session_expire2e(struct torture_context *tctx) { return test_session_expire2i(tctx, true); /* force_encryption */ } static bool test_session_expire_disconnect(struct torture_context *tctx) { NTSTATUS status; bool ret = false; struct smbcli_options options; const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); struct cli_credentials *credentials = samba_cmdline_get_creds(); struct smb2_tree *tree = NULL; enum credentials_use_kerberos use_kerberos; char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; union smb_fileinfo qfinfo; bool connected; struct timeval endtime; use_kerberos = cli_credentials_get_kerberos_state(credentials); if (use_kerberos != CRED_USE_KERBEROS_REQUIRED) { torture_warning(tctx, "smb2.session.expire1 requires " "--use-kerberos=required!"); torture_skip(tctx, "smb2.session.expire1 requires " "--use-kerberos=required!"); } cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); lpcfg_set_option( tctx->lp_ctx, GENSEC_GSSAPI_REQUESTED_LIFETIME(KRB5_TICKET_LIFETIME)); lpcfg_smbcli_options(tctx->lp_ctx, &options); options.signing = SMB_SIGNING_REQUIRED; status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials, &tree, tctx->ev, &options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); /* * We request a ticket lifetime of KRB5_TICKET_LIFETIME seconds. * Give the server at least KRB5_TICKET_LIFETIME + KRB5_CLOCKSKEW + a * few more milliseconds for this to kick in. */ endtime = timeval_current_ofs(KRB5_TICKET_EXPIRETIME, 500 * 1000); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect failed"); smbXcli_session_set_disconnect_expired(tree->session->smbXcli); /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_expire1_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; status = smb2_create(tree, tctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* get the security descriptor */ ZERO_STRUCT(qfinfo); qfinfo.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; qfinfo.access_information.in.file.handle = _h1; torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb2_getinfo_file(tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); sleep_remaining(tctx, &endtime); torture_comment(tctx, "query info => EXPIRED\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb2_getinfo_file(tree, tctx, &qfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "smb2_getinfo_file " "returned unexpected status"); connected = smbXcli_conn_is_connected(tree->session->transport->conn); torture_assert_goto(tctx, !connected, ret, done, "connected\n"); ret = true; done: cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); if (h1 != NULL) { smb2_util_close(tree, *h1); } talloc_free(tree); lpcfg_set_option(tctx->lp_ctx, GENSEC_GSSAPI_REQUESTED_LIFETIME(0)); return ret; } bool test_session_bind1(struct torture_context *tctx, struct smb2_tree *tree1) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); struct cli_credentials *credentials = samba_cmdline_get_creds(); NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; union smb_fileinfo qfinfo; bool ret = false; struct smb2_tree *tree2 = NULL; struct smb2_transport *transport1 = tree1->session->transport; struct smbcli_options options2; struct smb2_transport *transport2 = NULL; struct smb2_session *session1_1 = tree1->session; struct smb2_session *session1_2 = NULL; struct smb2_session *session2_1 = NULL; struct smb2_session *session2_2 = NULL; uint32_t caps; caps = smb2cli_conn_server_capabilities(transport1->conn); if (!(caps & SMB2_CAP_MULTI_CHANNEL)) { torture_skip(tctx, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n"); } /* * We always want signing for this test! */ smb2cli_tcon_should_sign(tree1->smbXcli, true); options2 = transport1->options; options2.signing = SMB_SIGNING_REQUIRED; /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_bind1_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree1, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree1, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials, &tree2, tctx->ev, &options2, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect failed"); session2_2 = tree2->session; transport2 = tree2->session->transport; /* * Now bind the 2nd transport connection to the 1st session */ session1_2 = smb2_session_channel(transport2, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree2, session1_1); torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed"); status = smb2_session_setup_spnego(session1_2, samba_cmdline_get_creds(), 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* use the 1st connection, 1st session */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; tree1->session = session1_1; status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); /* use the 2nd connection, 1st session */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; tree1->session = session1_2; status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); tree1->session = session1_1; status = smb2_util_close(tree1, *h1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed"); h1 = NULL; /* * Now bind the 1st transport connection to the 2nd session */ session2_1 = smb2_session_channel(transport1, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree1, session2_2); torture_assert(tctx, session2_1 != NULL, "smb2_session_channel failed"); status = smb2_session_setup_spnego(session2_1, samba_cmdline_get_creds(), 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); tree2->session = session2_1; status = smb2_util_unlink(tree2, fname); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_unlink failed"); ret = true; done: talloc_free(tree2); tree1->session = session1_1; if (h1 != NULL) { smb2_util_close(tree1, *h1); } smb2_util_unlink(tree1, fname); talloc_free(tree1); talloc_free(mem_ctx); return ret; } static bool test_session_bind2(struct torture_context *tctx, struct smb2_tree *tree1) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); struct cli_credentials *credentials = samba_cmdline_get_creds(); NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname1[256]; char fname2[256]; struct smb2_handle _h1f1; struct smb2_handle *h1f1 = NULL; struct smb2_handle _h1f2; struct smb2_handle *h1f2 = NULL; struct smb2_handle _h2f2; struct smb2_handle *h2f2 = NULL; struct smb2_create io1f1; struct smb2_create io1f2; struct smb2_create io2f1; struct smb2_create io2f2; union smb_fileinfo qfinfo; bool ret = false; struct smb2_transport *transport1 = tree1->session->transport; struct smbcli_options options2; struct smb2_tree *tree2 = NULL; struct smb2_transport *transport2 = NULL; struct smbcli_options options3; struct smb2_tree *tree3 = NULL; struct smb2_transport *transport3 = NULL; struct smb2_session *session1_1 = tree1->session; struct smb2_session *session1_2 = NULL; struct smb2_session *session1_3 = NULL; struct smb2_session *session2_1 = NULL; struct smb2_session *session2_2 = NULL; struct smb2_session *session2_3 = NULL; uint32_t caps; caps = smb2cli_conn_server_capabilities(transport1->conn); if (!(caps & SMB2_CAP_MULTI_CHANNEL)) { torture_skip(tctx, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n"); } /* * We always want signing for this test! */ smb2cli_tcon_should_sign(tree1->smbXcli, true); options2 = transport1->options; options2.signing = SMB_SIGNING_REQUIRED; /* Add some random component to the file name. */ snprintf(fname1, sizeof(fname1), "session_bind2_1_%s.dat", generate_random_str(tctx, 8)); snprintf(fname2, sizeof(fname2), "session_bind2_2_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree1, fname1); smb2_util_unlink(tree1, fname2); smb2_oplock_create_share(&io1f1, fname1, smb2_util_share_access(""), smb2_util_oplock_level("")); smb2_oplock_create_share(&io1f2, fname2, smb2_util_share_access(""), smb2_util_oplock_level("")); status = smb2_create(tree1, mem_ctx, &io1f1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1f1 = io1f1.out.file.handle; h1f1 = &_h1f1; CHECK_CREATED(tctx, &io1f1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1f1.out.oplock_level, smb2_util_oplock_level(""), "oplock_level incorrect"); status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials, &tree2, tctx->ev, &options2, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect failed"); session2_2 = tree2->session; transport2 = tree2->session->transport; smb2cli_tcon_should_sign(tree2->smbXcli, true); smb2_oplock_create_share(&io2f1, fname1, smb2_util_share_access(""), smb2_util_oplock_level("")); smb2_oplock_create_share(&io2f2, fname2, smb2_util_share_access(""), smb2_util_oplock_level("")); status = smb2_create(tree2, mem_ctx, &io2f2); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h2f2 = io2f2.out.file.handle; h2f2 = &_h2f2; CHECK_CREATED(tctx, &io2f2, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io2f2.out.oplock_level, smb2_util_oplock_level(""), "oplock_level incorrect"); options3 = transport1->options; options3.signing = SMB_SIGNING_REQUIRED; options3.only_negprot = true; status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials, &tree3, tctx->ev, &options3, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect failed"); transport3 = tree3->session->transport; /* * Create a fake session for the 2nd transport connection to the 1st session */ session1_2 = smb2_session_channel(transport2, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree1, session1_1); torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed"); /* * Now bind the 3rd transport connection to the 1st session */ session1_3 = smb2_session_channel(transport3, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree1, session1_1); torture_assert(tctx, session1_3 != NULL, "smb2_session_channel failed"); status = smb2_session_setup_spnego(session1_3, credentials, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* * Create a fake session for the 1st transport connection to the 2nd session */ session2_1 = smb2_session_channel(transport1, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree2, session2_2); torture_assert(tctx, session2_1 != NULL, "smb2_session_channel failed"); /* * Now bind the 3rd transport connection to the 2nd session */ session2_3 = smb2_session_channel(transport3, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree2, session2_2); torture_assert(tctx, session2_3 != NULL, "smb2_session_channel failed"); status = smb2_session_setup_spnego(session2_3, credentials, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1f1; tree1->session = session1_1; status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); tree1->session = session1_2; status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_getinfo_file failed"); tree1->session = session1_3; status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h2f2; tree2->session = session2_1; status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_getinfo_file failed"); tree2->session = session2_2; status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); tree2->session = session2_3; status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); tree1->session = session1_1; status = smb2_create(tree1, mem_ctx, &io1f2); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done, "smb2_create failed"); tree1->session = session1_2; status = smb2_create(tree1, mem_ctx, &io1f2); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_create failed"); tree1->session = session1_3; status = smb2_create(tree1, mem_ctx, &io1f2); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done, "smb2_create failed"); tree2->session = session2_1; status = smb2_create(tree2, mem_ctx, &io2f1); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_create failed"); tree2->session = session2_2; status = smb2_create(tree2, mem_ctx, &io2f1); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done, "smb2_create failed"); tree2->session = session2_3; status = smb2_create(tree2, mem_ctx, &io2f1); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done, "smb2_create failed"); smbXcli_conn_disconnect(transport3->conn, NT_STATUS_LOCAL_DISCONNECT); smb_msleep(500); tree1->session = session1_1; status = smb2_create(tree1, mem_ctx, &io1f2); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done, "smb2_create failed"); tree1->session = session1_2; status = smb2_create(tree1, mem_ctx, &io1f2); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_create failed"); tree2->session = session2_1; status = smb2_create(tree2, mem_ctx, &io2f1); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_create failed"); tree2->session = session2_2; status = smb2_create(tree2, mem_ctx, &io2f1); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done, "smb2_create failed"); smbXcli_conn_disconnect(transport2->conn, NT_STATUS_LOCAL_DISCONNECT); smb_msleep(500); h2f2 = NULL; tree1->session = session1_1; status = smb2_create(tree1, mem_ctx, &io1f2); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1f2 = io1f2.out.file.handle; h1f2 = &_h1f2; CHECK_CREATED(tctx, &io1f2, EXISTED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1f2.out.oplock_level, smb2_util_oplock_level(""), "oplock_level incorrect"); tree1->session = session1_1; status = smb2_util_close(tree1, *h1f1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed"); h1f1 = NULL; ret = true; done: smbXcli_conn_disconnect(transport3->conn, NT_STATUS_LOCAL_DISCONNECT); smbXcli_conn_disconnect(transport2->conn, NT_STATUS_LOCAL_DISCONNECT); tree1->session = session1_1; tree2->session = session2_2; if (h1f1 != NULL) { smb2_util_close(tree1, *h1f1); } if (h1f2 != NULL) { smb2_util_close(tree1, *h1f2); } if (h2f2 != NULL) { smb2_util_close(tree2, *h2f2); } smb2_util_unlink(tree1, fname1); smb2_util_unlink(tree1, fname2); talloc_free(tree1); talloc_free(mem_ctx); return ret; } static bool test_session_bind_auth_mismatch(struct torture_context *tctx, struct smb2_tree *tree1, const char *testname, struct cli_credentials *creds1, struct cli_credentials *creds2, bool creds2_require_ok) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; union smb_fileinfo qfinfo; bool ret = false; struct smb2_tree *tree2 = NULL; struct smb2_transport *transport1 = tree1->session->transport; struct smbcli_options options2; struct smb2_transport *transport2 = NULL; struct smb2_session *session1_1 = tree1->session; struct smb2_session *session1_2 = NULL; struct smb2_session *session2_1 = NULL; struct smb2_session *session2_2 = NULL; struct smb2_session *session3_1 = NULL; uint32_t caps; bool encrypted; bool creds2_got_ok = false; encrypted = smb2cli_tcon_is_encryption_on(tree1->smbXcli); caps = smb2cli_conn_server_capabilities(transport1->conn); if (!(caps & SMB2_CAP_MULTI_CHANNEL)) { torture_skip(tctx, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n"); } /* * We always want signing for this test! */ smb2cli_tcon_should_sign(tree1->smbXcli, true); options2 = transport1->options; options2.signing = SMB_SIGNING_REQUIRED; /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "%s_%s.dat", testname, generate_random_str(tctx, 8)); smb2_util_unlink(tree1, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree1, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), creds1, &tree2, tctx->ev, &options2, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect failed"); session2_2 = tree2->session; transport2 = tree2->session->transport; /* * Now bind the 2nd transport connection to the 1st session */ session1_2 = smb2_session_channel(transport2, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree2, session1_1); torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed"); status = smb2_session_setup_spnego(session1_2, creds1, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* use the 1st connection, 1st session */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; tree1->session = session1_1; status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); /* use the 2nd connection, 1st session */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; tree1->session = session1_2; status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); tree1->session = session1_1; status = smb2_util_close(tree1, *h1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed"); h1 = NULL; /* * Create a 3rd session in order to check if the invalid (creds2) * are mapped to guest. */ session3_1 = smb2_session_init(transport1, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tctx); torture_assert(tctx, session3_1 != NULL, "smb2_session_channel failed"); status = smb2_session_setup_spnego(session3_1, creds2, 0 /* previous_session_id */); if (creds2_require_ok) { torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego worked"); creds2_got_ok = true; } else if (NT_STATUS_IS_OK(status)) { bool authentiated = smbXcli_session_is_authenticated(session3_1->smbXcli); torture_assert(tctx, !authentiated, "Invalid credentials allowed!"); creds2_got_ok = true; } else { torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_LOGON_FAILURE, ret, done, "smb2_session_setup_spnego worked"); } /* * Now bind the 1st transport connection to the 2nd session */ session2_1 = smb2_session_channel(transport1, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree1, session2_2); torture_assert(tctx, session2_1 != NULL, "smb2_session_channel failed"); tree2->session = session2_1; status = smb2_util_unlink(tree2, fname); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_util_unlink worked on invalid channel"); status = smb2_session_setup_spnego(session2_1, creds2, 0 /* previous_session_id */); if (creds2_got_ok) { /* * attaching with a different user (guest or anonymous) results * in ACCESS_DENIED. */ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED, ret, done, "smb2_session_setup_spnego worked"); } else { torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_LOGON_FAILURE, ret, done, "smb2_session_setup_spnego worked"); } tree2->session = session2_1; status = smb2_util_unlink(tree2, fname); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_util_unlink worked on invalid channel"); tree2->session = session2_2; status = smb2_util_unlink(tree2, fname); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_unlink failed"); status = smb2_util_unlink(tree2, fname); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_util_unlink worked"); if (creds2_got_ok) { /* * We got ACCESS_DENIED on the session bind * with a different user, now check that * the correct user can actually bind on * the same connection. */ TALLOC_FREE(session2_1); session2_1 = smb2_session_channel(transport1, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree1, session2_2); torture_assert(tctx, session2_1 != NULL, "smb2_session_channel failed"); status = smb2_session_setup_spnego(session2_1, creds1, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); tree2->session = session2_1; status = smb2_util_unlink(tree2, fname); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_util_unlink worked"); tree2->session = session2_2; } tree1->session = session1_1; status = smb2_util_unlink(tree1, fname); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_util_unlink worked"); tree1->session = session1_2; status = smb2_util_unlink(tree1, fname); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_util_unlink worked"); if (creds2_got_ok) { /* * With valid credentials, there's no point to test a failing * reauth. */ ret = true; goto done; } /* * Do a failing reauth the 2nd channel */ status = smb2_session_setup_spnego(session1_2, creds2, 0 /* previous_session_id */); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_LOGON_FAILURE, ret, done, "smb2_session_setup_spnego worked"); tree1->session = session1_1; status = smb2_util_unlink(tree1, fname); if (encrypted) { torture_assert_goto(tctx, !smbXcli_conn_is_connected(transport1->conn), ret, done, "smb2_util_unlink worked"); } else { torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_util_unlink worked"); } tree1->session = session1_2; status = smb2_util_unlink(tree1, fname); if (encrypted) { torture_assert_goto(tctx, !smbXcli_conn_is_connected(transport2->conn), ret, done, "smb2_util_unlink worked"); } else { torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done, "smb2_util_unlink worked"); } status = smb2_util_unlink(tree2, fname); if (encrypted) { torture_assert_goto(tctx, !smbXcli_conn_is_connected(transport1->conn), ret, done, "smb2_util_unlink worked"); torture_assert_goto(tctx, !smbXcli_conn_is_connected(transport2->conn), ret, done, "smb2_util_unlink worked"); } else { torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_util_unlink worked"); } ret = true; done: talloc_free(tree2); tree1->session = session1_1; if (h1 != NULL) { smb2_util_close(tree1, *h1); } smb2_util_unlink(tree1, fname); talloc_free(tree1); talloc_free(mem_ctx); return ret; } static bool test_session_bind_invalid_auth(struct torture_context *tctx, struct smb2_tree *tree1) { struct cli_credentials *credentials = samba_cmdline_get_creds(); struct cli_credentials *invalid_credentials = NULL; bool ret = false; invalid_credentials = cli_credentials_init(tctx); torture_assert(tctx, (invalid_credentials != NULL), "talloc error"); cli_credentials_set_username(invalid_credentials, "__none__invalid__none__", CRED_SPECIFIED); cli_credentials_set_domain(invalid_credentials, "__none__invalid__none__", CRED_SPECIFIED); cli_credentials_set_password(invalid_credentials, "__none__invalid__none__", CRED_SPECIFIED); cli_credentials_set_realm(invalid_credentials, NULL, CRED_SPECIFIED); cli_credentials_set_workstation(invalid_credentials, "", CRED_UNINITIALISED); ret = test_session_bind_auth_mismatch(tctx, tree1, __func__, credentials, invalid_credentials, false); return ret; } static bool test_session_bind_different_user(struct torture_context *tctx, struct smb2_tree *tree1) { struct cli_credentials *credentials1 = samba_cmdline_get_creds(); struct cli_credentials *credentials2 = torture_user2_credentials(tctx, tctx); char *u1 = cli_credentials_get_unparsed_name(credentials1, tctx); char *u2 = cli_credentials_get_unparsed_name(credentials2, tctx); bool ret = false; bool bval; torture_assert(tctx, (credentials2 != NULL), "talloc error"); bval = cli_credentials_is_anonymous(credentials2); if (bval) { torture_skip(tctx, "valid user2 credentials are required"); } bval = strequal(u1, u2); if (bval) { torture_skip(tctx, "different user2 credentials are required"); } ret = test_session_bind_auth_mismatch(tctx, tree1, __func__, credentials1, credentials2, true); return ret; } static bool test_session_bind_negative_smbXtoX(struct torture_context *tctx, const char *testname, struct cli_credentials *credentials, const struct smbcli_options *options1, const struct smbcli_options *options2, NTSTATUS bind_reject_status) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); NTSTATUS status; bool ret = false; struct smb2_tree *tree1 = NULL; struct smb2_session *session1_1 = NULL; char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; union smb_fileinfo qfinfo1; struct smb2_tree *tree2_0 = NULL; struct smb2_transport *transport2 = NULL; struct smb2_session *session1_2 = NULL; uint64_t session1_id = 0; uint16_t session1_flags = 0; NTSTATUS deleted_status = NT_STATUS_USER_SESSION_DELETED; status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials, &tree1, tctx->ev, options1, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect options1 failed"); session1_1 = tree1->session; session1_id = smb2cli_session_current_id(session1_1->smbXcli); session1_flags = smb2cli_session_get_flags(session1_1->smbXcli); /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "%s_%s.dat", testname, generate_random_str(tctx, 8)); smb2_util_unlink(tree1, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; status = smb2_create(tree1, tctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials, &tree2_0, tctx->ev, options2, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect options2 failed"); transport2 = tree2_0->session->transport; /* * Now bind the 2nd transport connection to the 1st session */ session1_2 = smb2_session_channel(transport2, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree2_0, session1_1); torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed"); status = smb2_session_setup_spnego(session1_2, credentials, 0 /* previous_session_id */); torture_assert_ntstatus_equal_goto(tctx, status, bind_reject_status, ret, done, "smb2_session_setup_spnego failed"); if (NT_STATUS_IS_OK(bind_reject_status)) { ZERO_STRUCT(qfinfo1); qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo1.generic.in.file.handle = _h1; tree1->session = session1_2; status = smb2_getinfo_file(tree1, tctx, &qfinfo1); tree1->session = session1_1; torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); } TALLOC_FREE(session1_2); /* Check the initial session is still alive */ ZERO_STRUCT(qfinfo1); qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo1.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree1, tctx, &qfinfo1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); if (NT_STATUS_IS_OK(bind_reject_status)) { deleted_status = NT_STATUS_ACCESS_DENIED; bind_reject_status = NT_STATUS_ACCESS_DENIED; } /* * I guess this is not part of MultipleChannel_Negative_SMB2002, * but we should also check the status without * SMB2_SESSION_FLAG_BINDING. */ session1_2 = smb2_session_channel(transport2, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree2_0, session1_1); torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed"); session1_2->needs_bind = false; status = smb2_session_setup_spnego(session1_2, credentials, 0 /* previous_session_id */); torture_assert_ntstatus_equal_goto(tctx, status, deleted_status, ret, done, "smb2_session_setup_spnego failed"); TALLOC_FREE(session1_2); /* * ... and we should also check the status without any existing * session keys. */ session1_2 = smb2_session_init(transport2, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree2_0); torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed"); talloc_steal(tree2_0->session, transport2); smb2cli_session_set_id_and_flags(session1_2->smbXcli, session1_id, session1_flags); status = smb2_session_setup_spnego(session1_2, credentials, 0 /* previous_session_id */); torture_assert_ntstatus_equal_goto(tctx, status, deleted_status, ret, done, "smb2_session_setup_spnego failed"); TALLOC_FREE(session1_2); /* Check the initial session is still alive */ ZERO_STRUCT(qfinfo1); qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo1.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree1, tctx, &qfinfo1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); /* * Now bind the 2nd transport connection to the 1st session (again) */ session1_2 = smb2_session_channel(transport2, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree2_0, session1_1); torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed"); status = smb2_session_setup_spnego(session1_2, credentials, 0 /* previous_session_id */); torture_assert_ntstatus_equal_goto(tctx, status, bind_reject_status, ret, done, "smb2_session_setup_spnego failed"); TALLOC_FREE(session1_2); /* Check the initial session is still alive */ ZERO_STRUCT(qfinfo1); qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo1.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree1, tctx, &qfinfo1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); ret = true; done: talloc_free(tree2_0); if (h1 != NULL) { smb2_util_close(tree1, *h1); } talloc_free(tree1); return ret; } /* * This is similar to the MultipleChannel_Negative_SMB2002 test * from the Windows Protocol Test Suite. * * It demonstrates that the server needs to do lookup * in the global session table in order to get the signing * and error code of invalid session setups correct. * * See: https://bugzilla.samba.org/show_bug.cgi?id=14512 * * Note you can ignore tree0... */ static bool test_session_bind_negative_smb202(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test SMB 2.02 if encryption is required"); } options1 = transport0->options; options1.client_guid = GUID_zero(); options1.max_protocol = PROTOCOL_SMB2_02; options2 = options1; options2.only_negprot = true; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_NOT_ACCEPTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb210s(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test SMB 2.10 if encryption is required"); } options1 = transport0->options; options1.client_guid = GUID_random(); options1.max_protocol = PROTOCOL_SMB2_10; /* same client guid */ options2 = options1; options2.only_negprot = true; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_NOT_ACCEPTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb210d(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test SMB 2.10 if encryption is required"); } options1 = transport0->options; options1.client_guid = GUID_random(); options1.max_protocol = PROTOCOL_SMB2_10; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_NOT_ACCEPTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb2to3s(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test SMB 2.10 if encryption is required"); } if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "Can't test without SMB3 support"); } options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB2_02; options1.max_protocol = PROTOCOL_SMB2_10; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB3_00; options2.max_protocol = PROTOCOL_SMB3_11; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_INVALID_PARAMETER); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb2to3d(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test SMB 2.10 if encryption is required"); } if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "Can't test without SMB3 support"); } options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB2_02; options1.max_protocol = PROTOCOL_SMB2_10; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB3_00; options2.max_protocol = PROTOCOL_SMB3_11; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_INVALID_PARAMETER); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3to2s(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test SMB 2.10 if encryption is required"); } if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "Can't test without SMB3 support"); } options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_00; options1.max_protocol = PROTOCOL_SMB3_11; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB2_02; options2.max_protocol = PROTOCOL_SMB2_10; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_NOT_ACCEPTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3to2d(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test SMB 2.10 if encryption is required"); } if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "Can't test without SMB3 support"); } options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_00; options1.max_protocol = PROTOCOL_SMB3_11; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB2_02; options2.max_protocol = PROTOCOL_SMB2_10; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_NOT_ACCEPTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3to3s(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_02; options1.max_protocol = PROTOCOL_SMB3_02; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB3_11; options2.max_protocol = PROTOCOL_SMB3_11; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_INVALID_PARAMETER); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3to3d(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_02; options1.max_protocol = PROTOCOL_SMB3_02; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB3_11; options2.max_protocol = PROTOCOL_SMB3_11; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_INVALID_PARAMETER); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3encGtoCs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_GCM, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_CCM, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_INVALID_PARAMETER); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3encGtoCd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_GCM, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_CCM, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_INVALID_PARAMETER); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signCtoHs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_OK); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signCtoHd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_OK); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signHtoCs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_OK); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signHtoCd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_OK); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signHtoGs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signHtoGd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signCtoGs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signCtoGd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signGtoCs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signGtoCd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signGtoHs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signGtoHd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3sneGtoCs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_GCM, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_CCM, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3sneGtoCd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_GCM, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_CCM, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3sneGtoHs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_GCM, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_CCM, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3sneGtoHd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_GCM, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_CCM, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3sneCtoGs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_CCM, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_GCM, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3sneCtoGd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_CCM, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_GCM, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3sneHtoGs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_CCM, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_GCM, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3sneHtoGd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_CCM, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_GCM, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signC30toGs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_00; options1.max_protocol = PROTOCOL_SMB3_02; options1.signing = SMB_SIGNING_REQUIRED; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB3_11; options2.max_protocol = PROTOCOL_SMB3_11; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signC30toGd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_00; options1.max_protocol = PROTOCOL_SMB3_02; options1.signing = SMB_SIGNING_REQUIRED; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB3_11; options2.max_protocol = PROTOCOL_SMB3_11; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signH2XtoGs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test SMB 2.10 if encryption is required"); } if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_OFF, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB2_02; options1.max_protocol = PROTOCOL_SMB2_10; options1.signing = SMB_SIGNING_REQUIRED; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB3_11; options2.max_protocol = PROTOCOL_SMB3_11; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signH2XtoGd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test SMB 2.10 if encryption is required"); } if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_OFF, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB2_02; options1.max_protocol = PROTOCOL_SMB2_10; options1.signing = SMB_SIGNING_REQUIRED; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB3_11; options2.max_protocol = PROTOCOL_SMB3_11; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_NOT_SUPPORTED); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signGtoC30s(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB3_00; options2.max_protocol = PROTOCOL_SMB3_02; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signGtoC30d(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB3_00; options2.max_protocol = PROTOCOL_SMB3_02; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signGtoH2Xs(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test SMB 2.10 if encryption is required"); } if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; /* same client guid */ options2 = options1; options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB2_02; options2.max_protocol = PROTOCOL_SMB2_10; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_bind_negative_smb3signGtoH2Xd(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; struct smbcli_options options2; bool ok; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test SMB 2.10 if encryption is required"); } if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; /* different client guid */ options2 = options1; options2.client_guid = GUID_random(); options2.only_negprot = true; options2.min_protocol = PROTOCOL_SMB2_02; options2.max_protocol = PROTOCOL_SMB2_10; options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; ret = test_session_bind_negative_smbXtoX(tctx, __func__, credentials, &options1, &options2, NT_STATUS_REQUEST_OUT_OF_SEQUENCE); talloc_free(tree0); return ret; } static bool test_session_two_logoff(struct torture_context *tctx, struct smb2_tree *tree1) { NTSTATUS status; bool ret = true; struct smbcli_options transport2_options; struct smb2_tree *tree2 = NULL; struct smb2_session *session2 = NULL; struct smb2_session *session1 = tree1->session; struct smb2_transport *transport1 = tree1->session->transport; struct smb2_transport *transport2; bool ok; /* Connect 2nd connection */ torture_comment(tctx, "connect tree2 with the same client_guid\n"); transport2_options = transport1->options; ok = torture_smb2_connection_ext(tctx, 0, &transport2_options, &tree2); torture_assert(tctx, ok, "couldn't connect tree2\n"); transport2 = tree2->session->transport; session2 = tree2->session; torture_comment(tctx, "session2: logoff\n"); status = smb2_logoff(session2); torture_assert_ntstatus_ok(tctx, status, "session2: logoff"); torture_comment(tctx, "transport2: keepalive\n"); status = smb2_keepalive(transport2); torture_assert_ntstatus_ok(tctx, status, "transport2: keepalive"); torture_comment(tctx, "transport2: disconnect\n"); TALLOC_FREE(tree2); torture_comment(tctx, "session1: logoff\n"); status = smb2_logoff(session1); torture_assert_ntstatus_ok(tctx, status, "session1: logoff"); torture_comment(tctx, "transport1: keepalive\n"); status = smb2_keepalive(transport1); torture_assert_ntstatus_ok(tctx, status, "transport1: keepalive"); torture_comment(tctx, "transport1: disconnect\n"); TALLOC_FREE(tree1); return ret; } static bool test_session_sign_enc(struct torture_context *tctx, const char *testname, struct cli_credentials *credentials1, const struct smbcli_options *options1) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); NTSTATUS status; bool ret = false; struct smb2_tree *tree1 = NULL; char fname[256]; struct smb2_handle rh = {{0}}; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; union smb_fileinfo qfinfo1; union smb_notify notify; struct smb2_request *req = NULL; status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials1, &tree1, tctx->ev, options1, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect options1 failed"); status = smb2_util_roothandle(tree1, &rh); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_roothandle failed"); /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "%s_%s.dat", testname, generate_random_str(tctx, 8)); smb2_util_unlink(tree1, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; status = smb2_create(tree1, tctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* Check the initial session is still alive */ ZERO_STRUCT(qfinfo1); qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo1.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree1, tctx, &qfinfo1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); /* ask for a change notify, on file or directory name changes */ ZERO_STRUCT(notify); notify.smb2.level = RAW_NOTIFY_SMB2; notify.smb2.in.buffer_size = 1000; notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME; notify.smb2.in.file.handle = rh; notify.smb2.in.recursive = true; req = smb2_notify_send(tree1, &(notify.smb2)); WAIT_FOR_ASYNC_RESPONSE(req); status = smb2_cancel(req); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_cancel failed"); status = smb2_notify_recv(req, tctx, &(notify.smb2)); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_CANCELLED, ret, done, "smb2_notify_recv failed"); /* Check the initial session is still alive */ ZERO_STRUCT(qfinfo1); qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo1.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree1, tctx, &qfinfo1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); ret = true; done: if (h1 != NULL) { smb2_util_close(tree1, *h1); } TALLOC_FREE(tree1); return ret; } static bool test_session_signing_hmac_sha_256(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test signing only if encryption is required"); } if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_HMAC_SHA256, }, }; ret = test_session_sign_enc(tctx, __func__, credentials, &options1); TALLOC_FREE(tree0); return ret; } static bool test_session_signing_aes_128_cmac(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test signing only if encryption is required"); } if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_CMAC, }, }; ret = test_session_sign_enc(tctx, __func__, credentials, &options1); TALLOC_FREE(tree0); return ret; } static bool test_session_signing_aes_128_gmac(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials = samba_cmdline_get_creds(); bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; bool encrypted; encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli); if (encrypted) { torture_skip(tctx, "Can't test signing only if encryption is required"); } if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) { .num_algos = 1, .algos = { SMB2_SIGNING_AES128_GMAC, }, }; ret = test_session_sign_enc(tctx, __func__, credentials, &options1); TALLOC_FREE(tree0); return ret; } static bool test_session_encryption_aes_128_ccm(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_CCM, }, }; ret = test_session_sign_enc(tctx, __func__, credentials, &options1); TALLOC_FREE(tree0); return ret; } static bool test_session_encryption_aes_128_gcm(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES128_GCM, }, }; ret = test_session_sign_enc(tctx, __func__, credentials, &options1); TALLOC_FREE(tree0); return ret; } static bool test_session_encryption_aes_256_ccm(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES256_CCM, }, }; ret = test_session_sign_enc(tctx, __func__, credentials, &options1); TALLOC_FREE(tree0); return ret; } static bool test_session_encryption_aes_256_gcm(struct torture_context *tctx, struct smb2_tree *tree0) { struct cli_credentials *credentials0 = samba_cmdline_get_creds(); struct cli_credentials *credentials = NULL; bool ret = false; struct smb2_transport *transport0 = tree0->session->transport; struct smbcli_options options1; bool ok; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) { torture_skip(tctx, "Can't test without SMB 3.1.1 support"); } if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) { torture_skip(tctx, "Can't test without SMB 3.1.1 signing negotiation support"); } credentials = cli_credentials_shallow_copy(tctx, credentials0); torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(credentials, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options1 = transport0->options; options1.client_guid = GUID_random(); options1.min_protocol = PROTOCOL_SMB3_11; options1.max_protocol = PROTOCOL_SMB3_11; options1.signing = SMB_SIGNING_REQUIRED; options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) { .num_algos = 1, .algos = { SMB2_ENCRYPTION_AES256_GCM, }, }; ret = test_session_sign_enc(tctx, __func__, credentials, &options1); TALLOC_FREE(tree0); return ret; } static bool test_session_ntlmssp_bug14932(struct torture_context *tctx, struct smb2_tree *tree) { struct cli_credentials *ntlm_creds = cli_credentials_shallow_copy(tctx, samba_cmdline_get_creds()); NTSTATUS status; bool ret = true; /* * This is a NTLMv2_RESPONSE with the strange * NTLMv2_CLIENT_CHALLENGE used by the net diag * tool. * * As we expect an error anyway we fill the * Response part with 0xab... */ static const char *netapp_magic = "\xab\xab\xab\xab\xab\xab\xab\xab" "\xab\xab\xab\xab\xab\xab\xab\xab" "\x01\x01\x00\x00\x00\x00\x00\x00" "\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f" "\xb8\x82\x3a\xf1\xb3\xdd\x08\x15" "\x00\x00\x00\x00\x11\xa2\x08\x81" "\x50\x38\x22\x78\x2b\x94\x47\xfe" "\x54\x94\x7b\xff\x17\x27\x5a\xb4" "\xf4\x18\xba\xdc\x2c\x38\xfd\x5b" "\xfb\x0e\xc1\x85\x1e\xcc\x92\xbb" "\x9b\xb1\xc4\xd5\x53\x14\xff\x8c" "\x76\x49\xf5\x45\x90\x19\xa2"; DATA_BLOB lm_response = data_blob_talloc_zero(tctx, 24); DATA_BLOB lm_session_key = data_blob_talloc_zero(tctx, 16); DATA_BLOB nt_response = data_blob_const(netapp_magic, 95); DATA_BLOB nt_session_key = data_blob_talloc_zero(tctx, 16); cli_credentials_set_kerberos_state(ntlm_creds, CRED_USE_KERBEROS_DISABLED, CRED_SPECIFIED); cli_credentials_set_ntlm_response(ntlm_creds, &lm_response, &lm_session_key, &nt_response, &nt_session_key, CRED_SPECIFIED); status = smb2_session_setup_spnego(tree->session, ntlm_creds, 0 /* previous_session_id */); torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_PARAMETER, "smb2_session_setup_spnego failed"); return ret; } static bool test_session_anon_encryption1(struct torture_context *tctx, struct smb2_tree *tree0) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = "IPC$"; char *unc = NULL; struct smb2_transport *transport0 = tree0->session->transport; struct cli_credentials *anon_creds = NULL; struct smbcli_options options; struct smb2_transport *transport = NULL; struct smb2_session *anon_session = NULL; struct smb2_tree *anon_tree = NULL; NTSTATUS status; bool ok = true; struct tevent_req *subreq = NULL; uint32_t timeout_msec; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "Can't test without SMB3 support"); } unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share); torture_assert(tctx, unc != NULL, "talloc_asprintf"); anon_creds = cli_credentials_init_anon(tctx); torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon"); ok = cli_credentials_set_smb_encryption(anon_creds, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options = transport0->options; options.client_guid = GUID_random(); options.only_negprot = true; status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), anon_creds, &anon_tree, tctx->ev, &options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx)); torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed"); anon_session = anon_tree->session; transport = anon_session->transport; anon_session->anonymous_session_key = true; smb2cli_session_torture_anonymous_encryption(anon_session->smbXcli, true); status = smb2_session_setup_spnego(anon_session, anon_creds, 0 /* previous_session_id */); torture_assert_ntstatus_ok(tctx, status, "smb2_session_setup_spnego failed"); ok = smbXcli_session_is_authenticated(anon_session->smbXcli); torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong"); /* * The connection is still in ConstrainedConnection state... * * This will use encryption and causes a connection reset */ timeout_msec = transport->options.request_timeout * 1000; subreq = smb2cli_tcon_send(tctx, tctx->ev, transport->conn, timeout_msec, anon_session->smbXcli, anon_tree->smbXcli, 0, /* flags */ unc); torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send"); torture_assert(tctx, tevent_req_poll_ntstatus(subreq, tctx->ev, &status), "tevent_req_poll_ntstatus"); status = smb2cli_tcon_recv(subreq); TALLOC_FREE(subreq); if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) { status = NT_STATUS_CONNECTION_RESET; } torture_assert_ntstatus_equal(tctx, status, NT_STATUS_CONNECTION_RESET, "smb2cli_tcon_recv"); ok = smbXcli_conn_is_connected(transport->conn); torture_assert(tctx, !ok, "smbXcli_conn_is_connected still connected"); return true; } static bool test_session_anon_encryption2(struct torture_context *tctx, struct smb2_tree *tree0) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = "IPC$"; char *unc = NULL; struct smb2_transport *transport0 = tree0->session->transport; struct cli_credentials *_creds = samba_cmdline_get_creds(); struct cli_credentials *user_creds = NULL; struct cli_credentials *anon_creds = NULL; struct smbcli_options options; struct smb2_transport *transport = NULL; struct smb2_session *user_session = NULL; struct smb2_tree *user_tree = NULL; struct smb2_session *anon_session = NULL; struct smb2_tree *anon_tree = NULL; struct smb2_ioctl ioctl = { .level = RAW_IOCTL_SMB2, .in = { .file = { .handle = { .data = { [0] = UINT64_MAX, [1] = UINT64_MAX, }, }, }, .function = FSCTL_QUERY_NETWORK_INTERFACE_INFO, /* Windows client sets this to 64KiB */ .max_output_response = 0x10000, .flags = SMB2_IOCTL_FLAG_IS_FSCTL, }, }; NTSTATUS status; bool ok = true; struct tevent_req *subreq = NULL; uint32_t timeout_msec; uint32_t caps = smb2cli_conn_server_capabilities(transport0->conn); NTSTATUS expected_mc_status; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "Can't test without SMB3 support"); } if (caps & SMB2_CAP_MULTI_CHANNEL) { expected_mc_status = NT_STATUS_OK; } else { expected_mc_status = NT_STATUS_FS_DRIVER_REQUIRED; } unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share); torture_assert(tctx, unc != NULL, "talloc_asprintf"); user_creds = cli_credentials_shallow_copy(tctx, _creds); torture_assert(tctx, user_creds != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(user_creds, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); anon_creds = cli_credentials_init_anon(tctx); torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon"); ok = cli_credentials_set_smb_encryption(anon_creds, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options = transport0->options; options.client_guid = GUID_random(); status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), user_creds, &user_tree, tctx->ev, &options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx)); torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed"); user_session = user_tree->session; transport = user_session->transport; ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli); torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(user)"); ok = smbXcli_session_is_authenticated(user_session->smbXcli); torture_assert(tctx, ok, "smbXcli_session_is_authenticated(user)"); anon_session = smb2_session_init(transport, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tctx); torture_assert(tctx, anon_session != NULL, "smb2_session_init(anon)"); anon_session->anonymous_session_key = true; smb2cli_session_torture_anonymous_encryption(anon_session->smbXcli, true); status = smb2_session_setup_spnego(anon_session, anon_creds, 0 /* previous_session_id */); torture_assert_ntstatus_ok(tctx, status, "smb2_session_setup_spnego failed"); ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli); torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(anon)"); ok = smbXcli_session_is_authenticated(anon_session->smbXcli); torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong"); anon_tree = smb2_tree_init(anon_session, tctx, false); torture_assert(tctx, anon_tree != NULL, "smb2_tree_init"); timeout_msec = transport->options.request_timeout * 1000; subreq = smb2cli_tcon_send(tctx, tctx->ev, transport->conn, timeout_msec, anon_session->smbXcli, anon_tree->smbXcli, 0, /* flags */ unc); torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send"); torture_assert(tctx, tevent_req_poll_ntstatus(subreq, tctx->ev, &status), "tevent_req_poll_ntstatus"); status = smb2cli_tcon_recv(subreq); TALLOC_FREE(subreq); torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv(anon)"); ok = smbXcli_conn_is_connected(transport->conn); torture_assert(tctx, ok, "smbXcli_conn_is_connected"); ok = smb2cli_tcon_is_encryption_on(anon_tree->smbXcli); torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(anon)"); ok = smbXcli_session_is_authenticated(anon_session->smbXcli); torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong"); status = smb2_ioctl(user_tree, tctx, &ioctl); torture_assert_ntstatus_equal(tctx, status, expected_mc_status, "FSCTL_QUERY_NETWORK_INTERFACE_INFO user"); ok = smbXcli_conn_is_connected(transport->conn); torture_assert(tctx, ok, "smbXcli_conn_is_connected"); status = smb2_ioctl(anon_tree, tctx, &ioctl); torture_assert_ntstatus_equal(tctx, status, expected_mc_status, "FSCTL_QUERY_NETWORK_INTERFACE_INFO anonymous"); ok = smbXcli_conn_is_connected(transport->conn); torture_assert(tctx, ok, "smbXcli_conn_is_connected"); status = smb2_ioctl(user_tree, tctx, &ioctl); torture_assert_ntstatus_equal(tctx, status, expected_mc_status, "FSCTL_QUERY_NETWORK_INTERFACE_INFO user"); ok = smbXcli_conn_is_connected(transport->conn); torture_assert(tctx, ok, "smbXcli_conn_is_connected"); status = smb2_ioctl(anon_tree, tctx, &ioctl); torture_assert_ntstatus_equal(tctx, status, expected_mc_status, "FSCTL_QUERY_NETWORK_INTERFACE_INFO anonymous"); ok = smbXcli_conn_is_connected(transport->conn); torture_assert(tctx, ok, "smbXcli_conn_is_connected"); return true; } static bool test_session_anon_encryption3(struct torture_context *tctx, struct smb2_tree *tree0) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = "IPC$"; char *unc = NULL; struct smb2_transport *transport0 = tree0->session->transport; struct cli_credentials *_creds = samba_cmdline_get_creds(); struct cli_credentials *user_creds = NULL; struct cli_credentials *anon_creds = NULL; struct smbcli_options options; struct smb2_transport *transport = NULL; struct smb2_session *user_session = NULL; struct smb2_tree *user_tree = NULL; struct smb2_session *anon_session = NULL; struct smb2_tree *anon_tree = NULL; NTSTATUS status; bool ok = true; struct tevent_req *subreq = NULL; uint32_t timeout_msec; uint8_t wrong_session_key[16] = { 0x1f, 0x2f, 0x3f, }; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "Can't test without SMB3 support"); } unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share); torture_assert(tctx, unc != NULL, "talloc_asprintf"); user_creds = cli_credentials_shallow_copy(tctx, _creds); torture_assert(tctx, user_creds != NULL, "cli_credentials_shallow_copy"); ok = cli_credentials_set_smb_encryption(user_creds, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); anon_creds = cli_credentials_init_anon(tctx); torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon"); ok = cli_credentials_set_smb_encryption(anon_creds, SMB_ENCRYPTION_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options = transport0->options; options.client_guid = GUID_random(); status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), user_creds, &user_tree, tctx->ev, &options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx)); torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed"); user_session = user_tree->session; transport = user_session->transport; ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli); torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(user)"); ok = smbXcli_session_is_authenticated(user_session->smbXcli); torture_assert(tctx, ok, "smbXcli_session_is_authenticated(user)"); anon_session = smb2_session_init(transport, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tctx); torture_assert(tctx, anon_session != NULL, "smb2_session_init(anon)"); anon_session->anonymous_session_key = true; anon_session->forced_session_key = data_blob_const(wrong_session_key, ARRAY_SIZE(wrong_session_key)); smb2cli_session_torture_anonymous_encryption(anon_session->smbXcli, true); status = smb2_session_setup_spnego(anon_session, anon_creds, 0 /* previous_session_id */); torture_assert_ntstatus_ok(tctx, status, "smb2_session_setup_spnego failed"); ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli); torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(anon)"); ok = smbXcli_session_is_authenticated(anon_session->smbXcli); torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong"); anon_tree = smb2_tree_init(anon_session, tctx, false); torture_assert(tctx, anon_tree != NULL, "smb2_tree_init"); timeout_msec = transport->options.request_timeout * 1000; subreq = smb2cli_tcon_send(tctx, tctx->ev, transport->conn, timeout_msec, anon_session->smbXcli, anon_tree->smbXcli, 0, /* flags */ unc); torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send"); torture_assert(tctx, tevent_req_poll_ntstatus(subreq, tctx->ev, &status), "tevent_req_poll_ntstatus"); status = smb2cli_tcon_recv(subreq); TALLOC_FREE(subreq); if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) { status = NT_STATUS_CONNECTION_RESET; } torture_assert_ntstatus_equal(tctx, status, NT_STATUS_CONNECTION_RESET, "smb2cli_tcon_recv"); ok = smbXcli_conn_is_connected(transport->conn); torture_assert(tctx, !ok, "smbXcli_conn_is_connected still connected"); return true; } static bool test_session_anon_signing1(struct torture_context *tctx, struct smb2_tree *tree0) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = "IPC$"; char *unc = NULL; struct smb2_transport *transport0 = tree0->session->transport; struct cli_credentials *anon_creds = NULL; struct smbcli_options options; struct smb2_transport *transport = NULL; struct smb2_session *anon_session = NULL; struct smb2_tree *anon_tree = NULL; NTSTATUS status; bool ok = true; struct tevent_req *subreq = NULL; uint32_t timeout_msec; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "Can't test without SMB3 support"); } unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share); torture_assert(tctx, unc != NULL, "talloc_asprintf"); anon_creds = cli_credentials_init_anon(tctx); torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon"); ok = cli_credentials_set_smb_signing(anon_creds, SMB_SIGNING_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_signing"); ok = cli_credentials_set_smb_ipc_signing(anon_creds, SMB_SIGNING_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_ipc_signing"); ok = cli_credentials_set_smb_encryption(anon_creds, SMB_ENCRYPTION_OFF, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options = transport0->options; options.client_guid = GUID_random(); options.only_negprot = true; options.signing = SMB_SIGNING_REQUIRED; status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), anon_creds, &anon_tree, tctx->ev, &options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx)); torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed"); anon_session = anon_tree->session; transport = anon_session->transport; anon_session->anonymous_session_key = true; smb2cli_session_torture_anonymous_signing(anon_session->smbXcli, true); status = smb2_session_setup_spnego(anon_session, anon_creds, 0 /* previous_session_id */); torture_assert_ntstatus_ok(tctx, status, "smb2_session_setup_spnego failed"); ok = smbXcli_session_is_authenticated(anon_session->smbXcli); torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong"); timeout_msec = transport->options.request_timeout * 1000; subreq = smb2cli_tcon_send(tctx, tctx->ev, transport->conn, timeout_msec, anon_session->smbXcli, anon_tree->smbXcli, 0, /* flags */ unc); torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send"); torture_assert(tctx, tevent_req_poll_ntstatus(subreq, tctx->ev, &status), "tevent_req_poll_ntstatus"); status = smb2cli_tcon_recv(subreq); TALLOC_FREE(subreq); torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv"); ok = smbXcli_conn_is_connected(transport->conn); torture_assert(tctx, ok, "smbXcli_conn_is_connected"); return true; } static bool test_session_anon_signing2(struct torture_context *tctx, struct smb2_tree *tree0) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = "IPC$"; char *unc = NULL; struct smb2_transport *transport0 = tree0->session->transport; struct cli_credentials *anon_creds = NULL; struct smbcli_options options; struct smb2_transport *transport = NULL; struct smb2_session *anon_session = NULL; struct smb2_session *anon_session_nosign = NULL; struct smb2_tree *anon_tree = NULL; NTSTATUS status; bool ok = true; struct tevent_req *subreq = NULL; uint32_t timeout_msec; uint8_t wrong_session_key[16] = { 0x1f, 0x2f, 0x3f, }; uint64_t session_id; if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) { torture_skip(tctx, "Can't test without SMB3 support"); } unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share); torture_assert(tctx, unc != NULL, "talloc_asprintf"); anon_creds = cli_credentials_init_anon(tctx); torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon"); ok = cli_credentials_set_smb_signing(anon_creds, SMB_SIGNING_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_signing"); ok = cli_credentials_set_smb_ipc_signing(anon_creds, SMB_SIGNING_REQUIRED, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_ipc_signing"); ok = cli_credentials_set_smb_encryption(anon_creds, SMB_ENCRYPTION_OFF, CRED_SPECIFIED); torture_assert(tctx, ok, "cli_credentials_set_smb_encryption"); options = transport0->options; options.client_guid = GUID_random(); options.only_negprot = true; options.signing = SMB_SIGNING_REQUIRED; status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), anon_creds, &anon_tree, tctx->ev, &options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx)); torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed"); anon_session = anon_tree->session; transport = anon_session->transport; anon_session->anonymous_session_key = true; anon_session->forced_session_key = data_blob_const(wrong_session_key, ARRAY_SIZE(wrong_session_key)); smb2cli_session_torture_anonymous_signing(anon_session->smbXcli, true); smb2cli_session_torture_no_signing_disconnect(anon_session->smbXcli); status = smb2_session_setup_spnego(anon_session, anon_creds, 0 /* previous_session_id */); torture_assert_ntstatus_ok(tctx, status, "smb2_session_setup_spnego failed"); ok = smbXcli_session_is_authenticated(anon_session->smbXcli); torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong"); /* * create a new structure for the same session id, * but without smb2.should_sign set. */ session_id = smb2cli_session_current_id(anon_session->smbXcli); anon_session_nosign = smb2_session_init(transport, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tctx); torture_assert(tctx, anon_session_nosign != NULL, "smb2_session_init(anon_nosign)"); smb2cli_session_set_id_and_flags(anon_session_nosign->smbXcli, session_id, 0); smb2cli_session_torture_no_signing_disconnect(anon_session_nosign->smbXcli); timeout_msec = transport->options.request_timeout * 1000; subreq = smb2cli_tcon_send(tctx, tctx->ev, transport->conn, timeout_msec, anon_session->smbXcli, anon_tree->smbXcli, 0, /* flags */ unc); torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send"); torture_assert(tctx, tevent_req_poll_ntstatus(subreq, tctx->ev, &status), "tevent_req_poll_ntstatus"); status = smb2cli_tcon_recv(subreq); TALLOC_FREE(subreq); torture_assert_ntstatus_equal(tctx, status, NT_STATUS_ACCESS_DENIED, "smb2cli_tcon_recv"); ok = smbXcli_conn_is_connected(transport->conn); torture_assert(tctx, ok, "smbXcli_conn_is_connected"); subreq = smb2cli_tcon_send(tctx, tctx->ev, transport->conn, timeout_msec, anon_session_nosign->smbXcli, anon_tree->smbXcli, 0, /* flags */ unc); torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send"); torture_assert(tctx, tevent_req_poll_ntstatus(subreq, tctx->ev, &status), "tevent_req_poll_ntstatus"); status = smb2cli_tcon_recv(subreq); TALLOC_FREE(subreq); torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv"); ok = smbXcli_conn_is_connected(transport->conn); torture_assert(tctx, ok, "smbXcli_conn_is_connected"); return true; } struct torture_suite *torture_smb2_session_init(TALLOC_CTX *ctx) { struct torture_suite *suite = torture_suite_create(ctx, "session"); torture_suite_add_1smb2_test(suite, "reconnect1", test_session_reconnect1); torture_suite_add_1smb2_test(suite, "reconnect2", test_session_reconnect2); torture_suite_add_1smb2_test(suite, "reauth1", test_session_reauth1); torture_suite_add_1smb2_test(suite, "reauth2", test_session_reauth2); torture_suite_add_1smb2_test(suite, "reauth3", test_session_reauth3); torture_suite_add_1smb2_test(suite, "reauth4", test_session_reauth4); torture_suite_add_1smb2_test(suite, "reauth5", test_session_reauth5); torture_suite_add_1smb2_test(suite, "reauth6", test_session_reauth6); torture_suite_add_simple_test(suite, "expire1n", test_session_expire1n); torture_suite_add_simple_test(suite, "expire1s", test_session_expire1s); torture_suite_add_simple_test(suite, "expire1e", test_session_expire1e); torture_suite_add_simple_test(suite, "expire2s", test_session_expire2s); torture_suite_add_simple_test(suite, "expire2e", test_session_expire2e); torture_suite_add_simple_test(suite, "expire_disconnect", test_session_expire_disconnect); torture_suite_add_1smb2_test(suite, "bind1", test_session_bind1); torture_suite_add_1smb2_test(suite, "bind2", test_session_bind2); torture_suite_add_1smb2_test(suite, "bind_invalid_auth", test_session_bind_invalid_auth); torture_suite_add_1smb2_test(suite, "bind_different_user", test_session_bind_different_user); torture_suite_add_1smb2_test(suite, "bind_negative_smb202", test_session_bind_negative_smb202); torture_suite_add_1smb2_test(suite, "bind_negative_smb210s", test_session_bind_negative_smb210s); torture_suite_add_1smb2_test(suite, "bind_negative_smb210d", test_session_bind_negative_smb210d); torture_suite_add_1smb2_test(suite, "bind_negative_smb2to3s", test_session_bind_negative_smb2to3s); torture_suite_add_1smb2_test(suite, "bind_negative_smb2to3d", test_session_bind_negative_smb2to3d); torture_suite_add_1smb2_test(suite, "bind_negative_smb3to2s", test_session_bind_negative_smb3to2s); torture_suite_add_1smb2_test(suite, "bind_negative_smb3to2d", test_session_bind_negative_smb3to2d); torture_suite_add_1smb2_test(suite, "bind_negative_smb3to3s", test_session_bind_negative_smb3to3s); torture_suite_add_1smb2_test(suite, "bind_negative_smb3to3d", test_session_bind_negative_smb3to3d); torture_suite_add_1smb2_test(suite, "bind_negative_smb3encGtoCs", test_session_bind_negative_smb3encGtoCs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3encGtoCd", test_session_bind_negative_smb3encGtoCd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signCtoHs", test_session_bind_negative_smb3signCtoHs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signCtoHd", test_session_bind_negative_smb3signCtoHd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signCtoGs", test_session_bind_negative_smb3signCtoGs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signCtoGd", test_session_bind_negative_smb3signCtoGd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signHtoCs", test_session_bind_negative_smb3signHtoCs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signHtoCd", test_session_bind_negative_smb3signHtoCd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signHtoGs", test_session_bind_negative_smb3signHtoGs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signHtoGd", test_session_bind_negative_smb3signHtoGd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoCs", test_session_bind_negative_smb3signGtoCs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoCd", test_session_bind_negative_smb3signGtoCd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoHs", test_session_bind_negative_smb3signGtoHs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoHd", test_session_bind_negative_smb3signGtoHd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneGtoCs", test_session_bind_negative_smb3sneGtoCs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneGtoCd", test_session_bind_negative_smb3sneGtoCd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneGtoHs", test_session_bind_negative_smb3sneGtoHs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneGtoHd", test_session_bind_negative_smb3sneGtoHd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneCtoGs", test_session_bind_negative_smb3sneCtoGs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneCtoGd", test_session_bind_negative_smb3sneCtoGd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneHtoGs", test_session_bind_negative_smb3sneHtoGs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneHtoGd", test_session_bind_negative_smb3sneHtoGd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signC30toGs", test_session_bind_negative_smb3signC30toGs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signC30toGd", test_session_bind_negative_smb3signC30toGd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signH2XtoGs", test_session_bind_negative_smb3signH2XtoGs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signH2XtoGd", test_session_bind_negative_smb3signH2XtoGd); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoC30s", test_session_bind_negative_smb3signGtoC30s); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoC30d", test_session_bind_negative_smb3signGtoC30d); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoH2Xs", test_session_bind_negative_smb3signGtoH2Xs); torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoH2Xd", test_session_bind_negative_smb3signGtoH2Xd); torture_suite_add_1smb2_test(suite, "two_logoff", test_session_two_logoff); torture_suite_add_1smb2_test(suite, "signing-hmac-sha-256", test_session_signing_hmac_sha_256); torture_suite_add_1smb2_test(suite, "signing-aes-128-cmac", test_session_signing_aes_128_cmac); torture_suite_add_1smb2_test(suite, "signing-aes-128-gmac", test_session_signing_aes_128_gmac); torture_suite_add_1smb2_test(suite, "encryption-aes-128-ccm", test_session_encryption_aes_128_ccm); torture_suite_add_1smb2_test(suite, "encryption-aes-128-gcm", test_session_encryption_aes_128_gcm); torture_suite_add_1smb2_test(suite, "encryption-aes-256-ccm", test_session_encryption_aes_256_ccm); torture_suite_add_1smb2_test(suite, "encryption-aes-256-gcm", test_session_encryption_aes_256_gcm); torture_suite_add_1smb2_test(suite, "ntlmssp_bug14932", test_session_ntlmssp_bug14932); torture_suite_add_1smb2_test(suite, "anon-encryption1", test_session_anon_encryption1); torture_suite_add_1smb2_test(suite, "anon-encryption2", test_session_anon_encryption2); torture_suite_add_1smb2_test(suite, "anon-encryption3", test_session_anon_encryption3); torture_suite_add_1smb2_test(suite, "anon-signing1", test_session_anon_signing1); torture_suite_add_1smb2_test(suite, "anon-signing2", test_session_anon_signing2); suite->description = talloc_strdup(suite, "SMB2-SESSION tests"); return suite; } static bool test_session_require_sign_bug15397(struct torture_context *tctx, struct smb2_tree *_tree) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); struct cli_credentials *_creds = samba_cmdline_get_creds(); struct cli_credentials *creds = NULL; struct smbcli_options options; struct smb2_tree *tree = NULL; uint8_t security_mode; NTSTATUS status; bool ok = true; /* * Setup our own connection so we can control the signing flags */ creds = cli_credentials_shallow_copy(tctx, _creds); torture_assert(tctx, creds != NULL, "cli_credentials_shallow_copy"); options = _tree->session->transport->options; options.client_guid = GUID_random(); options.signing = SMB_SIGNING_IF_REQUIRED; status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), creds, &tree, tctx->ev, &options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx)); torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "smb2_connect failed"); security_mode = smb2cli_session_security_mode(tree->session->smbXcli); torture_assert_int_equal_goto( tctx, security_mode, SMB2_NEGOTIATE_SIGNING_REQUIRED | SMB2_NEGOTIATE_SIGNING_ENABLED, ok, done, "Signing not required"); done: return ok; } struct torture_suite *torture_smb2_session_req_sign_init(TALLOC_CTX *ctx) { struct torture_suite *suite = torture_suite_create(ctx, "session-require-signing"); torture_suite_add_1smb2_test(suite, "bug15397", test_session_require_sign_bug15397); suite->description = talloc_strdup(suite, "SMB2-SESSION require signing tests"); return suite; }