2007-12-26 17:12:36 -08:00
/*
Unix SMB / CIFS implementation .
SMB Transport encryption ( sealing ) code - server code .
Copyright ( C ) Jeremy Allison 2007.
2011-08-05 16:01:23 +02:00
2007-12-26 17:12:36 -08: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-08-05 16:01:23 +02:00
2007-12-26 17:12:36 -08: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-08-05 16:01:23 +02:00
2007-12-26 17:12:36 -08: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-03-22 16:57:01 +01:00
# include "smbd/smbd.h"
2009-01-08 12:03:45 +01:00
# include "smbd/globals.h"
2011-10-19 13:47:39 +02:00
# include "../libcli/smb/smb_seal.h"
2011-03-24 13:46:20 +01:00
# include "auth.h"
2011-05-06 11:47:43 +02:00
# include "libsmb/libsmb.h"
2011-06-15 11:15:06 +02:00
# include "../lib/tsocket/tsocket.h"
2011-10-18 21:13:16 +11:00
# include "auth/gensec/gensec.h"
2007-12-26 17:12:36 -08:00
/******************************************************************************
Server side encryption .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/******************************************************************************
2008-01-04 12:56:23 -08:00
Return global enc context - this must change if we ever do multiple contexts .
2007-12-26 17:12:36 -08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-10-19 16:33:04 +11:00
static uint16_t srv_enc_ctx ( const struct smb_trans_enc_state * es )
2007-12-26 17:12:36 -08:00
{
2011-10-19 16:33:04 +11:00
return es - > enc_ctx_num ;
2007-12-26 17:12:36 -08:00
}
2007-12-30 13:10:29 -08:00
/******************************************************************************
2008-01-04 12:56:23 -08:00
Is this an incoming encrypted packet ?
2007-12-30 13:10:29 -08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-11 14:28:13 +02:00
bool is_encrypted_packet ( const uint8_t * inbuf )
2007-12-30 13:10:29 -08:00
{
2008-01-04 12:56:23 -08:00
NTSTATUS status ;
uint16_t enc_num ;
2008-01-08 16:08:39 -08:00
/* Ignore non-session messages or non 0xFF'E' messages. */
2010-10-06 17:40:58 +02:00
if ( CVAL ( inbuf , 0 )
| | ( smb_len ( inbuf ) < 8 )
| | ! ( inbuf [ 4 ] = = 0xFF & & inbuf [ 5 ] = = ' E ' ) ) {
2008-01-04 12:56:23 -08:00
return false ;
}
status = get_enc_ctx_num ( inbuf , & enc_num ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return false ;
}
2008-01-08 16:08:39 -08:00
/* Encrypted messages are 0xFF'E'<ctx> */
2011-08-05 16:22:48 +02:00
if ( srv_trans_enc_ctx & & enc_num = = srv_enc_ctx ( srv_trans_enc_ctx ) ) {
2008-01-04 12:56:23 -08:00
return true ;
}
return false ;
2007-12-30 13:10:29 -08:00
}
2007-12-26 17:12:36 -08:00
/******************************************************************************
2011-12-26 14:23:15 +11:00
Create an gensec_security and ensure pointer copy is correct .
2007-12-26 17:12:36 -08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-12-26 15:58:11 +11:00
static NTSTATUS make_auth_gensec ( const struct tsocket_address * remote_address ,
2012-01-14 12:15:17 +11:00
struct smb_trans_enc_state * es )
2007-12-26 17:12:36 -08:00
{
2012-01-14 12:15:17 +11:00
NTSTATUS status ;
2012-01-14 15:30:34 +11:00
status = auth_generic_prepare ( es , remote_address ,
& es - > gensec_security ) ;
2007-12-26 17:12:36 -08:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return nt_status_squash ( status ) ;
}
2012-01-14 15:30:34 +11:00
gensec_want_feature ( es - > gensec_security , GENSEC_FEATURE_SEAL ) ;
2011-07-22 12:10:30 +10:00
2007-12-26 17:12:36 -08:00
/*
2012-01-13 20:34:10 +11:00
* We could be accessing the secrets . tdb or krb5 . keytab file here .
2007-12-26 17:12:36 -08:00
* ensure we have permissions to do so .
*/
become_root ( ) ;
2012-01-14 15:30:34 +11:00
status = gensec_start_mech_by_oid ( es - > gensec_security , GENSEC_OID_SPNEGO ) ;
2007-12-26 17:12:36 -08:00
2012-01-13 20:34:10 +11:00
unbecome_root ( ) ;
2007-12-26 17:12:36 -08:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-01-13 20:34:10 +11:00
return nt_status_squash ( status ) ;
2007-12-26 17:12:36 -08:00
}
2012-01-13 20:34:10 +11:00
return status ;
2007-12-26 17:12:36 -08:00
}
/******************************************************************************
Create a server encryption context .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-06-15 11:15:06 +02:00
static NTSTATUS make_srv_encryption_context ( const struct tsocket_address * remote_address ,
2011-10-19 16:33:04 +11:00
struct smb_trans_enc_state * * pp_es )
2007-12-26 17:12:36 -08:00
{
2012-01-13 20:34:10 +11:00
NTSTATUS status ;
2011-10-19 16:33:04 +11:00
struct smb_trans_enc_state * es ;
2007-12-26 17:12:36 -08:00
2011-10-19 16:33:04 +11:00
* pp_es = NULL ;
2007-12-26 17:12:36 -08:00
ZERO_STRUCTP ( partial_srv_trans_enc_ctx ) ;
2012-01-14 15:30:34 +11:00
es = talloc_zero ( NULL , struct smb_trans_enc_state ) ;
2011-10-19 16:33:04 +11:00
if ( ! es ) {
2007-12-26 17:12:36 -08:00
return NT_STATUS_NO_MEMORY ;
}
2012-01-13 20:34:10 +11:00
status = make_auth_gensec ( remote_address ,
2012-01-14 12:15:17 +11:00
es ) ;
2012-01-13 20:34:10 +11:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-01-14 15:30:34 +11:00
TALLOC_FREE ( es ) ;
2012-01-13 20:34:10 +11:00
return status ;
}
2011-10-19 16:33:04 +11:00
* pp_es = es ;
2007-12-26 17:12:36 -08:00
return NT_STATUS_OK ;
}
/******************************************************************************
Free an encryption - allocated buffer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-12 08:43:26 +02:00
void srv_free_enc_buffer ( struct smbXsrv_connection * xconn , char * buf )
2007-12-26 17:12:36 -08:00
{
/* We know this is an smb buffer, and we
* didn ' t malloc , only copy , for a keepalive ,
2008-01-04 12:56:23 -08:00
* so ignore non - session messages . */
2007-12-26 17:12:36 -08:00
2008-01-04 12:56:23 -08:00
if ( CVAL ( buf , 0 ) ) {
2007-12-26 17:12:36 -08:00
return ;
}
if ( srv_trans_enc_ctx ) {
2011-10-19 16:33:04 +11:00
common_free_enc_buffer ( srv_trans_enc_ctx , buf ) ;
2007-12-26 17:12:36 -08:00
}
}
/******************************************************************************
Decrypt an incoming buffer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-12 08:43:26 +02:00
NTSTATUS srv_decrypt_buffer ( struct smbXsrv_connection * xconn , char * buf )
2007-12-26 17:12:36 -08:00
{
2008-01-04 12:56:23 -08:00
/* Ignore non-session messages. */
if ( CVAL ( buf , 0 ) ) {
2007-12-26 17:12:36 -08:00
return NT_STATUS_OK ;
}
if ( srv_trans_enc_ctx ) {
2011-10-19 16:33:04 +11:00
return common_decrypt_buffer ( srv_trans_enc_ctx , buf ) ;
2007-12-26 17:12:36 -08:00
}
return NT_STATUS_OK ;
}
/******************************************************************************
Encrypt an outgoing buffer . Return the encrypted pointer in buf_out .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-12 08:43:26 +02:00
NTSTATUS srv_encrypt_buffer ( struct smbXsrv_connection * xconn , char * buf ,
2011-08-05 17:00:42 +02:00
char * * buf_out )
2007-12-26 17:12:36 -08:00
{
* buf_out = buf ;
2008-01-04 12:56:23 -08:00
/* Ignore non-session messages. */
if ( CVAL ( buf , 0 ) ) {
2007-12-26 17:12:36 -08:00
return NT_STATUS_OK ;
}
if ( srv_trans_enc_ctx ) {
2011-10-19 16:33:04 +11:00
return common_encrypt_buffer ( srv_trans_enc_ctx , buf , buf_out ) ;
2007-12-26 17:12:36 -08:00
}
/* Not encrypting. */
return NT_STATUS_OK ;
}
/******************************************************************************
Do the SPNEGO encryption negotiation . Parameters are in / out .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-01-14 12:15:17 +11:00
NTSTATUS srv_request_encryption_setup ( connection_struct * conn ,
2007-12-26 17:12:36 -08:00
unsigned char * * ppdata ,
size_t * p_data_size ,
unsigned char * * pparam ,
size_t * p_param_size )
{
NTSTATUS status ;
DATA_BLOB blob = data_blob_const ( * ppdata , * p_data_size ) ;
DATA_BLOB response = data_blob_null ;
2011-10-19 16:33:04 +11:00
struct smb_trans_enc_state * es ;
2007-12-26 17:12:36 -08:00
2012-01-14 12:15:17 +11:00
SAFE_FREE ( * pparam ) ;
* p_param_size = 0 ;
2007-12-26 17:12:36 -08:00
if ( ! partial_srv_trans_enc_ctx ) {
/* This is the initial step. */
2012-01-14 12:15:17 +11:00
status = make_srv_encryption_context ( conn - > sconn - > remote_address ,
& partial_srv_trans_enc_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2007-12-26 17:12:36 -08:00
}
}
2011-10-19 16:33:04 +11:00
es = partial_srv_trans_enc_ctx ;
2012-01-14 12:15:17 +11:00
if ( ! es | | es - > gensec_security = = NULL ) {
2012-01-14 15:30:34 +11:00
TALLOC_FREE ( partial_srv_trans_enc_ctx ) ;
2007-12-26 17:12:36 -08:00
return NT_STATUS_INVALID_PARAMETER ;
}
/* Second step. */
2012-01-14 12:15:17 +11:00
become_root ( ) ;
status = gensec_update ( es - > gensec_security ,
2013-12-13 19:56:13 +01:00
talloc_tos ( ) ,
2011-10-18 21:13:16 +11:00
blob , & response ) ;
2012-01-14 12:15:17 +11:00
unbecome_root ( ) ;
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) & &
! NT_STATUS_IS_OK ( status ) ) {
2012-01-14 15:30:34 +11:00
TALLOC_FREE ( partial_srv_trans_enc_ctx ) ;
2012-01-14 12:15:17 +11:00
return nt_status_squash ( status ) ;
}
2007-12-26 17:12:36 -08:00
if ( NT_STATUS_IS_OK ( status ) ) {
/* Return the context we're using for this encryption state. */
if ( ! ( * pparam = SMB_MALLOC_ARRAY ( unsigned char , 2 ) ) ) {
return NT_STATUS_NO_MEMORY ;
}
2011-10-19 16:33:04 +11:00
SSVAL ( * pparam , 0 , es - > enc_ctx_num ) ;
2007-12-26 17:12:36 -08:00
* p_param_size = 2 ;
}
/* Return the raw blob. */
SAFE_FREE ( * ppdata ) ;
2014-04-14 14:37:29 +02:00
* ppdata = ( unsigned char * ) smb_memdup ( response . data , response . length ) ;
2008-10-12 04:00:55 +02:00
if ( ( * ppdata ) = = NULL & & response . length > 0 )
return NT_STATUS_NO_MEMORY ;
2007-12-26 17:12:36 -08:00
* p_data_size = response . length ;
2008-10-12 04:00:55 +02:00
data_blob_free ( & response ) ;
2007-12-26 17:12:36 -08:00
return status ;
}
/******************************************************************************
Negotiation was successful - turn on server - side encryption .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-10-19 16:33:04 +11:00
static NTSTATUS check_enc_good ( struct smb_trans_enc_state * es )
2007-12-26 17:12:36 -08:00
{
2011-10-19 16:33:04 +11:00
if ( ! es ) {
2007-12-26 17:12:36 -08:00
return NT_STATUS_LOGON_FAILURE ;
}
2012-01-14 12:15:17 +11:00
if ( ! gensec_have_feature ( es - > gensec_security , GENSEC_FEATURE_SIGN ) ) {
return NT_STATUS_INVALID_PARAMETER ;
2007-12-26 17:12:36 -08:00
}
2012-01-14 12:15:17 +11:00
if ( ! gensec_have_feature ( es - > gensec_security , GENSEC_FEATURE_SEAL ) ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2007-12-26 17:12:36 -08:00
return NT_STATUS_OK ;
}
/******************************************************************************
Negotiation was successful - turn on server - side encryption .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS srv_encryption_start ( connection_struct * conn )
{
NTSTATUS status ;
/* Check that we are really doing sign+seal. */
status = check_enc_good ( partial_srv_trans_enc_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* Throw away the context we're using currently (if any). */
2012-01-14 15:30:34 +11:00
TALLOC_FREE ( srv_trans_enc_ctx ) ;
2007-12-26 17:12:36 -08:00
/* Steal the partial pointer. Deliberate shallow copy. */
srv_trans_enc_ctx = partial_srv_trans_enc_ctx ;
2011-10-19 16:33:04 +11:00
srv_trans_enc_ctx - > enc_on = true ;
2007-12-26 17:12:36 -08:00
partial_srv_trans_enc_ctx = NULL ;
2008-01-04 12:56:23 -08:00
2008-01-08 16:08:39 -08:00
DEBUG ( 1 , ( " srv_encryption_start: context negotiated \n " ) ) ;
2007-12-26 17:12:36 -08:00
return NT_STATUS_OK ;
}
/******************************************************************************
Shutdown all server contexts .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-12 08:43:26 +02:00
void server_encryption_shutdown ( struct smbXsrv_connection * xconn )
2007-12-26 17:12:36 -08:00
{
2012-01-14 15:30:34 +11:00
TALLOC_FREE ( partial_srv_trans_enc_ctx ) ;
TALLOC_FREE ( srv_trans_enc_ctx ) ;
2007-12-26 17:12:36 -08:00
}