libcli:smb: Use C99 initializer for derivation in smbXcli_base
[metze/samba/wip.git] / libcli / smb / smbXcli_base.c
index e9fdc1dc32a83e2efae12b3df393b28a8079817d..3118365871aaf7ab1179828dc34f0664692035dc 100644 (file)
@@ -161,6 +161,7 @@ struct smb2cli_session {
        uint64_t nonce_low;
        uint16_t channel_sequence;
        bool replay_active;
+       bool require_signed_response;
 };
 
 struct smbXcli_session {
@@ -227,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];
@@ -287,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;
@@ -1583,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;
                }
        }
@@ -1914,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;
@@ -2105,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;
                }
 
                /*
@@ -2892,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,
@@ -2954,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 &&
@@ -3041,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;
                }
        }
@@ -3221,6 +3231,9 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
 
                avail = MIN(avail, state->conn->smb2.cur_credits);
                if (avail < charge) {
+                       DBG_ERR("Insufficient credits. "
+                               "%"PRIu64" available, %"PRIu16" needed\n",
+                               avail, charge);
                        return NT_STATUS_INTERNAL_ERROR;
                }
 
@@ -3470,7 +3483,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;
@@ -3656,7 +3670,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;
@@ -3742,12 +3756,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);
 
@@ -3794,6 +3802,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) {
@@ -3882,15 +3911,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;
                        }
                }
 
@@ -4368,6 +4399,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;
        }
@@ -5711,6 +5743,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)
 {
@@ -5759,7 +5797,9 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
                struct _derivation encryption;
                struct _derivation decryption;
                struct _derivation application;
-       } derivation = { };
+       } derivation = {
+               .signing.label.length = 0,
+       };
        size_t nonce_size = 0;
 
        if (conn == NULL) {
@@ -6043,7 +6083,9 @@ NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session,
        };
        struct {
                struct _derivation signing;
-       } derivation = { };
+       } derivation = {
+               .signing.label.length = 0,
+       };
 
        if (conn == NULL) {
                return NT_STATUS_INVALID_PARAMETER_MIX;