libcli/smb: don't overwrite status code
[vlendec/samba-autobuild/.git] / libcli / smb / smbXcli_base.c
index 6335ce0c121877c92410bfde427c1805bc72ea3f..40480c83aa05b62949b93bae543342f5716880d5 100644 (file)
@@ -138,6 +138,8 @@ struct smbXcli_conn {
 
                uint8_t io_priority;
 
+               bool force_channel_sequence;
+
                uint8_t preauth_sha512[64];
        } smb2;
 
@@ -159,6 +161,7 @@ struct smb2cli_session {
        uint64_t nonce_low;
        uint16_t channel_sequence;
        bool replay_active;
+       bool require_signed_response;
 };
 
 struct smbXcli_session {
@@ -225,6 +228,8 @@ struct smbXcli_req_state {
 
        struct tevent_req *write_req;
 
+       struct timeval endtime;
+
        struct {
                /* Space for the header including the wct */
                uint8_t hdr[HDR_VWV];
@@ -285,6 +290,7 @@ struct smbXcli_req_state {
                uint64_t encryption_session_id;
 
                bool signing_skipped;
+               bool require_signed_response;
                bool notify_async;
                bool got_async;
                uint16_t cancel_flags;
@@ -549,6 +555,17 @@ const struct GUID *smbXcli_conn_server_guid(struct smbXcli_conn *conn)
        return &conn->smb1.server.guid;
 }
 
+bool smbXcli_conn_get_force_channel_sequence(struct smbXcli_conn *conn)
+{
+       return conn->smb2.force_channel_sequence;
+}
+
+void smbXcli_conn_set_force_channel_sequence(struct smbXcli_conn *conn,
+                                            bool v)
+{
+       conn->smb2.force_channel_sequence = v;
+}
+
 struct smbXcli_conn_samba_suicide_state {
        struct smbXcli_conn *conn;
        struct iovec iov;
@@ -1570,10 +1587,8 @@ struct tevent_req *smb1cli_req_create(TALLOC_CTX *mem_ctx,
        state->smb1.iov_count = iov_count + 4;
 
        if (timeout_msec > 0) {
-               struct timeval endtime;
-
-               endtime = timeval_current_ofs_msec(timeout_msec);
-               if (!tevent_req_set_endtime(req, ev, endtime)) {
+               state->endtime = timeval_current_ofs_msec(timeout_msec);
+               if (!tevent_req_set_endtime(req, ev, state->endtime)) {
                        return req;
                }
        }
@@ -1901,7 +1916,7 @@ static NTSTATUS smb1cli_inbuf_parse_chain(uint8_t *buf, TALLOC_CTX *mem_ctx,
                                          struct iovec **piov, int *pnum_iov)
 {
        struct iovec *iov;
-       int num_iov;
+       size_t num_iov;
        size_t buflen;
        size_t taken;
        size_t remaining;
@@ -2092,10 +2107,10 @@ static NTSTATUS smb1cli_inbuf_parse_chain(uint8_t *buf, TALLOC_CTX *mem_ctx,
                wct_ofs = SVAL(cur[0].iov_base, 2);
 
                if (wct_ofs < taken) {
-                       return NT_STATUS_INVALID_NETWORK_RESPONSE;
+                       goto inval;
                }
                if (wct_ofs > buflen) {
-                       return NT_STATUS_INVALID_NETWORK_RESPONSE;
+                       goto inval;
                }
 
                /*
@@ -2879,6 +2894,14 @@ static void smb2cli_req_cancel_done(struct tevent_req *subreq)
        TALLOC_FREE(subreq);
 }
 
+struct timeval smbXcli_req_endtime(struct tevent_req *req)
+{
+       struct smbXcli_req_state *state = tevent_req_data(
+               req, struct smbXcli_req_state);
+
+       return state->endtime;
+}
+
 struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
                                      struct tevent_context *ev,
                                      struct smbXcli_conn *conn,
@@ -2899,7 +2922,7 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
        uint32_t flags = 0;
        uint32_t tid = 0;
        uint64_t uid = 0;
-       bool use_channel_sequence = false;
+       bool use_channel_sequence = conn->smb2.force_channel_sequence;
        uint16_t channel_sequence = 0;
        bool use_replay_flag = false;
 
@@ -2941,6 +2964,8 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
 
                state->smb2.should_sign = session->smb2->should_sign;
                state->smb2.should_encrypt = session->smb2->should_encrypt;
+               state->smb2.require_signed_response =
+                       session->smb2->require_signed_response;
 
                if (cmd == SMB2_OP_SESSSETUP &&
                    session->smb2_channel.signing_key.length == 0 &&
@@ -3028,10 +3053,8 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
        }
 
        if (timeout_msec > 0) {
-               struct timeval endtime;
-
-               endtime = timeval_current_ofs_msec(timeout_msec);
-               if (!tevent_req_set_endtime(req, ev, endtime)) {
+               state->endtime = timeval_current_ofs_msec(timeout_msec);
+               if (!tevent_req_set_endtime(req, ev, state->endtime)) {
                        return req;
                }
        }
@@ -3457,7 +3480,8 @@ static NTSTATUS smb2cli_inbuf_parse_compound(struct smbXcli_conn *conn,
                                             uint8_t *buf,
                                             size_t buflen,
                                             TALLOC_CTX *mem_ctx,
-                                            struct iovec **piov, int *pnum_iov)
+                                            struct iovec **piov,
+                                            size_t *pnum_iov)
 {
        struct iovec *iov;
        int num_iov = 0;
@@ -3643,7 +3667,7 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
        struct tevent_req *req;
        struct smbXcli_req_state *state = NULL;
        struct iovec *iov = NULL;
-       int i, num_iov = 0;
+       size_t i, num_iov = 0;
        NTSTATUS status;
        bool defer = true;
        struct smbXcli_session *last_session = NULL;
@@ -3729,12 +3753,6 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
                }
                last_session = session;
 
-               if (state->smb2.should_sign) {
-                       if (!(flags & SMB2_HDR_FLAG_SIGNED)) {
-                               return NT_STATUS_ACCESS_DENIED;
-                       }
-               }
-
                if (flags & SMB2_HDR_FLAG_SIGNED) {
                        uint64_t uid = BVAL(inhdr, SMB2_HDR_SESSION_ID);
 
@@ -3781,6 +3799,27 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
                                 */
                                signing_key = NULL;
                        }
+
+                       if (!NT_STATUS_IS_OK(status)) {
+                               /*
+                                * Only check the signature of the last response
+                                * of a successfull session auth. This matches
+                                * Windows behaviour for NTLM auth and reauth.
+                                */
+                               state->smb2.require_signed_response = false;
+                       }
+               }
+
+               if (state->smb2.should_sign ||
+                   state->smb2.require_signed_response)
+               {
+                       if (!(flags & SMB2_HDR_FLAG_SIGNED)) {
+                               return NT_STATUS_ACCESS_DENIED;
+                       }
+               }
+
+               if (signing_key == NULL && state->smb2.require_signed_response) {
+                       signing_key = &session->smb2_channel.signing_key;
                }
 
                if (cur[0].iov_len == SMB2_TF_HDR_SIZE) {
@@ -3869,15 +3908,17 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
                }
 
                if (signing_key) {
-                       status = smb2_signing_check_pdu(*signing_key,
-                                                       state->conn->protocol,
-                                                       &cur[1], 3);
-                       if (!NT_STATUS_IS_OK(status)) {
+                       NTSTATUS signing_status;
+
+                       signing_status = smb2_signing_check_pdu(*signing_key,
+                                                               state->conn->protocol,
+                                                               &cur[1], 3);
+                       if (!NT_STATUS_IS_OK(signing_status)) {
                                /*
                                 * If the signing check fails, we disconnect
                                 * the connection.
                                 */
-                               return status;
+                               return signing_status;
                        }
                }
 
@@ -4355,6 +4396,7 @@ static void smbXcli_negprot_smb1_done(struct tevent_req *subreq)
        }
 
        if (conn->protocol == PROTOCOL_NONE) {
+               DBG_ERR("No compatible protocol selected by server.\n");
                tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
                return;
        }
@@ -5698,6 +5740,12 @@ void smb2cli_session_stop_replay(struct smbXcli_session *session)
        session->smb2->replay_active = false;
 }
 
+void smb2cli_session_require_signed_response(struct smbXcli_session *session,
+                                            bool require_signed_response)
+{
+       session->smb2->require_signed_response = require_signed_response;
+}
+
 NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session,
                                        const struct iovec *iov)
 {