From c48b610b516b72edd6232235a6f83d388f5a0552 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 19 Mar 2007 20:39:58 +0000 Subject: r21876: Start adding in the seal implementation - prototype code for the server side enc. (doesn't break anything). I'll keep updating this until I've got NTLM seal working on both client and server, then add in the gss level seal. Jeremy. (This used to be commit 530ac29abf23e920baa549e7cec55199edd8bd74) --- source3/include/client.h | 18 ++++- source3/lib/util_sock.c | 9 ++- source3/libsmb/smb_seal.c | 178 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 198 insertions(+), 7 deletions(-) (limited to 'source3') 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 + } +} -- cgit