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"
2010-06-30 12:19:07 +04:00
# include "../libcli/auth/schannel_proto.h"
2009-08-25 23:16:27 +04:00
# 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"
/******************************************************************************
2010-06-23 04:31:50 +04:00
Open or create the schannel session store tdb . Non - static so it can
be called from parent processes to corectly handle TDB_CLEAR_IF_FIRST
2010-02-18 22:44:09 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-23 04:31:50 +04:00
struct tdb_wrap * open_schannel_session_store ( TALLOC_CTX * mem_ctx ,
const char * private_dir )
2010-02-18 22:44:09 +03:00
{
2010-02-19 00:17:06 +03:00
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-06-23 04:37:13 +04:00
tdb_sc = tdb_wrap_open ( mem_ctx , fname , 0 , TDB_CLEAR_IF_FIRST | TDB_NOSYNC , 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 ;
}
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 ,
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-05-09 19:20:01 +04:00
ndr_err = ndr_push_struct_blob ( & blob , mem_ctx , 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 ,
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 ) {
2010-04-12 00:56:09 +04:00
return NT_STATUS_NO_MEMORY ;
2009-08-25 23:16:27 +04:00
}
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-05-09 19:20:01 +04:00
ndr_err = ndr_pull_struct_blob ( & blob , creds , 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
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-05-09 19:20:01 +04:00
status = schannel_fetch_session_key_tdb ( tdb_sc , tmpctx ,
2010-02-19 00:17:06 +03:00
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
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-05-09 19:20:01 +04:00
status = schannel_store_session_key_tdb ( tdb_sc , tmpctx , 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
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-05-09 19:20:01 +04:00
status = schannel_fetch_session_key_tdb ( tdb_sc , tmpctx ,
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-05-09 19:20:01 +04:00
status = schannel_store_session_key_tdb ( tdb_sc , tmpctx , 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