From d2d5fb1abfcb9d21fe2742d53de00c7638fad14d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 14 Aug 2012 09:35:59 +0200 Subject: [PATCH] libcli/smb: verify decrypted SMB2 pdus correctly We need to make sure we got a encrypted response if we asked for it. If we don't get a encrypted response, we use a similar logic as with signing to propagated wellknown errors to the higher layer and set state->smb2.signing_skipped = true. metze Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Wed Aug 15 16:26:26 CEST 2012 on sn-devel-104 --- libcli/smb/smbXcli_base.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 05a97268a47..45da5fd90f1 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -3159,6 +3159,7 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn, uint32_t new_credits; struct smbXcli_session *session = NULL; const DATA_BLOB *signing_key = NULL; + bool was_encrypted = false; new_credits = conn->smb2.cur_credits; new_credits += credits; @@ -3276,6 +3277,26 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn, } } + if (cur[0].iov_len == SMB2_TF_HDR_SIZE) { + const uint8_t *tf = (const uint8_t *)cur[0].iov_base; + uint64_t uid = BVAL(tf, SMB2_TF_SESSION_ID); + + /* + * If the response was encrypted in a SMB2_TRANSFORM + * pdu, which belongs to the correct session, + * we do not need to do signing checks + * + * It could be the session the response belongs to + * or the session that was used to encrypt the + * SMB2_TRANSFORM request. + */ + if ((session && session->smb2->session_id == uid) || + (state->smb2.encryption_session_id == uid)) { + signing_key = NULL; + was_encrypted = true; + } + } + if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) { /* * if the server returns NT_STATUS_USER_SESSION_DELETED @@ -3283,9 +3304,24 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn, * propagate the NT_STATUS_USER_SESSION_DELETED * status to the caller. */ + state->smb2.signing_skipped = true; signing_key = NULL; - } else if (state->smb2.should_encrypt) { - if (cur[0].iov_len != SMB2_TF_HDR_SIZE) { + } + + if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { + /* + * if the server returns + * NT_STATUS_INVALID_PARAMETER + * the response might not be encrypted. + */ + if (state->smb2.should_encrypt && !was_encrypted) { + state->smb2.signing_skipped = true; + signing_key = NULL; + } + } + + if (state->smb2.should_encrypt && !was_encrypted) { + if (!state->smb2.signing_skipped) { return NT_STATUS_ACCESS_DENIED; } } -- 2.11.4.GIT