2009-08-25 23:16:27 +04:00
/*
Unix SMB / CIFS implementation .
module to store / fetch session keys for the schannel server
Copyright ( C ) Andrew Tridgell 2004
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2006 - 2009
Copyright ( C ) Guenther Deschner 2009
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 .
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 .
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"
2010-02-19 00:17:06 +03:00
# include "system/filesys.h"
# include <tdb.h>
# include "../lib/util/util_tdb.h"
2009-08-25 23:16:27 +04:00
# include "../libcli/auth/libcli_auth.h"
# include "../libcli/auth/schannel_state.h"
# include "../librpc/gen_ndr/ndr_schannel.h"
2010-02-19 00:17:06 +03:00
# if _SAMBA_BUILD_ == 4
# include "tdb_wrap.h"
# endif
2009-08-25 23:16:27 +04:00
2010-02-18 22:44:09 +03:00
# define SECRETS_SCHANNEL_STATE "SECRETS / SCHANNEL"
/******************************************************************************
Open or create the schannel session store tdb .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define SCHANNEL_STORE_VERSION_1 1
# define SCHANNEL_STORE_VERSION_2 2 /* should not be used */
# define SCHANNEL_STORE_VERSION_CURRENT SCHANNEL_STORE_VERSION_1
2010-02-19 00:17:06 +03:00
static struct tdb_wrap * open_schannel_session_store ( TALLOC_CTX * mem_ctx ,
const char * private_dir )
2010-02-18 22:44:09 +03:00
{
TDB_DATA vers ;
2010-02-19 00:17:06 +03:00
uint32_t ver ;
struct tdb_wrap * tdb_sc = NULL ;
char * fname = talloc_asprintf ( mem_ctx , " %s/schannel_store.tdb " , private_dir ) ;
2010-02-18 22:44:09 +03:00
if ( ! fname ) {
return NULL ;
}
2010-02-19 00:17:06 +03:00
tdb_sc = tdb_wrap_open ( mem_ctx , fname , 0 , TDB_DEFAULT , O_RDWR | O_CREAT , 0600 ) ;
2010-02-18 22:44:09 +03:00
if ( ! tdb_sc ) {
2010-02-26 12:09:36 +03:00
DEBUG ( 0 , ( " open_schannel_session_store: Failed to open %s - %s \n " ,
fname , strerror ( errno ) ) ) ;
2010-02-18 22:44:09 +03:00
TALLOC_FREE ( fname ) ;
return NULL ;
}
again :
2010-02-19 00:17:06 +03:00
vers = tdb_fetch_bystring ( tdb_sc - > tdb , " SCHANNEL_STORE_VERSION " ) ;
2010-02-18 22:44:09 +03:00
if ( vers . dptr = = NULL ) {
/* First opener, no version. */
SIVAL ( & ver , 0 , SCHANNEL_STORE_VERSION_CURRENT ) ;
2010-02-19 00:17:06 +03:00
vers . dptr = ( uint8_t * ) & ver ;
2010-02-18 22:44:09 +03:00
vers . dsize = 4 ;
2010-02-19 00:17:06 +03:00
tdb_store_bystring ( tdb_sc - > tdb , " SCHANNEL_STORE_VERSION " , vers , TDB_REPLACE ) ;
2010-02-18 22:44:09 +03:00
vers . dptr = NULL ;
} else if ( vers . dsize = = 4 ) {
ver = IVAL ( vers . dptr , 0 ) ;
if ( ver = = SCHANNEL_STORE_VERSION_2 ) {
DEBUG ( 0 , ( " open_schannel_session_store: wrong version number %d in %s \n " ,
( int ) ver , fname ) ) ;
2010-02-19 00:17:06 +03:00
tdb_wipe_all ( tdb_sc - > tdb ) ;
2010-02-18 22:44:09 +03:00
goto again ;
}
if ( ver ! = SCHANNEL_STORE_VERSION_CURRENT ) {
DEBUG ( 0 , ( " open_schannel_session_store: wrong version number %d in %s \n " ,
( int ) ver , fname ) ) ;
2010-02-19 00:17:06 +03:00
TALLOC_FREE ( tdb_sc ) ;
2010-02-18 22:44:09 +03:00
}
} else {
2010-02-19 00:17:06 +03:00
TALLOC_FREE ( tdb_sc ) ;
2010-02-18 22:44:09 +03:00
DEBUG ( 0 , ( " open_schannel_session_store: wrong version number size %d in %s \n " ,
( int ) vers . dsize , fname ) ) ;
}
SAFE_FREE ( vers . dptr ) ;
TALLOC_FREE ( fname ) ;
return tdb_sc ;
}
2009-08-25 23:16:27 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-02-18 22:44:09 +03:00
static
2010-02-19 00:17:06 +03:00
NTSTATUS schannel_store_session_key_tdb ( struct tdb_wrap * tdb_sc ,
2009-08-25 23:16:27 +04:00
TALLOC_CTX * mem_ctx ,
2010-02-19 00:17:06 +03:00
struct smb_iconv_convenience * ic ,
2009-08-25 23:16:27 +04:00
struct netlogon_creds_CredentialState * creds )
{
enum ndr_err_code ndr_err ;
DATA_BLOB blob ;
TDB_DATA value ;
int ret ;
char * keystr ;
2010-02-19 00:17:06 +03:00
char * name_upper ;
2009-08-25 23:16:27 +04:00
2010-02-19 00:17:06 +03:00
name_upper = strupper_talloc ( mem_ctx , creds - > computer_name ) ;
if ( ! name_upper ) {
return NT_STATUS_NO_MEMORY ;
}
keystr = talloc_asprintf ( mem_ctx , " %s/%s " ,
SECRETS_SCHANNEL_STATE , name_upper ) ;
TALLOC_FREE ( name_upper ) ;
2009-08-25 23:16:27 +04:00
if ( ! keystr ) {
return NT_STATUS_NO_MEMORY ;
}
2010-02-19 00:17:06 +03:00
ndr_err = ndr_push_struct_blob ( & blob , mem_ctx , ic , creds ,
2009-08-25 23:16:27 +04:00
( ndr_push_flags_fn_t ) ndr_push_netlogon_creds_CredentialState ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( keystr ) ;
return ndr_map_error2ntstatus ( ndr_err ) ;
}
value . dptr = blob . data ;
value . dsize = blob . length ;
2010-02-19 00:17:06 +03:00
ret = tdb_store_bystring ( tdb_sc - > tdb , keystr , value , TDB_REPLACE ) ;
2009-08-25 23:16:27 +04:00
if ( ret ! = TDB_SUCCESS ) {
DEBUG ( 0 , ( " Unable to add %s to session key db - %s \n " ,
2010-02-19 00:17:06 +03:00
keystr , tdb_errorstr ( tdb_sc - > tdb ) ) ) ;
2009-08-25 23:16:27 +04:00
talloc_free ( keystr ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
DEBUG ( 3 , ( " schannel_store_session_key_tdb: stored schannel info with key %s \n " ,
keystr ) ) ;
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( netlogon_creds_CredentialState , creds ) ;
}
talloc_free ( keystr ) ;
return NT_STATUS_OK ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-02-18 22:44:09 +03:00
static
2010-02-19 00:17:06 +03:00
NTSTATUS schannel_fetch_session_key_tdb ( struct tdb_wrap * tdb_sc ,
2009-08-25 23:16:27 +04:00
TALLOC_CTX * mem_ctx ,
2010-02-19 00:17:06 +03:00
struct smb_iconv_convenience * ic ,
2009-08-25 23:16:27 +04:00
const char * computer_name ,
struct netlogon_creds_CredentialState * * pcreds )
{
NTSTATUS status ;
TDB_DATA value ;
enum ndr_err_code ndr_err ;
DATA_BLOB blob ;
struct netlogon_creds_CredentialState * creds = NULL ;
char * keystr = NULL ;
2010-02-19 00:17:06 +03:00
char * name_upper ;
2009-08-25 23:16:27 +04:00
* pcreds = NULL ;
2010-02-19 00:17:06 +03:00
name_upper = strupper_talloc ( mem_ctx , computer_name ) ;
if ( ! name_upper ) {
return NT_STATUS_NO_MEMORY ;
}
keystr = talloc_asprintf ( mem_ctx , " %s/%s " ,
SECRETS_SCHANNEL_STATE , name_upper ) ;
TALLOC_FREE ( name_upper ) ;
2009-08-25 23:16:27 +04:00
if ( ! keystr ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
2010-02-19 00:17:06 +03:00
value = tdb_fetch_bystring ( tdb_sc - > tdb , keystr ) ;
2009-08-25 23:16:27 +04:00
if ( ! value . dptr ) {
DEBUG ( 0 , ( " schannel_fetch_session_key_tdb: Failed to find entry with key %s \n " ,
keystr ) ) ;
status = NT_STATUS_OBJECT_NAME_NOT_FOUND ;
goto done ;
}
creds = talloc_zero ( mem_ctx , struct netlogon_creds_CredentialState ) ;
if ( ! creds ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
blob = data_blob_const ( value . dptr , value . dsize ) ;
2010-02-19 00:17:06 +03:00
ndr_err = ndr_pull_struct_blob ( & blob , creds , ic , creds ,
2009-08-25 23:16:27 +04:00
( ndr_pull_flags_fn_t ) ndr_pull_netlogon_creds_CredentialState ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
goto done ;
}
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( netlogon_creds_CredentialState , creds ) ;
}
DEBUG ( 3 , ( " schannel_fetch_session_key_tdb: restored schannel info key %s \n " ,
keystr ) ) ;
status = NT_STATUS_OK ;
done :
talloc_free ( keystr ) ;
2010-03-16 18:23:57 +03:00
SAFE_FREE ( value . dptr ) ;
2009-08-25 23:16:27 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( creds ) ;
return status ;
}
* pcreds = creds ;
return NT_STATUS_OK ;
}
2010-02-18 22:44:09 +03:00
/******************************************************************************
Wrapper around schannel_fetch_session_key_tdb ( )
Note we must be root here .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS schannel_get_creds_state ( TALLOC_CTX * mem_ctx ,
2010-02-19 00:17:06 +03:00
struct smb_iconv_convenience * ic ,
const char * db_priv_dir ,
2010-02-18 22:44:09 +03:00
const char * computer_name ,
2010-02-19 00:17:06 +03:00
struct netlogon_creds_CredentialState * * _creds )
2010-02-18 22:44:09 +03:00
{
2010-02-19 00:17:06 +03:00
TALLOC_CTX * tmpctx ;
struct tdb_wrap * tdb_sc ;
struct netlogon_creds_CredentialState * creds ;
2010-02-18 22:44:09 +03:00
NTSTATUS status ;
2010-02-19 00:17:06 +03:00
tmpctx = talloc_named ( mem_ctx , 0 , " schannel_get_creds_state " ) ;
if ( ! tmpctx ) {
return NT_STATUS_NO_MEMORY ;
2010-02-18 22:44:09 +03:00
}
2009-08-25 23:16:27 +04:00
2010-02-19 00:17:06 +03:00
tdb_sc = open_schannel_session_store ( tmpctx , db_priv_dir ) ;
if ( ! tdb_sc ) {
return NT_STATUS_ACCESS_DENIED ;
}
2009-08-25 23:16:27 +04:00
2010-02-19 00:17:06 +03:00
status = schannel_fetch_session_key_tdb ( tdb_sc , tmpctx , ic ,
computer_name , & creds ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
* _creds = talloc_steal ( mem_ctx , creds ) ;
if ( ! * _creds ) {
status = NT_STATUS_NO_MEMORY ;
}
}
2009-08-25 23:16:27 +04:00
2010-02-19 00:17:06 +03:00
talloc_free ( tmpctx ) ;
2010-02-18 22:44:09 +03:00
return status ;
}
/******************************************************************************
Wrapper around schannel_store_session_key_tdb ( )
Note we must be root here .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS schannel_save_creds_state ( TALLOC_CTX * mem_ctx ,
2010-02-19 00:17:06 +03:00
struct smb_iconv_convenience * ic ,
const char * db_priv_dir ,
2010-02-18 22:44:09 +03:00
struct netlogon_creds_CredentialState * creds )
{
2010-02-19 00:17:06 +03:00
TALLOC_CTX * tmpctx ;
struct tdb_wrap * tdb_sc ;
2010-02-18 22:44:09 +03:00
NTSTATUS status ;
2010-02-19 00:17:06 +03:00
tmpctx = talloc_named ( mem_ctx , 0 , " schannel_save_creds_state " ) ;
if ( ! tmpctx ) {
return NT_STATUS_NO_MEMORY ;
2010-02-18 22:44:09 +03:00
}
2009-08-25 23:16:27 +04:00
2010-02-19 00:17:06 +03:00
tdb_sc = open_schannel_session_store ( tmpctx , db_priv_dir ) ;
if ( ! tdb_sc ) {
return NT_STATUS_ACCESS_DENIED ;
}
2010-02-18 22:44:09 +03:00
2010-02-19 00:17:06 +03:00
status = schannel_store_session_key_tdb ( tdb_sc , tmpctx , ic , creds ) ;
2010-02-18 22:44:09 +03:00
2010-02-19 00:17:06 +03:00
talloc_free ( tmpctx ) ;
2010-02-18 22:44:09 +03:00
return status ;
}
/********************************************************************
Validate an incoming authenticator against the credentials for the
remote machine stored in the schannel database .
The credentials are ( re ) read and from the schannel database , and
written back after the caclulations are performed .
If the creds_out parameter is not NULL returns the credentials .
2009-08-25 23:16:27 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-02-18 22:44:09 +03:00
NTSTATUS schannel_check_creds_state ( TALLOC_CTX * mem_ctx ,
2010-02-19 00:17:06 +03:00
struct smb_iconv_convenience * ic ,
const char * db_priv_dir ,
2010-02-18 22:44:09 +03:00
const char * computer_name ,
struct netr_Authenticator * received_authenticator ,
struct netr_Authenticator * return_authenticator ,
struct netlogon_creds_CredentialState * * creds_out )
2009-08-25 23:16:27 +04:00
{
2010-02-18 22:44:09 +03:00
TALLOC_CTX * tmpctx ;
2010-02-19 00:17:06 +03:00
struct tdb_wrap * tdb_sc ;
2009-08-25 23:16:27 +04:00
struct netlogon_creds_CredentialState * creds ;
NTSTATUS status ;
int ret ;
2010-02-18 22:44:09 +03:00
tmpctx = talloc_named ( mem_ctx , 0 , " schannel_check_creds_state " ) ;
if ( ! tmpctx ) {
return NT_STATUS_NO_MEMORY ;
}
2010-02-19 00:17:06 +03:00
tdb_sc = open_schannel_session_store ( tmpctx , db_priv_dir ) ;
if ( ! tdb_sc ) {
2010-02-18 22:44:09 +03:00
status = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
2010-02-19 00:17:06 +03:00
ret = tdb_transaction_start ( tdb_sc - > tdb ) ;
2009-08-25 23:16:27 +04:00
if ( ret ! = 0 ) {
2010-02-18 22:44:09 +03:00
status = NT_STATUS_INTERNAL_DB_CORRUPTION ;
goto done ;
2009-08-25 23:16:27 +04:00
}
/* Because this is a shared structure (even across
* disconnects ) we must update the database every time we
* update the structure */
2010-02-19 00:17:06 +03:00
status = schannel_fetch_session_key_tdb ( tdb_sc , tmpctx , ic ,
2010-02-18 22:44:09 +03:00
computer_name , & creds ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-02-19 00:17:06 +03:00
tdb_transaction_cancel ( tdb_sc - > tdb ) ;
2010-02-18 22:44:09 +03:00
goto done ;
}
2009-08-25 23:16:27 +04:00
2010-02-18 22:44:09 +03:00
status = netlogon_creds_server_step_check ( creds ,
received_authenticator ,
return_authenticator ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-02-19 00:17:06 +03:00
tdb_transaction_cancel ( tdb_sc - > tdb ) ;
2010-02-18 22:44:09 +03:00
goto done ;
2009-08-25 23:16:27 +04:00
}
2010-02-19 00:17:06 +03:00
status = schannel_store_session_key_tdb ( tdb_sc , tmpctx , ic , creds ) ;
2010-02-18 22:44:09 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-02-19 00:17:06 +03:00
tdb_transaction_cancel ( tdb_sc - > tdb ) ;
2010-02-18 22:44:09 +03:00
goto done ;
2009-08-25 23:16:27 +04:00
}
2010-02-19 00:17:06 +03:00
tdb_transaction_commit ( tdb_sc - > tdb ) ;
2010-02-18 22:44:09 +03:00
if ( creds_out ) {
* creds_out = talloc_steal ( mem_ctx , creds ) ;
if ( ! * creds_out ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
2009-08-25 23:16:27 +04:00
}
}
2010-02-18 22:44:09 +03:00
status = NT_STATUS_OK ;
done :
talloc_free ( tmpctx ) ;
2009-08-25 23:16:27 +04:00
return status ;
}
2010-02-18 22:44:09 +03:00