diff options
-rw-r--r-- | source3/include/client.h | 18 | ||||
-rw-r--r-- | source3/lib/util_sock.c | 9 | ||||
-rw-r--r-- | source3/libsmb/smb_seal.c | 178 |
3 files changed, 198 insertions, 7 deletions
diff --git a/source3/include/client.h b/source3/include/client.h index aa8a647947..97922ba232 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -34,8 +34,7 @@ * These definitions depend on smb.h */ -struct print_job_info -{ +struct print_job_info { uint16 id; uint16 priority; size_t size; @@ -79,6 +78,19 @@ struct rpc_pipe_client { struct dcinfo *dc; }; +/* Transport encryption state. */ +enum smb_trans_enc_type { SMB_TRANS_ENC_NTLM, SMB_TRANS_ENC_KRB5 }; + +struct smb_trans_enc_state { + enum smb_trans_enc_type smb_enc_type; + union { + NTLMSSP_STATE *ntlmssp_state; +#if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5) + gss_ctx_id_t context_handle; +#endif + }; +}; + struct cli_state { int port; int fd; @@ -137,6 +149,8 @@ struct cli_state { smb_sign_info sign_info; + struct smb_trans_enc_state *trans_enc_state; /* Setup if we're encrypting SMB's. */ + /* the session key for this CLI, outside any per-pipe authenticaion */ DATA_BLOB user_session_key; diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index 663502bef0..296405edd3 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -770,29 +770,32 @@ BOOL send_smb(int fd, char *buffer) size_t len; size_t nwritten=0; ssize_t ret; + char *buf_out; /* Sign the outgoing packet if required. */ srv_calculate_sign_mac(buffer); - status = srv_encrypt_buffer(buffer); + status = srv_encrypt_buffer(buffer, &buf_out); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("send_smb: SMB encryption failed on outgoing packet! Error %s\n", nt_errstr(status) )); return False; } - len = smb_len(buffer) + 4; + len = smb_len(buf_out) + 4; while (nwritten < len) { - ret = write_data(fd,buffer+nwritten,len - nwritten); + ret = write_data(fd,buf_out+nwritten,len - nwritten); if (ret <= 0) { DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n", (int)len,(int)ret, strerror(errno) )); + srv_free_buffer(buf_out); return False; } nwritten += ret; } + srv_free_buffer(buf_out); return True; } diff --git a/source3/libsmb/smb_seal.c b/source3/libsmb/smb_seal.c index eb35fc05f9..90efa05f0b 100644 --- a/source3/libsmb/smb_seal.c +++ b/source3/libsmb/smb_seal.c @@ -30,12 +30,186 @@ NTSTATUS cli_encrypt_message(struct cli_state *cli) return NT_STATUS_OK; } -NTSTATUS srv_decrypt_buffer(char *buffer) +/* Server state if we're encrypting SMBs. If NULL then enc is off. */ + +static struct smb_trans_enc_state *srv_trans_enc_state; + +/****************************************************************************** + Is server encryption on ? +******************************************************************************/ + +BOOL srv_encryption_on(void) +{ + return srv_trans_enc_state != NULL; +} + +/****************************************************************************** + Free an encryption-allocated buffer. +******************************************************************************/ + +void srv_free_buffer(char *buf_out) { + if (!srv_trans_enc_state) { + return; + } + + if (srv_trans_enc_state->smb_enc_type == SMB_TRANS_ENC_NTLM) { + SAFE_FREE(buf_out); + return; + } + +#if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5) + /* gss-api free buffer.... */ +#endif +} + +/****************************************************************************** + gss-api decrypt an incoming buffer. +******************************************************************************/ + +#if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5) +static NTSTATUS srv_gss_decrypt_buffer(gss_ctx_id_t context_handle, char *buf) +{ + return NT_STATUS_NOT_SUPPORTED; +} +#endif + +/****************************************************************************** + NTLM decrypt an incoming buffer. +******************************************************************************/ + +static NTSTATUS srv_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf) +{ + NTSTATUS status; + size_t orig_len = smb_len(buf); + size_t new_len = orig_len - NTLMSSP_SIG_SIZE; + DATA_BLOB sig; + + if (orig_len < 8 + NTLMSSP_SIG_SIZE) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + + /* Save off the signature. */ + sig = data_blob(buf+orig_len-NTLMSSP_SIG_SIZE, NTLMSSP_SIG_SIZE); + + status = ntlmssp_unseal_packet(ntlmssp_state, + (unsigned char *)buf + 8, /* 4 byte len + 0xFF 'S' 'M' 'B' */ + new_len - 8, + (unsigned char *)buf, + new_len, + &sig); + + if (!NT_STATUS_IS_OK(status)) { + data_blob_free(&sig); + return status; + } + /* Reset the length. */ + smb_setlen(buf, new_len); return NT_STATUS_OK; } -NTSTATUS srv_encrypt_buffer(char *buffer) +/****************************************************************************** + Decrypt an incoming buffer. +******************************************************************************/ + +NTSTATUS srv_decrypt_buffer(char *buf) { + if (!srv_trans_enc_state) { + /* Not decrypting. */ + return NT_STATUS_OK; + } + if (srv_trans_enc_state->smb_enc_type == SMB_TRANS_ENC_NTLM) { + return srv_ntlm_decrypt_buffer(srv_trans_enc_state->ntlmssp_state, buf); + } else { +#if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5) + return srv_gss_decrypt_buffer(srv_trans_enc_state->context_handle, buf); +#else + return NT_STATUS_NOT_SUPPORTED; +#endif + } +} + +/****************************************************************************** + gss-api encrypt an outgoing buffer. Return the encrypted pointer in buf_out. +******************************************************************************/ + +#if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5) +static NTSTATUS srv_gss_encrypt_buffer(gss_ctx_id_t context_handle, char *buf, char **buf_out) +{ + return NT_STATUS_NOT_SUPPORTED; +} +#endif + +/****************************************************************************** + NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out. +******************************************************************************/ + +static NTSTATUS srv_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf, char **ppbuf_out) +{ + NTSTATUS status; + char *buf_out; + size_t orig_len = smb_len(buf); + size_t new_len = orig_len + NTLMSSP_SIG_SIZE; + DATA_BLOB sig; + + *ppbuf_out = NULL; + + if (orig_len < 8) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + + /* + * We know smb_len can't return a value > 128k, so no int overflow + * check needed. + */ + + /* Copy the original buffer. */ + + buf_out = SMB_XMALLOC_ARRAY(char, new_len); + memcpy(buf_out, buf, orig_len); + /* Last 16 bytes undefined here... */ + + smb_setlen(buf_out, new_len); + + sig = data_blob(NULL, NTLMSSP_SIG_SIZE); + + status = ntlmssp_seal_packet(ntlmssp_state, + (unsigned char *)buf_out + 8, /* 4 byte len + 0xFF 'S' 'M' 'B' */ + orig_len - 8, + (unsigned char *)buf_out, + orig_len, + &sig); + + if (!NT_STATUS_IS_OK(status)) { + data_blob_free(&sig); + SAFE_FREE(buf_out); + return status; + } + + memcpy(buf_out+orig_len, sig.data, NTLMSSP_SIG_SIZE); + *ppbuf_out = buf_out; return NT_STATUS_OK; } + +/****************************************************************************** + Encrypt an outgoing buffer. Return the encrypted pointer in buf_out. +******************************************************************************/ + +NTSTATUS srv_encrypt_buffer(char *buffer, char **buf_out) +{ + if (!srv_trans_enc_state) { + /* Not encrypting. */ + *buf_out = buffer; + return NT_STATUS_OK; + } + + if (srv_trans_enc_state->smb_enc_type == SMB_TRANS_ENC_NTLM) { + return srv_ntlm_encrypt_buffer(srv_trans_enc_state->ntlmssp_state, buffer, buf_out); + } else { +#if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5) + return srv_gss_encrypt_buffer(srv_trans_enc_state->context_handle, buffer, buf_out); +#else + return NT_STATUS_NOT_SUPPORTED; +#endif + } +} |