2011-10-19 15:47:39 +04:00
/*
2007-12-27 04:12:36 +03:00
Unix SMB / CIFS implementation .
SMB Transport encryption ( sealing ) code .
Copyright ( C ) Jeremy Allison 2007.
2011-10-19 15:47:39 +04:00
2007-12-27 04:12:36 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
2011-10-19 15:47:39 +04:00
2007-12-27 04:12:36 +03:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2011-10-19 15:47:39 +04:00
2007-12-27 04:12:36 +03:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-10-19 15:47:39 +04:00
# include "smb_common.h"
2012-01-02 00:17:43 +04:00
# if HAVE_KRB5
2011-10-20 15:23:27 +04:00
# include "libcli/auth/krb5_wrap.h"
2012-01-02 00:17:43 +04:00
# endif
2011-10-18 14:27:39 +04:00
# include "auth/gensec/gensec.h"
2011-10-24 10:33:59 +04:00
# include "libcli/smb/smb_seal.h"
2011-07-21 13:13:59 +04:00
2011-10-20 15:44:14 +04:00
# undef malloc
2007-12-27 04:12:36 +03:00
/******************************************************************************
Pull out the encryption context for this packet . 0 means global context .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-10-19 17:35:23 +04:00
NTSTATUS get_enc_ctx_num ( const uint8_t * buf , uint16_t * p_enc_ctx_num )
2007-12-27 04:12:36 +03:00
{
2011-10-20 11:47:53 +04:00
if ( smb_len_nbt ( buf ) < 8 ) {
2007-12-27 04:12:36 +03:00
return NT_STATUS_INVALID_BUFFER_SIZE ;
}
2008-01-04 23:56:23 +03:00
if ( buf [ 4 ] = = 0xFF ) {
2007-12-27 04:12:36 +03:00
if ( buf [ 5 ] = = ' S ' & & buf [ 6 ] = = ' M ' & & buf [ 7 ] = = ' B ' ) {
/* Not an encrypted buffer. */
return NT_STATUS_NOT_FOUND ;
}
if ( buf [ 5 ] = = ' E ' ) {
* p_enc_ctx_num = SVAL ( buf , 6 ) ;
return NT_STATUS_OK ;
}
}
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2011-10-19 19:37:29 +04:00
/*******************************************************************
Set the length and marker of an encrypted smb packet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void smb_set_enclen ( char * buf , int len , uint16_t enc_ctx_num )
{
2011-10-20 11:47:53 +04:00
_smb_setlen_nbt ( buf , len ) ;
2011-10-19 19:37:29 +04:00
SCVAL ( buf , 4 , 0xFF ) ;
SCVAL ( buf , 5 , ' E ' ) ;
SSVAL ( buf , 6 , enc_ctx_num ) ;
}
2007-12-27 04:12:36 +03:00
/******************************************************************************
Generic code for client and server .
Is encryption turned on ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool common_encryption_on ( struct smb_trans_enc_state * es )
{
return ( ( es ! = NULL ) & & es - > enc_on ) ;
}
/******************************************************************************
Generic code for client and server .
2011-10-19 08:57:18 +04:00
GENSEC decrypt an incoming buffer .
2007-12-27 04:12:36 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-10-19 08:57:18 +04:00
static NTSTATUS common_gensec_decrypt_buffer ( struct gensec_security * gensec ,
char * buf )
2007-12-27 04:12:36 +03:00
{
NTSTATUS status ;
2011-10-20 11:47:53 +04:00
size_t buf_len = smb_len_nbt ( buf ) + 4 ; /* Don't forget the 4 length bytes. */
2011-10-20 13:53:40 +04:00
DATA_BLOB in_buf , out_buf ;
TALLOC_CTX * frame ;
2007-12-27 04:12:36 +03:00
2011-10-20 13:53:40 +04:00
if ( buf_len < 8 ) {
2007-12-27 04:12:36 +03:00
return NT_STATUS_BUFFER_TOO_SMALL ;
}
2011-10-20 13:53:40 +04:00
frame = talloc_stackframe ( ) ;
2007-12-27 04:12:36 +03:00
2011-10-20 13:53:40 +04:00
in_buf = data_blob_const ( buf + 8 , buf_len - 8 ) ;
2007-12-27 04:12:36 +03:00
2011-10-20 13:53:40 +04:00
status = gensec_unwrap ( gensec , frame , & in_buf , & out_buf ) ;
2007-12-27 04:12:36 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-10-19 08:57:18 +04:00
DEBUG ( 0 , ( " common_gensec_decrypt_buffer: gensec_unwrap failed. Error %s \n " ,
2011-10-20 13:53:40 +04:00
nt_errstr ( status ) ) ) ;
TALLOC_FREE ( frame ) ;
2007-12-27 04:12:36 +03:00
return status ;
}
2011-10-20 13:53:40 +04:00
if ( out_buf . length > in_buf . length ) {
2011-10-19 08:57:18 +04:00
DEBUG ( 0 , ( " common_gensec_decrypt_buffer: gensec_unwrap size (%u) too large (%u) ! \n " ,
2011-10-20 13:53:40 +04:00
( unsigned int ) out_buf . length ,
( unsigned int ) in_buf . length ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
memcpy ( buf + 8 , out_buf . data , out_buf . length ) ;
2007-12-27 04:12:36 +03:00
2008-01-04 23:56:23 +03:00
/* Reset the length and overwrite the header. */
2011-10-20 13:53:40 +04:00
smb_setlen_nbt ( buf , out_buf . length + 4 ) ;
TALLOC_FREE ( frame ) ;
2007-12-27 04:12:36 +03:00
return NT_STATUS_OK ;
}
/******************************************************************************
Generic code for client and server .
NTLM encrypt an outgoing buffer . Return the encrypted pointer in ppbuf_out .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-10-19 08:57:18 +04:00
static NTSTATUS common_gensec_encrypt_buffer ( struct gensec_security * gensec ,
uint16_t enc_ctx_num ,
char * buf ,
char * * ppbuf_out )
2007-12-27 04:12:36 +03:00
{
NTSTATUS status ;
2011-10-20 13:53:40 +04:00
DATA_BLOB in_buf , out_buf ;
size_t buf_len = smb_len_nbt ( buf ) + 4 ; /* Don't forget the 4 length bytes. */
2010-05-25 14:55:40 +04:00
TALLOC_CTX * frame ;
2011-10-20 13:53:40 +04:00
2007-12-27 04:12:36 +03:00
* ppbuf_out = NULL ;
2011-10-20 13:53:40 +04:00
if ( buf_len < 8 ) {
2007-12-27 04:12:36 +03:00
return NT_STATUS_BUFFER_TOO_SMALL ;
}
2011-10-20 13:53:40 +04:00
in_buf = data_blob_const ( buf + 8 , buf_len - 8 ) ;
2007-12-27 04:12:36 +03:00
2010-05-25 14:55:40 +04:00
frame = talloc_stackframe ( ) ;
2007-12-27 04:12:36 +03:00
2011-10-20 13:53:40 +04:00
status = gensec_wrap ( gensec , frame , & in_buf , & out_buf ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-10-19 08:57:18 +04:00
DEBUG ( 0 , ( " common_gensec_encrypt_buffer: gensec_wrap failed. Error %s \n " ,
2011-10-20 13:53:40 +04:00
nt_errstr ( status ) ) ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
* ppbuf_out = ( char * ) malloc ( out_buf . length + 8 ) ; /* We know this can't wrap. */
if ( ! * ppbuf_out ) {
2011-10-20 15:44:14 +04:00
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
2007-12-27 04:12:36 +03:00
2011-10-20 13:53:40 +04:00
memcpy ( * ppbuf_out + 8 , out_buf . data , out_buf . length ) ;
smb_set_enclen ( * ppbuf_out , out_buf . length + 4 , enc_ctx_num ) ;
2007-12-27 04:12:36 +03:00
2011-10-20 13:53:40 +04:00
TALLOC_FREE ( frame ) ;
2007-12-27 04:12:36 +03:00
return NT_STATUS_OK ;
}
/******************************************************************************
Generic code for client and server .
Encrypt an outgoing buffer . Return the alloced encrypted pointer in buf_out .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS common_encrypt_buffer ( struct smb_trans_enc_state * es , char * buffer , char * * buf_out )
{
if ( ! common_encryption_on ( es ) ) {
/* Not encrypting. */
* buf_out = buffer ;
return NT_STATUS_OK ;
}
2012-01-14 05:00:53 +04:00
return common_gensec_encrypt_buffer ( es - > gensec_security , es - > enc_ctx_num , buffer , buf_out ) ;
2007-12-27 04:12:36 +03:00
}
/******************************************************************************
Generic code for client and server .
Decrypt an incoming SMB buffer . Replaces the data within it .
New data must be less than or equal to the current length .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS common_decrypt_buffer ( struct smb_trans_enc_state * es , char * buf )
{
if ( ! common_encryption_on ( es ) ) {
/* Not decrypting. */
return NT_STATUS_OK ;
}
2012-01-14 05:00:53 +04:00
return common_gensec_decrypt_buffer ( es - > gensec_security , buf ) ;
2007-12-27 04:12:36 +03:00
}
/******************************************************************************
Free an encryption - allocated buffer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void common_free_enc_buffer ( struct smb_trans_enc_state * es , char * buf )
{
2008-12-06 00:20:55 +03:00
uint16_t enc_ctx_num ;
2007-12-27 04:12:36 +03:00
if ( ! common_encryption_on ( es ) ) {
return ;
}
2008-12-06 00:20:55 +03:00
if ( ! NT_STATUS_IS_OK ( get_enc_ctx_num ( ( const uint8_t * ) buf ,
& enc_ctx_num ) ) ) {
return ;
}
2011-10-20 15:46:05 +04:00
SAFE_FREE ( buf ) ;
2007-12-27 04:12:36 +03:00
}