s3:smbd: fallback to smb2srv_session_lookup_global() for session setups with failed...
authorStefan Metzmacher <metze@samba.org>
Fri, 9 Jul 2021 13:36:12 +0000 (15:36 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 15 Jul 2021 00:06:31 +0000 (00:06 +0000)
The motivation is to get the same error responses as a windows server.

We already fallback to smb2srv_session_lookup_global() in other places
where we don't have a valid session in the current smbd process.

If signing is failing while verifying a session setup request,
we should do the same if we don't have a valid channel binding
for the connection yet.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
selftest/knownfail.d/smb2.session [deleted file]
source3/smbd/smb2_server.c

diff --git a/selftest/knownfail.d/smb2.session b/selftest/knownfail.d/smb2.session
deleted file mode 100644 (file)
index 4521b67..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-^samba3.smb2.session.*bind_negative_smb3encGtoCs
-^samba3.smb2.session.ntlm.bind_negative_smb210s.ad_dc
-^samba3.smb2.session.ntlm.bind_negative_smb2to3s.ad_dc
-^samba3.smb2.session.ntlm.bind_negative_smb3to2s.ad_dc
-^samba3.smb2.session.ntlm.bind_negative_smb3to3s.ad_dc
-^samba3.smb2.session.krb5.bind_negative_smb210s.ad_dc
-^samba3.smb2.session.krb5.bind_negative_smb2to3s.ad_dc
-^samba3.smb2.session.krb5.bind_negative_smb3to2s.ad_dc
-^samba3.smb2.session.krb5.bind_negative_smb3to3s.ad_dc
index a2f2447595df434daf47fe497856fd1651b40c7b..2d9f0d2cc74a1972abbb13aa423dd5cf41bc62a3 100644 (file)
@@ -2119,19 +2119,27 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
 
 static
 struct smb2_signing_key *smbd_smb2_signing_key(struct smbXsrv_session *session,
-                                              struct smbXsrv_connection *xconn)
+                                              struct smbXsrv_connection *xconn,
+                                              bool *_has_channel)
 {
        struct smbXsrv_channel_global0 *c = NULL;
        NTSTATUS status;
        struct smb2_signing_key *key = NULL;
+       bool has_channel = false;
 
        status = smbXsrv_session_find_channel(session, xconn, &c);
        if (NT_STATUS_IS_OK(status)) {
                key = c->signing_key;
+               has_channel = true;
        }
 
        if (!smb2_signing_key_valid(key)) {
                key = session->global->signing_key;
+               has_channel = false;
+       }
+
+       if (_has_channel != NULL) {
+               *_has_channel = has_channel;
        }
 
        return key;
@@ -2338,7 +2346,7 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
        } else if (req->do_signing) {
                struct smbXsrv_session *x = req->session;
                struct smb2_signing_key *signing_key =
-                       smbd_smb2_signing_key(x, xconn);
+                       smbd_smb2_signing_key(x, xconn, NULL);
 
                status = smb2_signing_sign_pdu(signing_key,
                                        &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
@@ -3080,6 +3088,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                signing_required = false;
        } else if (signing_required || (flags & SMB2_HDR_FLAG_SIGNED)) {
                struct smb2_signing_key *signing_key = NULL;
+               bool has_channel = false;
 
                if (x == NULL) {
                        /*
@@ -3101,7 +3110,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return smbd_smb2_request_error(req, status);
                }
 
-               signing_key = smbd_smb2_signing_key(x, xconn);
+               signing_key = smbd_smb2_signing_key(x, xconn, &has_channel);
 
                /*
                 * If we have a signing key, we should
@@ -3114,6 +3123,33 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                status = smb2_signing_check_pdu(signing_key,
                                                SMBD_SMB2_IN_HDR_IOV(req),
                                                SMBD_SMB2_NUM_IOV_PER_REQ - 1);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+                   opcode == SMB2_OP_SESSSETUP && !has_channel &&
+                   NT_STATUS_IS_OK(session_status))
+               {
+                       if (!NT_STATUS_EQUAL(x->status, NT_STATUS_BAD_LOGON_SESSION_STATE)) {
+                               struct smbXsrv_session *session = NULL;
+                               NTSTATUS error;
+
+                               error = smb2srv_session_lookup_global(req->xconn->client,
+                                                                     x->global->session_wire_id,
+                                                                     req,
+                                                                     &session);
+                               if (!NT_STATUS_IS_OK(error)) {
+                                       return smbd_smb2_request_error(req, error);
+                               }
+
+                               /*
+                                * We fallback to a session of
+                                * another process in order to
+                                * get the signing correct.
+                                *
+                                * We don't set req->last_session_id here.
+                                */
+                               req->session = x = session;
+                       }
+                       goto skipped_signing;
+               }
                if (!NT_STATUS_IS_OK(status)) {
                        return smbd_smb2_request_error(req, status);
                }
@@ -3165,6 +3201,8 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                }
        }
 
+skipped_signing:
+
        if (flags & SMB2_HDR_FLAG_CHAINED) {
                req->compound_related = true;
        }
@@ -3594,7 +3632,7 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
                if (req->do_signing && firsttf->iov_len == 0) {
                        struct smbXsrv_session *x = req->session;
                        struct smb2_signing_key *signing_key =
-                               smbd_smb2_signing_key(x, xconn);
+                               smbd_smb2_signing_key(x, xconn, NULL);
 
                        /*
                         * we need to remember the signing key
@@ -3648,7 +3686,7 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
        } else if (req->do_signing) {
                struct smbXsrv_session *x = req->session;
                struct smb2_signing_key *signing_key =
-                       smbd_smb2_signing_key(x, xconn);
+                       smbd_smb2_signing_key(x, xconn, NULL);
 
                status = smb2_signing_sign_pdu(signing_key,
                                               outhdr,