1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

s4:torture/smb2: add smb2.session.bind_negative_{smb202,smb210,smb2to3,smb3to2,smb3to3}

'smb2.session.bind_negative_smb202' 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.

In order to work out the details I've added more similar tests.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14512

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Stefan Metzmacher 2021-02-24 17:43:40 +01:00 committed by Jeremy Allison
parent 30fa5a45c2
commit 457b989881
2 changed files with 403 additions and 0 deletions

View File

@ -0,0 +1,6 @@
^samba3.smb2.session.*.bind_negative_smb202
^samba3.smb2.session.*.bind_negative_smb210
^samba3.smb2.session.*.bind_negative_smb2to3
^samba3.smb2.session.*.bind_negative_smb3to2
^samba3.smb2.session.*.bind_negative_smb3to3
^samba3.smb2.session.*.bind_negative_smb3encGtoC

View File

@ -1850,6 +1850,397 @@ done:
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;
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;
/* 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");
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");
/*
* 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, NT_STATUS_USER_SESSION_DELETED, 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 = popt_get_cmdline_credentials();
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 is encrytion 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_smb210(struct torture_context *tctx, struct smb2_tree *tree0)
{
struct cli_credentials *credentials = popt_get_cmdline_credentials();
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 is encrytion is required");
}
options1 = transport0->options;
options1.client_guid = GUID_random();
options1.max_protocol = PROTOCOL_SMB2_10;
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_smb2to3(struct torture_context *tctx, struct smb2_tree *tree0)
{
struct cli_credentials *credentials = popt_get_cmdline_credentials();
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 is encrytion 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;
options2 = options1;
options2.only_negprot = true;
options2.min_protocol = PROTOCOL_SMB3_00;
options2.max_protocol = PROTOCOL_SMB3_11;
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_smb3to2(struct torture_context *tctx, struct smb2_tree *tree0)
{
struct cli_credentials *credentials = popt_get_cmdline_credentials();
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 is encrytion 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;
options2 = options1;
options2.only_negprot = true;
options2.min_protocol = PROTOCOL_SMB2_02;
options2.max_protocol = PROTOCOL_SMB2_10;
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_smb3to3(struct torture_context *tctx, struct smb2_tree *tree0)
{
struct cli_credentials *credentials = popt_get_cmdline_credentials();
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;
options2 = options1;
options2.only_negprot = true;
options2.min_protocol = PROTOCOL_SMB3_11;
options2.max_protocol = PROTOCOL_SMB3_11;
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_smb3encGtoC(struct torture_context *tctx, struct smb2_tree *tree0)
{
struct cli_credentials *credentials0 = popt_get_cmdline_credentials();
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,
},
};
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_two_logoff(struct torture_context *tctx,
struct smb2_tree *tree1)
{
@ -1913,6 +2304,12 @@ struct torture_suite *torture_smb2_session_init(TALLOC_CTX *ctx)
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, "bind_negative_smb202", test_session_bind_negative_smb202);
torture_suite_add_1smb2_test(suite, "bind_negative_smb210", test_session_bind_negative_smb210);
torture_suite_add_1smb2_test(suite, "bind_negative_smb2to3", test_session_bind_negative_smb2to3);
torture_suite_add_1smb2_test(suite, "bind_negative_smb3to2", test_session_bind_negative_smb3to2);
torture_suite_add_1smb2_test(suite, "bind_negative_smb3to3", test_session_bind_negative_smb3to3);
torture_suite_add_1smb2_test(suite, "bind_negative_smb3encGtoC", test_session_bind_negative_smb3encGtoC);
torture_suite_add_1smb2_test(suite, "two_logoff", test_session_two_logoff);
suite->description = talloc_strdup(suite, "SMB2-SESSION tests");