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