CVE-2015-5296: libcli/smb: make sure we require signing when we demand encryption...
[samba.git] / libcli / smb / smbXcli_base.c
index 04f8c96656d34bbef2d2cf98a9afb54fd6a8aca8..505d40dd4f585185f9f6316050f3c7254dc0f71a 100644 (file)
@@ -222,6 +222,8 @@ struct smbXcli_req_state {
 
        uint8_t *inbuf;
 
+       struct tevent_req *write_req;
+
        struct {
                /* Space for the header including the wct */
                uint8_t hdr[HDR_VWV];
@@ -374,6 +376,12 @@ struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx,
                conn->desire_signing = false;
                conn->mandatory_signing = false;
                break;
+       case SMB_SIGNING_DESIRED:
+               /* if the server desires it */
+               conn->allow_signing = true;
+               conn->desire_signing = true;
+               conn->mandatory_signing = false;
+               break;
        case SMB_SIGNING_REQUIRED:
                /* always */
                conn->allow_signing = true;
@@ -838,6 +846,8 @@ void smbXcli_req_unset_pending(struct tevent_req *req)
        size_t num_pending = talloc_array_length(conn->pending);
        size_t i;
 
+       TALLOC_FREE(state->write_req);
+
        if (state->smb1.mid != 0) {
                /*
                 * This is a [nt]trans[2] request which waits
@@ -896,6 +906,8 @@ static void smbXcli_req_cleanup(struct tevent_req *req,
                tevent_req_data(req,
                struct smbXcli_req_state);
 
+       TALLOC_FREE(state->write_req);
+
        switch (req_state) {
        case TEVENT_REQ_RECEIVED:
                /*
@@ -1614,6 +1626,8 @@ static NTSTATUS smb1cli_req_writev_submit(struct tevent_req *req,
                return NT_STATUS_NO_MEMORY;
        }
        tevent_req_set_callback(subreq, smb1cli_req_writev_done, req);
+       state->write_req = subreq;
+
        return NT_STATUS_OK;
 }
 
@@ -1670,6 +1684,8 @@ static void smb1cli_req_writev_done(struct tevent_req *subreq)
        ssize_t nwritten;
        int err;
 
+       state->write_req = NULL;
+
        nwritten = writev_recv(subreq, &err);
        TALLOC_FREE(subreq);
        if (nwritten == -1) {
@@ -3204,6 +3220,8 @@ skip_credits:
                return NT_STATUS_NO_MEMORY;
        }
        tevent_req_set_callback(subreq, smb2cli_req_writev_done, reqs[0]);
+       state->write_req = subreq;
+
        return NT_STATUS_OK;
 }
 
@@ -3265,6 +3283,8 @@ static void smb2cli_req_writev_done(struct tevent_req *subreq)
        ssize_t nwritten;
        int err;
 
+       state->write_req = NULL;
+
        nwritten = writev_recv(subreq, &err);
        TALLOC_FREE(subreq);
        if (nwritten == -1) {
@@ -4578,8 +4598,12 @@ static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_sta
                }
 
                SSVAL(p, 0, 2); /* ChiperCount */
-               SSVAL(p, 2, SMB2_ENCRYPTION_AES128_GCM);
-               SSVAL(p, 4, SMB2_ENCRYPTION_AES128_CCM);
+               /*
+                * For now we preferr CCM because our implementation
+                * is faster than GCM, see bug #11451.
+                */
+               SSVAL(p, 2, SMB2_ENCRYPTION_AES128_CCM);
+               SSVAL(p, 4, SMB2_ENCRYPTION_AES128_GCM);
 
                b = data_blob_const(p, 6);
                status = smb2_negotiate_context_add(state, &c,
@@ -5422,6 +5446,9 @@ uint8_t smb2cli_session_security_mode(struct smbXcli_session *session)
        if (conn->mandatory_signing) {
                security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
        }
+       if (session->smb2->should_sign) {
+               security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
+       }
 
        return security_mode;
 }
@@ -5853,6 +5880,14 @@ NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session,
 
 NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session)
 {
+       if (!session->smb2->should_sign) {
+               /*
+                * We need required signing on the session
+                * in order to prevent man in the middle attacks.
+                */
+               return NT_STATUS_INVALID_PARAMETER_MIX;
+       }
+
        if (session->smb2->should_encrypt) {
                return NT_STATUS_OK;
        }
@@ -5967,6 +6002,11 @@ uint32_t smb2cli_tcon_capabilities(struct smbXcli_tcon *tcon)
        return tcon->smb2.capabilities;
 }
 
+uint32_t smb2cli_tcon_flags(struct smbXcli_tcon *tcon)
+{
+       return tcon->smb2.flags;
+}
+
 void smb2cli_tcon_set_values(struct smbXcli_tcon *tcon,
                             struct smbXcli_session *session,
                             uint32_t tcon_id,