]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4:torture/smb2: add smb2.session.bind_negative_{smb202,smb210,smb2to3,smb3to2,smb3to3}
authorStefan Metzmacher <metze@samba.org>
Wed, 24 Feb 2021 16:43:40 +0000 (17:43 +0100)
committerJeremy Allison <jra@samba.org>
Wed, 17 Mar 2021 00:49:32 +0000 (00:49 +0000)
'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>
selftest/knownfail.d/smb2.session [new file with mode: 0644]
source4/torture/smb2/session.c

diff --git a/selftest/knownfail.d/smb2.session b/selftest/knownfail.d/smb2.session
new file mode 100644 (file)
index 0000000..c35d07f
--- /dev/null
@@ -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
index 5478e982d0eab4d3d86eb6fc62e67a611d8d90cf..19455ec8200278c65fa710e2cec91485ff17dae4 100644 (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");