2010-05-17 07:39:42 +04:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Andrew Tridgell 1992 - 2001
Copyright ( C ) Andrew Bartlett 2002
Copyright ( C ) Rafal Szczesniak 2002
Copyright ( C ) Tim Potter 2001
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/>.
*/
/* the Samba secrets database stores any generated, private information
such as the local SID and machine trust password */
# include "includes.h"
2011-03-18 20:58:37 +03:00
# include "passdb.h"
2010-05-17 07:39:42 +04:00
# include "../libcli/auth/libcli_auth.h"
2010-08-05 04:25:37 +04:00
# include "secrets.h"
2011-07-07 19:42:08 +04:00
# include "dbwrap/dbwrap.h"
2011-03-31 01:47:34 +04:00
# include "../librpc/ndr/libndr.h"
2011-05-05 13:25:29 +04:00
# include "util_tdb.h"
2014-05-13 09:47:03 +04:00
# include "libcli/security/security.h"
2010-05-17 07:39:42 +04:00
2017-05-19 17:28:17 +03:00
# include "librpc/gen_ndr/libnet_join.h"
# include "librpc/gen_ndr/ndr_secrets.h"
# include "lib/crypto/crypto.h"
# include "lib/krb5_wrap/krb5_samba.h"
# include "lib/util/time_basic.h"
2018-02-16 19:15:28 +03:00
# include "../libds/common/flags.h"
2020-08-07 21:17:34 +03:00
# include "lib/util/string_wrappers.h"
2017-05-19 17:28:17 +03:00
2010-05-17 07:39:42 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_PASSDB
2017-05-19 17:28:17 +03:00
static char * domain_info_keystr ( const char * domain ) ;
2017-05-22 13:18:33 +03:00
static char * des_salt_key ( const char * realm ) ;
2010-05-17 07:39:42 +04:00
/**
* Form a key for fetching the domain sid
*
* @ param domain domain name
*
* @ return keystring
* */
static const char * domain_sid_keystr ( const char * domain )
{
char * keystr ;
keystr = talloc_asprintf_strupper_m ( talloc_tos ( ) , " %s/%s " ,
SECRETS_DOMAIN_SID , domain ) ;
SMB_ASSERT ( keystr ! = NULL ) ;
return keystr ;
}
2017-05-22 13:10:45 +03:00
static const char * domain_guid_keystr ( const char * domain )
{
char * keystr ;
keystr = talloc_asprintf_strupper_m ( talloc_tos ( ) , " %s/%s " ,
SECRETS_DOMAIN_GUID , domain ) ;
SMB_ASSERT ( keystr ! = NULL ) ;
return keystr ;
}
2012-01-27 00:27:54 +04:00
static const char * protect_ids_keystr ( const char * domain )
{
char * keystr ;
keystr = talloc_asprintf_strupper_m ( talloc_tos ( ) , " %s/%s " ,
SECRETS_PROTECT_IDS , domain ) ;
SMB_ASSERT ( keystr ! = NULL ) ;
return keystr ;
}
/* N O T E: never use this outside of passdb modules that store the SID on their own */
bool secrets_mark_domain_protected ( const char * domain )
{
bool ret ;
ret = secrets_store ( protect_ids_keystr ( domain ) , " TRUE " , 5 ) ;
if ( ! ret ) {
DEBUG ( 0 , ( " Failed to protect the Domain IDs \n " ) ) ;
}
return ret ;
}
bool secrets_clear_domain_protection ( const char * domain )
{
bool ret ;
2012-08-14 16:58:19 +04:00
void * protection = secrets_fetch ( protect_ids_keystr ( domain ) , NULL ) ;
if ( protection ) {
SAFE_FREE ( protection ) ;
2017-06-20 14:07:15 +03:00
ret = secrets_delete_entry ( protect_ids_keystr ( domain ) ) ;
2012-08-14 16:58:19 +04:00
if ( ! ret ) {
DEBUG ( 0 , ( " Failed to remove Domain IDs protection \n " ) ) ;
}
return ret ;
2012-01-27 00:27:54 +04:00
}
2012-08-14 16:58:19 +04:00
return true ;
2012-01-27 00:27:54 +04:00
}
2010-05-17 07:39:42 +04:00
bool secrets_store_domain_sid ( const char * domain , const struct dom_sid * sid )
{
2012-01-27 00:27:54 +04:00
char * protect_ids ;
2010-05-17 07:39:42 +04:00
bool ret ;
2018-10-04 10:25:14 +03:00
struct dom_sid clean_sid = { 0 } ;
2010-05-17 07:39:42 +04:00
2012-01-27 00:27:54 +04:00
protect_ids = secrets_fetch ( protect_ids_keystr ( domain ) , NULL ) ;
if ( protect_ids ) {
if ( strncmp ( protect_ids , " TRUE " , 4 ) ) {
DEBUG ( 0 , ( " Refusing to store a Domain SID, "
" it has been marked as protected! \n " ) ) ;
2012-09-05 21:56:06 +04:00
SAFE_FREE ( protect_ids ) ;
2012-01-27 00:27:54 +04:00
return false ;
}
2011-05-08 14:52:06 +04:00
}
2012-09-05 21:56:06 +04:00
SAFE_FREE ( protect_ids ) ;
2011-05-08 14:52:06 +04:00
2018-10-04 10:25:14 +03:00
/*
* use a copy to prevent uninitialized memory from being carried over
* to the tdb
*/
sid_copy ( & clean_sid , sid ) ;
ret = secrets_store ( domain_sid_keystr ( domain ) ,
& clean_sid ,
sizeof ( struct dom_sid ) ) ;
2010-05-17 07:39:42 +04:00
2014-05-13 09:47:03 +04:00
/* Force a re-query, in the case where we modified our domain */
if ( ret ) {
if ( dom_sid_equal ( get_global_sam_sid ( ) , sid ) = = false ) {
reset_global_sam_sid ( ) ;
}
}
2010-05-17 07:39:42 +04:00
return ret ;
}
bool secrets_fetch_domain_sid ( const char * domain , struct dom_sid * sid )
{
struct dom_sid * dyn_sid ;
size_t size = 0 ;
dyn_sid = ( struct dom_sid * ) secrets_fetch ( domain_sid_keystr ( domain ) , & size ) ;
if ( dyn_sid = = NULL )
return False ;
if ( size ! = sizeof ( struct dom_sid ) ) {
SAFE_FREE ( dyn_sid ) ;
return False ;
}
* sid = * dyn_sid ;
SAFE_FREE ( dyn_sid ) ;
return True ;
}
2017-06-21 20:38:15 +03:00
bool secrets_store_domain_guid ( const char * domain , const struct GUID * guid )
2010-05-17 07:39:42 +04:00
{
2012-01-27 00:27:54 +04:00
char * protect_ids ;
2017-05-22 13:10:45 +03:00
const char * key ;
2010-05-17 07:39:42 +04:00
2012-01-27 00:27:54 +04:00
protect_ids = secrets_fetch ( protect_ids_keystr ( domain ) , NULL ) ;
if ( protect_ids ) {
if ( strncmp ( protect_ids , " TRUE " , 4 ) ) {
DEBUG ( 0 , ( " Refusing to store a Domain SID, "
" it has been marked as protected! \n " ) ) ;
2012-09-07 04:32:11 +04:00
SAFE_FREE ( protect_ids ) ;
2012-01-27 00:27:54 +04:00
return false ;
}
2011-05-08 14:52:06 +04:00
}
2012-09-07 04:32:11 +04:00
SAFE_FREE ( protect_ids ) ;
2011-05-08 14:52:06 +04:00
2017-05-22 13:10:45 +03:00
key = domain_guid_keystr ( domain ) ;
2010-05-17 07:39:42 +04:00
return secrets_store ( key , guid , sizeof ( struct GUID ) ) ;
}
bool secrets_fetch_domain_guid ( const char * domain , struct GUID * guid )
{
struct GUID * dyn_guid ;
2017-05-22 13:10:45 +03:00
const char * key ;
2010-05-17 07:39:42 +04:00
size_t size = 0 ;
struct GUID new_guid ;
2017-05-22 13:10:45 +03:00
key = domain_guid_keystr ( domain ) ;
2010-05-17 07:39:42 +04:00
dyn_guid = ( struct GUID * ) secrets_fetch ( key , & size ) ;
if ( ! dyn_guid ) {
2020-11-11 19:50:45 +03:00
if ( lp_server_role ( ) = = ROLE_DOMAIN_PDC | |
lp_server_role ( ) = = ROLE_IPA_DC ) {
2010-05-17 07:39:42 +04:00
new_guid = GUID_random ( ) ;
if ( ! secrets_store_domain_guid ( domain , & new_guid ) )
return False ;
dyn_guid = ( struct GUID * ) secrets_fetch ( key , & size ) ;
}
if ( dyn_guid = = NULL ) {
return False ;
}
}
if ( size ! = sizeof ( struct GUID ) ) {
DEBUG ( 1 , ( " UUID size %d is wrong! \n " , ( int ) size ) ) ;
SAFE_FREE ( dyn_guid ) ;
return False ;
}
* guid = * dyn_guid ;
SAFE_FREE ( dyn_guid ) ;
return True ;
}
/**
* Form a key for fetching the machine trust account sec channel type
*
* @ param domain domain name
*
* @ return keystring
* */
static const char * machine_sec_channel_type_keystr ( const char * domain )
{
char * keystr ;
keystr = talloc_asprintf_strupper_m ( talloc_tos ( ) , " %s/%s " ,
SECRETS_MACHINE_SEC_CHANNEL_TYPE ,
domain ) ;
SMB_ASSERT ( keystr ! = NULL ) ;
return keystr ;
}
/**
* Form a key for fetching the machine trust account last change time
*
* @ param domain domain name
*
* @ return keystring
* */
static const char * machine_last_change_time_keystr ( const char * domain )
{
char * keystr ;
keystr = talloc_asprintf_strupper_m ( talloc_tos ( ) , " %s/%s " ,
SECRETS_MACHINE_LAST_CHANGE_TIME ,
domain ) ;
SMB_ASSERT ( keystr ! = NULL ) ;
return keystr ;
}
2010-05-21 11:57:29 +04:00
/**
* Form a key for fetching the machine previous trust account password
*
* @ param domain domain name
*
* @ return keystring
* */
static const char * machine_prev_password_keystr ( const char * domain )
{
char * keystr ;
keystr = talloc_asprintf_strupper_m ( talloc_tos ( ) , " %s/%s " ,
SECRETS_MACHINE_PASSWORD_PREV , domain ) ;
SMB_ASSERT ( keystr ! = NULL ) ;
return keystr ;
}
2010-05-17 07:39:42 +04:00
/**
* Form a key for fetching the machine trust account password
*
* @ param domain domain name
*
* @ return keystring
* */
static const char * machine_password_keystr ( const char * domain )
{
char * keystr ;
keystr = talloc_asprintf_strupper_m ( talloc_tos ( ) , " %s/%s " ,
SECRETS_MACHINE_PASSWORD , domain ) ;
SMB_ASSERT ( keystr ! = NULL ) ;
return keystr ;
}
/**
* Form a key for fetching the machine trust account password
*
* @ param domain domain name
*
* @ return stored password ' s key
* */
static const char * trust_keystr ( const char * domain )
{
char * keystr ;
keystr = talloc_asprintf_strupper_m ( talloc_tos ( ) , " %s/%s " ,
SECRETS_MACHINE_ACCT_PASS , domain ) ;
SMB_ASSERT ( keystr ! = NULL ) ;
return keystr ;
}
/************************************************************************
Routine to get the default secure channel type for trust accounts
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
enum netr_SchannelType get_default_sec_channel ( void )
{
2020-11-11 19:50:45 +03:00
if ( IS_DC ) {
2010-05-17 07:39:42 +04:00
return SEC_CHAN_BDC ;
} else {
return SEC_CHAN_WKSTA ;
}
}
/************************************************************************
Routine to get the trust account password for a domain .
This only tries to get the legacy hashed version of the password .
The user of this function must have locked the trust password file using
the above secrets_lock_trust_account_password ( ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool secrets_fetch_trust_account_password_legacy ( const char * domain ,
2012-07-14 16:18:29 +04:00
uint8_t ret_pwd [ 16 ] ,
2010-05-17 07:39:42 +04:00
time_t * pass_last_set_time ,
enum netr_SchannelType * channel )
{
struct machine_acct_pass * pass ;
size_t size = 0 ;
if ( ! ( pass = ( struct machine_acct_pass * ) secrets_fetch (
trust_keystr ( domain ) , & size ) ) ) {
DEBUG ( 5 , ( " secrets_fetch failed! \n " ) ) ;
return False ;
}
if ( size ! = sizeof ( * pass ) ) {
DEBUG ( 0 , ( " secrets were of incorrect size! \n " ) ) ;
SAFE_FREE ( pass ) ;
return False ;
}
if ( pass_last_set_time ) {
* pass_last_set_time = pass - > mod_time ;
}
memcpy ( ret_pwd , pass - > hash , 16 ) ;
if ( channel ) {
* channel = get_default_sec_channel ( ) ;
}
SAFE_FREE ( pass ) ;
return True ;
}
/************************************************************************
Routine to get the trust account password for a domain .
The user of this function must have locked the trust password file using
the above secrets_lock_trust_account_password ( ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-07-14 16:18:29 +04:00
bool secrets_fetch_trust_account_password ( const char * domain , uint8_t ret_pwd [ 16 ] ,
2010-05-17 07:39:42 +04:00
time_t * pass_last_set_time ,
enum netr_SchannelType * channel )
{
char * plaintext ;
plaintext = secrets_fetch_machine_password ( domain , pass_last_set_time ,
channel ) ;
if ( plaintext ) {
DEBUG ( 4 , ( " Using cleartext machine password \n " ) ) ;
E_md4hash ( plaintext , ret_pwd ) ;
SAFE_FREE ( plaintext ) ;
return True ;
}
return secrets_fetch_trust_account_password_legacy ( domain , ret_pwd ,
pass_last_set_time ,
channel ) ;
}
/************************************************************************
2017-05-22 13:40:05 +03:00
Routine to delete all information related to the domain joined machine .
2010-05-17 07:39:42 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-05-22 13:44:31 +03:00
bool secrets_delete_machine_password_ex ( const char * domain , const char * realm )
2010-05-17 07:39:42 +04:00
{
2017-05-22 13:31:01 +03:00
const char * tmpkey = NULL ;
bool ok ;
2017-05-19 17:28:17 +03:00
tmpkey = domain_info_keystr ( domain ) ;
ok = secrets_delete ( tmpkey ) ;
if ( ! ok ) {
return false ;
}
2017-05-22 13:44:31 +03:00
if ( realm ! = NULL ) {
tmpkey = des_salt_key ( domain ) ;
ok = secrets_delete ( tmpkey ) ;
if ( ! ok ) {
return false ;
}
}
2017-05-22 13:40:05 +03:00
tmpkey = domain_guid_keystr ( domain ) ;
ok = secrets_delete ( tmpkey ) ;
if ( ! ok ) {
return false ;
}
2017-05-22 13:31:01 +03:00
tmpkey = machine_prev_password_keystr ( domain ) ;
ok = secrets_delete ( tmpkey ) ;
if ( ! ok ) {
return false ;
}
tmpkey = machine_password_keystr ( domain ) ;
2017-05-24 06:56:32 +03:00
ok = secrets_delete ( tmpkey ) ;
2017-05-22 13:31:01 +03:00
if ( ! ok ) {
2010-05-21 11:57:29 +04:00
return false ;
}
2017-05-22 13:31:01 +03:00
tmpkey = machine_sec_channel_type_keystr ( domain ) ;
2017-05-24 06:56:32 +03:00
ok = secrets_delete ( tmpkey ) ;
2017-05-22 13:31:01 +03:00
if ( ! ok ) {
2010-05-17 07:39:42 +04:00
return false ;
}
2017-05-22 13:31:01 +03:00
tmpkey = machine_last_change_time_keystr ( domain ) ;
2017-05-24 06:56:32 +03:00
ok = secrets_delete ( tmpkey ) ;
2017-05-22 13:31:01 +03:00
if ( ! ok ) {
2010-05-17 07:39:42 +04:00
return false ;
}
2017-05-22 13:31:01 +03:00
2017-05-22 13:40:05 +03:00
tmpkey = domain_sid_keystr ( domain ) ;
2017-05-24 06:56:32 +03:00
ok = secrets_delete ( tmpkey ) ;
2017-05-22 13:40:05 +03:00
if ( ! ok ) {
return false ;
}
2017-05-22 13:31:01 +03:00
return true ;
2010-05-17 07:39:42 +04:00
}
/************************************************************************
Routine to delete the domain sid
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool secrets_delete_domain_sid ( const char * domain )
{
2017-06-20 14:07:15 +03:00
return secrets_delete_entry ( domain_sid_keystr ( domain ) ) ;
2010-05-17 07:39:42 +04:00
}
2012-08-27 13:28:22 +04:00
/************************************************************************
Set the machine trust account password , the old pw and last change
time , domain SID and salting principals based on values passed in
( added to supprt the secrets_tdb_sync module on secrets . ldb )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool secrets_store_machine_pw_sync ( const char * pass , const char * oldpass , const char * domain ,
const char * realm ,
const char * salting_principal , uint32_t supported_enc_types ,
const struct dom_sid * domain_sid , uint32_t last_change_time ,
2014-05-26 03:58:38 +04:00
uint32_t secure_channel_type ,
2012-08-27 13:28:22 +04:00
bool delete_join )
{
bool ret ;
uint8_t last_change_time_store [ 4 ] ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2014-05-26 03:58:38 +04:00
uint8_t sec_channel_bytes [ 4 ] ;
2012-08-27 13:28:22 +04:00
if ( delete_join ) {
2017-05-22 13:44:31 +03:00
secrets_delete_machine_password_ex ( domain , realm ) ;
2012-08-27 13:28:22 +04:00
TALLOC_FREE ( frame ) ;
return true ;
}
ret = secrets_store ( machine_password_keystr ( domain ) , pass , strlen ( pass ) + 1 ) ;
if ( ! ret ) {
TALLOC_FREE ( frame ) ;
return ret ;
}
if ( oldpass ) {
ret = secrets_store ( machine_prev_password_keystr ( domain ) , oldpass , strlen ( oldpass ) + 1 ) ;
} else {
2017-05-22 13:21:37 +03:00
ret = secrets_delete ( machine_prev_password_keystr ( domain ) ) ;
2012-08-27 13:28:22 +04:00
}
if ( ! ret ) {
TALLOC_FREE ( frame ) ;
return ret ;
}
2014-05-26 03:58:38 +04:00
if ( secure_channel_type = = 0 ) {
/* We delete this and instead have the read code fall back to
* a default based on server role , as our caller can ' t specify
* this with any more certainty */
2017-05-22 13:21:37 +03:00
ret = secrets_delete ( machine_sec_channel_type_keystr ( domain ) ) ;
if ( ! ret ) {
TALLOC_FREE ( frame ) ;
return ret ;
2014-05-26 03:58:38 +04:00
}
} else {
SIVAL ( & sec_channel_bytes , 0 , secure_channel_type ) ;
ret = secrets_store ( machine_sec_channel_type_keystr ( domain ) ,
& sec_channel_bytes , sizeof ( sec_channel_bytes ) ) ;
2012-08-27 13:28:22 +04:00
if ( ! ret ) {
TALLOC_FREE ( frame ) ;
return ret ;
}
}
SIVAL ( & last_change_time_store , 0 , last_change_time ) ;
ret = secrets_store ( machine_last_change_time_keystr ( domain ) ,
& last_change_time_store , sizeof ( last_change_time ) ) ;
if ( ! ret ) {
TALLOC_FREE ( frame ) ;
return ret ;
}
ret = secrets_store_domain_sid ( domain , domain_sid ) ;
if ( ! ret ) {
TALLOC_FREE ( frame ) ;
return ret ;
}
2017-05-22 13:27:45 +03:00
if ( realm ! = NULL ) {
2017-05-22 13:18:33 +03:00
char * key = des_salt_key ( realm ) ;
2017-05-22 13:27:45 +03:00
if ( salting_principal ! = NULL ) {
ret = secrets_store ( key ,
salting_principal ,
strlen ( salting_principal ) + 1 ) ;
} else {
ret = secrets_delete ( key ) ;
}
2012-08-27 13:28:22 +04:00
}
TALLOC_FREE ( frame ) ;
return ret ;
}
2017-05-19 18:17:00 +03:00
/************************************************************************
Return the standard DES salt key
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * kerberos_standard_des_salt ( void )
{
fstring salt ;
fstr_sprintf ( salt , " host/%s.%s@ " , lp_netbios_name ( ) , lp_realm ( ) ) ;
( void ) strlower_m ( salt ) ;
fstrcat ( salt , lp_realm ( ) ) ;
return SMB_STRDUP ( salt ) ;
}
/************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-05-22 12:38:12 +03:00
static char * des_salt_key ( const char * realm )
2017-05-19 18:17:00 +03:00
{
2017-05-22 12:38:12 +03:00
char * keystr ;
2017-05-19 18:17:00 +03:00
2017-05-22 12:38:12 +03:00
keystr = talloc_asprintf_strupper_m ( talloc_tos ( ) , " %s/DES/%s " ,
SECRETS_SALTING_PRINCIPAL ,
realm ) ;
SMB_ASSERT ( keystr ! = NULL ) ;
return keystr ;
2017-05-19 18:17:00 +03:00
}
/************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool kerberos_secrets_store_des_salt ( const char * salt )
{
char * key ;
bool ret ;
2017-05-22 12:38:12 +03:00
key = des_salt_key ( lp_realm ( ) ) ;
if ( key = = NULL ) {
2017-05-19 18:17:00 +03:00
DEBUG ( 0 , ( " kerberos_secrets_store_des_salt: failed to generate key! \n " ) ) ;
return False ;
}
if ( ! salt ) {
DEBUG ( 8 , ( " kerberos_secrets_store_des_salt: deleting salt \n " ) ) ;
2017-06-20 14:07:15 +03:00
secrets_delete_entry ( key ) ;
2017-05-19 18:17:00 +03:00
return True ;
}
DEBUG ( 3 , ( " kerberos_secrets_store_des_salt: Storing salt \" %s \" \n " , salt ) ) ;
ret = secrets_store ( key , salt , strlen ( salt ) + 1 ) ;
2017-05-22 12:38:12 +03:00
TALLOC_FREE ( key ) ;
2017-05-19 18:17:00 +03:00
return ret ;
}
/************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static
char * kerberos_secrets_fetch_des_salt ( void )
{
char * salt , * key ;
2017-05-22 12:38:12 +03:00
key = des_salt_key ( lp_realm ( ) ) ;
if ( key = = NULL ) {
2017-05-19 18:17:00 +03:00
DEBUG ( 0 , ( " kerberos_secrets_fetch_des_salt: failed to generate key! \n " ) ) ;
return NULL ;
}
salt = ( char * ) secrets_fetch ( key , NULL ) ;
2017-05-22 12:38:12 +03:00
TALLOC_FREE ( key ) ;
2017-05-19 18:17:00 +03:00
return salt ;
}
/************************************************************************
Routine to get the salting principal for this service .
Caller must free if return is not null .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * kerberos_secrets_fetch_salt_princ ( void )
{
char * salt_princ_s ;
/* lookup new key first */
salt_princ_s = kerberos_secrets_fetch_des_salt ( ) ;
if ( salt_princ_s = = NULL ) {
/* fall back to host/machine.realm@REALM */
salt_princ_s = kerberos_standard_des_salt ( ) ;
}
return salt_princ_s ;
}
2010-05-21 11:57:29 +04:00
/************************************************************************
Routine to fetch the previous plaintext machine account password for a realm
the password is assumed to be a null terminated ascii string .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * secrets_fetch_prev_machine_password ( const char * domain )
{
return ( char * ) secrets_fetch ( machine_prev_password_keystr ( domain ) , NULL ) ;
}
2015-07-31 01:47:54 +03:00
/************************************************************************
Routine to fetch the last change time of the machine account password
for a realm
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
time_t secrets_fetch_pass_last_set_time ( const char * domain )
{
uint32_t * last_set_time ;
time_t pass_last_set_time ;
last_set_time = secrets_fetch ( machine_last_change_time_keystr ( domain ) ,
NULL ) ;
if ( last_set_time ) {
pass_last_set_time = IVAL ( last_set_time , 0 ) ;
SAFE_FREE ( last_set_time ) ;
} else {
pass_last_set_time = 0 ;
}
return pass_last_set_time ;
}
2010-05-17 07:39:42 +04:00
/************************************************************************
Routine to fetch the plaintext machine account password for a realm
the password is assumed to be a null terminated ascii string .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * secrets_fetch_machine_password ( const char * domain ,
time_t * pass_last_set_time ,
enum netr_SchannelType * channel )
{
char * ret ;
ret = ( char * ) secrets_fetch ( machine_password_keystr ( domain ) , NULL ) ;
if ( pass_last_set_time ) {
2015-07-31 01:47:54 +03:00
* pass_last_set_time = secrets_fetch_pass_last_set_time ( domain ) ;
2010-05-17 07:39:42 +04:00
}
if ( channel ) {
size_t size ;
2012-07-14 16:18:29 +04:00
uint32_t * channel_type ;
2010-05-17 07:39:42 +04:00
channel_type = ( unsigned int * ) secrets_fetch ( machine_sec_channel_type_keystr ( domain ) , & size ) ;
if ( channel_type ) {
* channel = IVAL ( channel_type , 0 ) ;
SAFE_FREE ( channel_type ) ;
} else {
* channel = get_default_sec_channel ( ) ;
}
}
return ret ;
}
2017-05-19 17:28:17 +03:00
static char * domain_info_keystr ( const char * domain )
{
char * keystr ;
keystr = talloc_asprintf_strupper_m ( talloc_tos ( ) , " %s/%s " ,
SECRETS_MACHINE_DOMAIN_INFO ,
domain ) ;
SMB_ASSERT ( keystr ! = NULL ) ;
return keystr ;
}
/************************************************************************
Routine to get account password to trusted domain
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS secrets_fetch_domain_info1_by_key ( const char * key ,
TALLOC_CTX * mem_ctx ,
struct secrets_domain_info1 * * _info1 )
{
struct secrets_domain_infoB sdib = { . version = 0 , } ;
enum ndr_err_code ndr_err ;
/* unpacking structures */
DATA_BLOB blob ;
/* fetching trusted domain password structure */
blob . data = ( uint8_t * ) secrets_fetch ( key , & blob . length ) ;
if ( blob . data = = NULL ) {
DBG_NOTICE ( " secrets_fetch failed! \n " ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
/* unpack trusted domain password */
ndr_err = ndr_pull_struct_blob ( & blob , mem_ctx , & sdib ,
( ndr_pull_flags_fn_t ) ndr_pull_secrets_domain_infoB ) ;
SAFE_FREE ( blob . data ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DBG_ERR ( " ndr_pull_struct_blob failed - %s! \n " ,
ndr_errstr ( ndr_err ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
if ( sdib . version ! = SECRETS_DOMAIN_INFO_VERSION_1 ) {
DBG_ERR ( " sdib.version = %u \n " , ( unsigned ) sdib . version ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
* _info1 = sdib . info . info1 ;
return NT_STATUS_OK ; ;
}
static NTSTATUS secrets_fetch_domain_info ( const char * domain ,
TALLOC_CTX * mem_ctx ,
struct secrets_domain_info1 * * pinfo )
{
char * key = domain_info_keystr ( domain ) ;
return secrets_fetch_domain_info1_by_key ( key , mem_ctx , pinfo ) ;
}
void secrets_debug_domain_info ( int lvl , const struct secrets_domain_info1 * info1 ,
const char * name )
{
struct secrets_domain_infoB sdib = {
. version = SECRETS_DOMAIN_INFO_VERSION_1 ,
} ;
sdib . info . info1 = discard_const_p ( struct secrets_domain_info1 , info1 ) ;
ndr_print_debug ( ( ndr_print_fn_t ) ndr_print_secrets_domain_infoB ,
name , & sdib ) ;
}
char * secrets_domain_info_string ( TALLOC_CTX * mem_ctx , const struct secrets_domain_info1 * info1 ,
const char * name , bool include_secrets )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct secrets_domain_infoB sdib = {
. version = SECRETS_DOMAIN_INFO_VERSION_1 ,
} ;
struct ndr_print * ndr = NULL ;
char * ret = NULL ;
sdib . info . info1 = discard_const_p ( struct secrets_domain_info1 , info1 ) ;
ndr = talloc_zero ( frame , struct ndr_print ) ;
if ( ndr = = NULL ) {
TALLOC_FREE ( frame ) ;
return NULL ;
}
ndr - > private_data = talloc_strdup ( ndr , " " ) ;
if ( ndr - > private_data = = NULL ) {
TALLOC_FREE ( frame ) ;
return NULL ;
}
ndr - > print = ndr_print_string_helper ;
ndr - > depth = 1 ;
ndr - > print_secrets = include_secrets ;
ndr_print_secrets_domain_infoB ( ndr , name , & sdib ) ;
ret = talloc_steal ( mem_ctx , ( char * ) ndr - > private_data ) ;
TALLOC_FREE ( frame ) ;
return ret ;
}
static NTSTATUS secrets_store_domain_info1_by_key ( const char * key ,
const struct secrets_domain_info1 * info1 )
{
struct secrets_domain_infoB sdib = {
. version = SECRETS_DOMAIN_INFO_VERSION_1 ,
} ;
/* packing structures */
DATA_BLOB blob ;
enum ndr_err_code ndr_err ;
bool ok ;
sdib . info . info1 = discard_const_p ( struct secrets_domain_info1 , info1 ) ;
ndr_err = ndr_push_struct_blob ( & blob , talloc_tos ( ) , & sdib ,
( ndr_push_flags_fn_t ) ndr_push_secrets_domain_infoB ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
ok = secrets_store ( key , blob . data , blob . length ) ;
data_blob_clear_free ( & blob ) ;
if ( ! ok ) {
return NT_STATUS_INTERNAL_DB_ERROR ;
}
return NT_STATUS_OK ;
}
2017-08-17 22:42:34 +03:00
static NTSTATUS secrets_store_domain_info ( const struct secrets_domain_info1 * info ,
bool upgrade )
2017-05-19 17:28:17 +03:00
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
const char * domain = info - > domain_info . name . string ;
const char * realm = info - > domain_info . dns_domain . string ;
char * key = domain_info_keystr ( domain ) ;
struct db_context * db = NULL ;
struct timeval last_change_tv ;
const DATA_BLOB * cleartext_blob = NULL ;
DATA_BLOB pw_blob = data_blob_null ;
DATA_BLOB old_pw_blob = data_blob_null ;
const char * pw = NULL ;
const char * old_pw = NULL ;
bool ok ;
NTSTATUS status ;
int ret ;
int role = lp_server_role ( ) ;
switch ( info - > secure_channel_type ) {
case SEC_CHAN_WKSTA :
case SEC_CHAN_BDC :
2017-08-17 22:42:34 +03:00
if ( ! upgrade & & role > = ROLE_ACTIVE_DIRECTORY_DC ) {
2017-05-19 17:28:17 +03:00
DBG_ERR ( " AD_DC not supported for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
break ;
default :
DBG_ERR ( " SEC_CHAN_* not supported for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
db = secrets_db_ctx ( ) ;
ret = dbwrap_transaction_start ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_start() failed for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
ok = secrets_clear_domain_protection ( domain ) ;
if ( ! ok ) {
DBG_ERR ( " secrets_clear_domain_protection(%s) failed \n " ,
domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
ok = secrets_delete_machine_password_ex ( domain , realm ) ;
if ( ! ok ) {
DBG_ERR ( " secrets_delete_machine_password_ex(%s) failed \n " ,
domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
status = secrets_store_domain_info1_by_key ( key , info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_store_domain_info1_by_key() failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
/*
* We use info - > password_last_change instead
* of info - > password . change_time because
* we may want to defer the next change approach
* if the server rejected the change the last time ,
* e . g . due to RefusePasswordChange = 1.
*/
nttime_to_timeval ( & last_change_tv , info - > password_last_change ) ;
cleartext_blob = & info - > password - > cleartext_blob ;
ok = convert_string_talloc ( frame , CH_UTF16MUNGED , CH_UNIX ,
cleartext_blob - > data ,
cleartext_blob - > length ,
( void * * ) & pw_blob . data ,
& pw_blob . length ) ;
if ( ! ok ) {
status = NT_STATUS_UNMAPPABLE_CHARACTER ;
if ( errno = = ENOMEM ) {
status = NT_STATUS_NO_MEMORY ;
}
DBG_ERR ( " convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
" failed for pw of %s - %s \n " ,
domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
pw = ( const char * ) pw_blob . data ;
if ( info - > old_password ! = NULL ) {
cleartext_blob = & info - > old_password - > cleartext_blob ;
ok = convert_string_talloc ( frame , CH_UTF16MUNGED , CH_UNIX ,
cleartext_blob - > data ,
cleartext_blob - > length ,
( void * * ) & old_pw_blob . data ,
& old_pw_blob . length ) ;
if ( ! ok ) {
status = NT_STATUS_UNMAPPABLE_CHARACTER ;
if ( errno = = ENOMEM ) {
status = NT_STATUS_NO_MEMORY ;
}
DBG_ERR ( " convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
" failed for old_pw of %s - %s \n " ,
domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
data_blob_clear_free ( & pw_blob ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
old_pw = ( const char * ) old_pw_blob . data ;
}
ok = secrets_store_machine_pw_sync ( pw , old_pw ,
domain , realm ,
info - > salt_principal ,
info - > supported_enc_types ,
info - > domain_info . sid ,
last_change_tv . tv_sec ,
info - > secure_channel_type ,
false ) ; /* delete_join */
data_blob_clear_free ( & pw_blob ) ;
data_blob_clear_free ( & old_pw_blob ) ;
if ( ! ok ) {
DBG_ERR ( " secrets_store_machine_pw_sync(%s) failed \n " ,
domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
if ( ! GUID_all_zero ( & info - > domain_info . domain_guid ) ) {
ok = secrets_store_domain_guid ( domain ,
& info - > domain_info . domain_guid ) ;
if ( ! ok ) {
DBG_ERR ( " secrets_store_domain_guid(%s) failed \n " ,
domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
}
ok = secrets_mark_domain_protected ( domain ) ;
if ( ! ok ) {
DBG_ERR ( " secrets_mark_domain_protected(%s) failed \n " ,
domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
ret = dbwrap_transaction_commit ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_commit() failed for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
}
static int secrets_domain_info_kerberos_keys ( struct secrets_domain_info1_password * p ,
const char * salt_principal )
{
# ifdef HAVE_ADS
krb5_error_code krb5_ret ;
krb5_context krb5_ctx = NULL ;
DATA_BLOB cleartext_utf8_b = data_blob_null ;
krb5_data cleartext_utf8 ;
krb5_data salt ;
krb5_keyblock key ;
DATA_BLOB aes_256_b = data_blob_null ;
DATA_BLOB aes_128_b = data_blob_null ;
bool ok ;
# endif /* HAVE_ADS */
DATA_BLOB arc4_b = data_blob_null ;
const uint16_t max_keys = 4 ;
struct secrets_domain_info1_kerberos_key * keys = NULL ;
uint16_t idx = 0 ;
char * salt_data = NULL ;
/*
* We calculate :
* ENCTYPE_AES256_CTS_HMAC_SHA1_96
* ENCTYPE_AES128_CTS_HMAC_SHA1_96
* ENCTYPE_ARCFOUR_HMAC
* ENCTYPE_DES_CBC_MD5
*
* We don ' t include ENCTYPE_DES_CBC_CRC
* as W2008R2 also doesn ' t store it anymore .
*
* Note we store all enctypes we support ,
* including the weak encryption types ,
* but that ' s no problem as we also
* store the cleartext password anyway .
*
* Which values are then used to construct
* a keytab is configured at runtime and the
* configuration of msDS - SupportedEncryptionTypes .
*
* If we don ' t have kerberos support or no
* salt , we only generate an entry for arcfour - hmac - md5 .
*/
keys = talloc_zero_array ( p ,
struct secrets_domain_info1_kerberos_key ,
max_keys ) ;
if ( keys = = NULL ) {
return ENOMEM ;
}
arc4_b = data_blob_talloc ( keys ,
p - > nt_hash . hash ,
sizeof ( p - > nt_hash . hash ) ) ;
if ( arc4_b . data = = NULL ) {
DBG_ERR ( " data_blob_talloc failed for arcfour-hmac-md5. \n " ) ;
TALLOC_FREE ( keys ) ;
return ENOMEM ;
}
# ifdef HAVE_ADS
if ( salt_principal = = NULL ) {
goto no_kerberos ;
}
2018-12-05 13:41:47 +03:00
krb5_ret = smb_krb5_init_context_common ( & krb5_ctx ) ;
2017-05-19 17:28:17 +03:00
if ( krb5_ret ! = 0 ) {
2018-12-05 13:41:47 +03:00
DBG_ERR ( " kerberos init context failed (%s) \n " ,
error_message ( krb5_ret ) ) ;
2017-05-19 17:28:17 +03:00
TALLOC_FREE ( keys ) ;
return krb5_ret ;
}
krb5_ret = smb_krb5_salt_principal2data ( krb5_ctx , salt_principal ,
p , & salt_data ) ;
if ( krb5_ret ! = 0 ) {
DBG_ERR ( " smb_krb5_salt_principal2data(%s) failed: %s \n " ,
salt_principal ,
smb_get_krb5_error_message ( krb5_ctx , krb5_ret , keys ) ) ;
krb5_free_context ( krb5_ctx ) ;
TALLOC_FREE ( keys ) ;
return krb5_ret ;
}
2017-10-25 20:50:57 +03:00
salt = ( krb5_data ) {
. data = discard_const ( salt_data ) ,
. length = strlen ( salt_data ) ,
} ;
2017-05-19 17:28:17 +03:00
ok = convert_string_talloc ( keys , CH_UTF16MUNGED , CH_UTF8 ,
p - > cleartext_blob . data ,
p - > cleartext_blob . length ,
( void * * ) & cleartext_utf8_b . data ,
& cleartext_utf8_b . length ) ;
if ( ! ok ) {
if ( errno ! = 0 ) {
krb5_ret = errno ;
} else {
krb5_ret = EINVAL ;
}
krb5_free_context ( krb5_ctx ) ;
TALLOC_FREE ( keys ) ;
return krb5_ret ;
}
cleartext_utf8 . data = ( void * ) cleartext_utf8_b . data ;
cleartext_utf8 . length = cleartext_utf8_b . length ;
krb5_ret = smb_krb5_create_key_from_string ( krb5_ctx ,
NULL ,
& salt ,
& cleartext_utf8 ,
ENCTYPE_AES256_CTS_HMAC_SHA1_96 ,
& key ) ;
if ( krb5_ret ! = 0 ) {
DBG_ERR ( " generation of a aes256-cts-hmac-sha1-96 key failed: %s \n " ,
smb_get_krb5_error_message ( krb5_ctx , krb5_ret , keys ) ) ;
krb5_free_context ( krb5_ctx ) ;
TALLOC_FREE ( keys ) ;
TALLOC_FREE ( salt_data ) ;
return krb5_ret ;
}
aes_256_b = data_blob_talloc ( keys ,
KRB5_KEY_DATA ( & key ) ,
KRB5_KEY_LENGTH ( & key ) ) ;
krb5_free_keyblock_contents ( krb5_ctx , & key ) ;
if ( aes_256_b . data = = NULL ) {
DBG_ERR ( " data_blob_talloc failed for aes-256. \n " ) ;
krb5_free_context ( krb5_ctx ) ;
TALLOC_FREE ( keys ) ;
TALLOC_FREE ( salt_data ) ;
return ENOMEM ;
}
krb5_ret = smb_krb5_create_key_from_string ( krb5_ctx ,
NULL ,
& salt ,
& cleartext_utf8 ,
ENCTYPE_AES128_CTS_HMAC_SHA1_96 ,
& key ) ;
if ( krb5_ret ! = 0 ) {
DBG_ERR ( " generation of a aes128-cts-hmac-sha1-96 key failed: %s \n " ,
smb_get_krb5_error_message ( krb5_ctx , krb5_ret , keys ) ) ;
krb5_free_context ( krb5_ctx ) ;
TALLOC_FREE ( keys ) ;
TALLOC_FREE ( salt_data ) ;
return krb5_ret ;
}
aes_128_b = data_blob_talloc ( keys ,
KRB5_KEY_DATA ( & key ) ,
KRB5_KEY_LENGTH ( & key ) ) ;
krb5_free_keyblock_contents ( krb5_ctx , & key ) ;
if ( aes_128_b . data = = NULL ) {
DBG_ERR ( " data_blob_talloc failed for aes-128. \n " ) ;
krb5_free_context ( krb5_ctx ) ;
TALLOC_FREE ( keys ) ;
TALLOC_FREE ( salt_data ) ;
return ENOMEM ;
}
krb5_free_context ( krb5_ctx ) ;
no_kerberos :
if ( aes_256_b . length ! = 0 ) {
keys [ idx ] . keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96 ;
keys [ idx ] . iteration_count = 4096 ;
keys [ idx ] . value = aes_256_b ;
idx + = 1 ;
}
if ( aes_128_b . length ! = 0 ) {
keys [ idx ] . keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96 ;
keys [ idx ] . iteration_count = 4096 ;
keys [ idx ] . value = aes_128_b ;
idx + = 1 ;
}
# endif /* HAVE_ADS */
keys [ idx ] . keytype = ENCTYPE_ARCFOUR_HMAC ;
keys [ idx ] . iteration_count = 4096 ;
keys [ idx ] . value = arc4_b ;
idx + = 1 ;
p - > salt_data = salt_data ;
p - > default_iteration_count = 4096 ;
p - > num_keys = idx ;
p - > keys = keys ;
return 0 ;
}
static NTSTATUS secrets_domain_info_password_create ( TALLOC_CTX * mem_ctx ,
const char * cleartext_unix ,
const char * salt_principal ,
NTTIME change_time ,
const char * change_server ,
struct secrets_domain_info1_password * * _p )
{
struct secrets_domain_info1_password * p = NULL ;
bool ok ;
size_t len ;
int ret ;
if ( change_server = = NULL ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
p = talloc_zero ( mem_ctx , struct secrets_domain_info1_password ) ;
if ( p = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
p - > change_time = change_time ;
p - > change_server = talloc_strdup ( p , change_server ) ;
if ( p - > change_server = = NULL ) {
TALLOC_FREE ( p ) ;
return NT_STATUS_NO_MEMORY ;
}
len = strlen ( cleartext_unix ) ;
ok = convert_string_talloc ( p , CH_UNIX , CH_UTF16 ,
cleartext_unix , len ,
( void * * ) & p - > cleartext_blob . data ,
& p - > cleartext_blob . length ) ;
if ( ! ok ) {
NTSTATUS status = NT_STATUS_UNMAPPABLE_CHARACTER ;
if ( errno = = ENOMEM ) {
status = NT_STATUS_NO_MEMORY ;
}
TALLOC_FREE ( p ) ;
return status ;
}
mdfour ( p - > nt_hash . hash ,
p - > cleartext_blob . data ,
p - > cleartext_blob . length ) ;
ret = secrets_domain_info_kerberos_keys ( p , salt_principal ) ;
if ( ret ! = 0 ) {
NTSTATUS status = krb5_to_nt_status ( ret ) ;
TALLOC_FREE ( p ) ;
return status ;
}
* _p = p ;
return NT_STATUS_OK ;
}
NTSTATUS secrets_fetch_or_upgrade_domain_info ( const char * domain ,
TALLOC_CTX * mem_ctx ,
struct secrets_domain_info1 * * pinfo )
{
TALLOC_CTX * frame = NULL ;
struct secrets_domain_info1 * old = NULL ;
struct secrets_domain_info1 * info = NULL ;
const char * dns_domain = NULL ;
const char * server = NULL ;
struct db_context * db = NULL ;
time_t last_set_time ;
NTTIME last_set_nt ;
enum netr_SchannelType channel ;
char * pw = NULL ;
char * old_pw = NULL ;
struct dom_sid domain_sid ;
struct GUID domain_guid ;
bool ok ;
NTSTATUS status ;
int ret ;
ok = strequal ( domain , lp_workgroup ( ) ) ;
if ( ok ) {
dns_domain = lp_dnsdomain ( ) ;
if ( dns_domain ! = NULL & & dns_domain [ 0 ] = = ' \0 ' ) {
dns_domain = NULL ;
}
}
last_set_time = secrets_fetch_pass_last_set_time ( domain ) ;
if ( last_set_time = = 0 ) {
2018-04-17 09:55:23 +03:00
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
2017-05-19 17:28:17 +03:00
}
unix_to_nt_time ( & last_set_nt , last_set_time ) ;
frame = talloc_stackframe ( ) ;
status = secrets_fetch_domain_info ( domain , frame , & old ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
if ( old - > password_last_change > = last_set_nt ) {
* pinfo = talloc_move ( mem_ctx , & old ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
}
TALLOC_FREE ( old ) ;
}
info = talloc_zero ( frame , struct secrets_domain_info1 ) ;
if ( info = = NULL ) {
DBG_ERR ( " talloc_zero failed \n " ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
db = secrets_db_ctx ( ) ;
ret = dbwrap_transaction_start ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_start() failed for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
pw = secrets_fetch_machine_password ( domain ,
& last_set_time ,
& channel ) ;
if ( pw = = NULL ) {
DBG_ERR ( " secrets_fetch_machine_password(%s) failed \n " ,
domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
unix_to_nt_time ( & last_set_nt , last_set_time ) ;
old_pw = secrets_fetch_prev_machine_password ( domain ) ;
ok = secrets_fetch_domain_sid ( domain , & domain_sid ) ;
if ( ! ok ) {
DBG_ERR ( " secrets_fetch_domain_sid(%s) failed \n " ,
domain ) ;
dbwrap_transaction_cancel ( db ) ;
2017-10-25 20:30:28 +03:00
SAFE_FREE ( old_pw ) ;
SAFE_FREE ( pw ) ;
2017-05-19 17:28:17 +03:00
TALLOC_FREE ( frame ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
ok = secrets_fetch_domain_guid ( domain , & domain_guid ) ;
if ( ! ok ) {
domain_guid = GUID_zero ( ) ;
}
info - > computer_name = lp_netbios_name ( ) ;
info - > account_name = talloc_asprintf ( frame , " %s$ " , info - > computer_name ) ;
if ( info - > account_name = = NULL ) {
DBG_ERR ( " talloc_asprintf(%s$) failed \n " , info - > computer_name ) ;
dbwrap_transaction_cancel ( db ) ;
2017-10-25 20:30:28 +03:00
SAFE_FREE ( old_pw ) ;
SAFE_FREE ( pw ) ;
2017-05-19 17:28:17 +03:00
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
info - > secure_channel_type = channel ;
info - > domain_info . name . string = domain ;
info - > domain_info . dns_domain . string = dns_domain ;
info - > domain_info . dns_forest . string = dns_domain ;
info - > domain_info . domain_guid = domain_guid ;
info - > domain_info . sid = & domain_sid ;
info - > trust_flags = NETR_TRUST_FLAG_PRIMARY ;
info - > trust_flags | = NETR_TRUST_FLAG_OUTBOUND ;
if ( dns_domain ! = NULL ) {
/*
* We just assume all AD domains are
* NETR_TRUST_FLAG_NATIVE these days .
*
* This isn ' t used anyway for now .
*/
info - > trust_flags | = NETR_TRUST_FLAG_NATIVE ;
info - > trust_type = LSA_TRUST_TYPE_UPLEVEL ;
server = info - > domain_info . dns_domain . string ;
} else {
info - > trust_type = LSA_TRUST_TYPE_DOWNLEVEL ;
server = talloc_asprintf ( info ,
" %s#%02X " ,
domain ,
NBT_NAME_PDC ) ;
if ( server = = NULL ) {
DBG_ERR ( " talloc_asprintf(%s#%02X) failed \n " ,
domain , NBT_NAME_PDC ) ;
dbwrap_transaction_cancel ( db ) ;
2017-10-25 20:30:28 +03:00
SAFE_FREE ( pw ) ;
SAFE_FREE ( old_pw ) ;
2017-05-19 17:28:17 +03:00
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
}
info - > trust_attributes = LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL ;
info - > join_time = 0 ;
/*
* We don ' t have enough information about the configured
* enctypes .
*/
info - > supported_enc_types = 0 ;
info - > salt_principal = NULL ;
if ( info - > trust_type = = LSA_TRUST_TYPE_UPLEVEL ) {
char * p = NULL ;
p = kerberos_secrets_fetch_salt_princ ( ) ;
if ( p = = NULL ) {
dbwrap_transaction_cancel ( db ) ;
2017-10-25 20:30:28 +03:00
SAFE_FREE ( old_pw ) ;
SAFE_FREE ( pw ) ;
2017-05-19 17:28:17 +03:00
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
info - > salt_principal = talloc_strdup ( info , p ) ;
SAFE_FREE ( p ) ;
if ( info - > salt_principal = = NULL ) {
dbwrap_transaction_cancel ( db ) ;
2017-10-25 20:30:28 +03:00
SAFE_FREE ( pw ) ;
SAFE_FREE ( old_pw ) ;
2017-05-19 17:28:17 +03:00
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
}
info - > password_last_change = last_set_nt ;
info - > password_changes = 1 ;
info - > next_change = NULL ;
status = secrets_domain_info_password_create ( info ,
pw ,
info - > salt_principal ,
last_set_nt , server ,
& info - > password ) ;
2017-10-25 20:30:28 +03:00
SAFE_FREE ( pw ) ;
2017-05-19 17:28:17 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_domain_info_password_create(pw) failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
2017-11-02 23:49:43 +03:00
SAFE_FREE ( old_pw ) ;
2017-05-19 17:28:17 +03:00
TALLOC_FREE ( frame ) ;
return status ;
}
/*
* After a join we don ' t have old passwords .
*/
if ( old_pw ! = NULL ) {
status = secrets_domain_info_password_create ( info ,
old_pw ,
info - > salt_principal ,
0 , server ,
& info - > old_password ) ;
2017-10-25 20:30:28 +03:00
SAFE_FREE ( old_pw ) ;
2017-05-19 17:28:17 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_domain_info_password_create(old) failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
info - > password_changes + = 1 ;
} else {
info - > old_password = NULL ;
}
info - > older_password = NULL ;
secrets_debug_domain_info ( DBGLVL_INFO , info , " upgrade " ) ;
2017-08-17 22:42:34 +03:00
status = secrets_store_domain_info ( info , true /* upgrade */ ) ;
2017-05-19 17:28:17 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_store_domain_info() failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
/*
* We now reparse it .
*/
status = secrets_fetch_domain_info ( domain , frame , & info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_fetch_domain_info() failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
ret = dbwrap_transaction_commit ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_commit() failed for %s \n " ,
domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
* pinfo = talloc_move ( mem_ctx , & info ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
}
NTSTATUS secrets_store_JoinCtx ( const struct libnet_JoinCtx * r )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct secrets_domain_info1 * old = NULL ;
struct secrets_domain_info1 * info = NULL ;
struct db_context * db = NULL ;
struct timeval tv = timeval_current ( ) ;
NTTIME now = timeval_to_nttime ( & tv ) ;
const char * domain = r - > out . netbios_domain_name ;
NTSTATUS status ;
int ret ;
info = talloc_zero ( frame , struct secrets_domain_info1 ) ;
if ( info = = NULL ) {
DBG_ERR ( " talloc_zero failed \n " ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
info - > computer_name = r - > in . machine_name ;
info - > account_name = r - > out . account_name ;
info - > secure_channel_type = r - > in . secure_channel_type ;
info - > domain_info . name . string =
r - > out . netbios_domain_name ;
info - > domain_info . dns_domain . string =
r - > out . dns_domain_name ;
info - > domain_info . dns_forest . string =
r - > out . forest_name ;
info - > domain_info . domain_guid = r - > out . domain_guid ;
info - > domain_info . sid = r - > out . domain_sid ;
info - > trust_flags = NETR_TRUST_FLAG_PRIMARY ;
info - > trust_flags | = NETR_TRUST_FLAG_OUTBOUND ;
if ( r - > out . domain_is_ad ) {
/*
* We just assume all AD domains are
* NETR_TRUST_FLAG_NATIVE these days .
*
* This isn ' t used anyway for now .
*/
info - > trust_flags | = NETR_TRUST_FLAG_NATIVE ;
info - > trust_type = LSA_TRUST_TYPE_UPLEVEL ;
} else {
info - > trust_type = LSA_TRUST_TYPE_DOWNLEVEL ;
}
info - > trust_attributes = LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL ;
info - > join_time = now ;
info - > supported_enc_types = r - > out . set_encryption_types ;
info - > salt_principal = r - > out . krb5_salt ;
if ( info - > salt_principal = = NULL & & r - > out . domain_is_ad ) {
char * p = NULL ;
2021-10-19 06:01:36 +03:00
ret = smb_krb5_salt_principal_str ( info - > domain_info . dns_domain . string ,
info - > account_name ,
NULL /* userPrincipalName */ ,
UF_WORKSTATION_TRUST_ACCOUNT ,
info , & p ) ;
2017-05-19 17:28:17 +03:00
if ( ret ! = 0 ) {
status = krb5_to_nt_status ( ret ) ;
DBG_ERR ( " smb_krb5_salt_principal() failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
info - > salt_principal = p ;
}
info - > password_last_change = now ;
info - > password_changes = 1 ;
info - > next_change = NULL ;
status = secrets_domain_info_password_create ( info ,
r - > in . machine_password ,
info - > salt_principal ,
now , r - > in . dc_name ,
& info - > password ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_domain_info_password_create(pw) failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
db = secrets_db_ctx ( ) ;
ret = dbwrap_transaction_start ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_start() failed for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
status = secrets_fetch_or_upgrade_domain_info ( domain , frame , & old ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_CANT_ACCESS_DOMAIN_INFO ) ) {
DBG_DEBUG ( " no old join for domain(%s) available \n " ,
domain ) ;
old = NULL ;
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_fetch_or_upgrade_domain_info(%s) failed \n " ,
domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
/*
* We reuse values from an old join , so that
* we still accept already granted kerberos tickets .
*/
if ( old ! = NULL ) {
info - > old_password = old - > password ;
info - > older_password = old - > old_password ;
}
secrets_debug_domain_info ( DBGLVL_INFO , info , " join " ) ;
2017-08-17 22:42:34 +03:00
status = secrets_store_domain_info ( info , false /* upgrade */ ) ;
2017-05-19 17:28:17 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_store_domain_info() failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
ret = dbwrap_transaction_commit ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_commit() failed for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
}
NTSTATUS secrets_prepare_password_change ( const char * domain , const char * dcname ,
const char * cleartext_unix ,
TALLOC_CTX * mem_ctx ,
struct secrets_domain_info1 * * pinfo ,
struct secrets_domain_info1_change * * pprev )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct db_context * db = NULL ;
struct secrets_domain_info1 * info = NULL ;
struct secrets_domain_info1_change * prev = NULL ;
struct secrets_domain_info1_change * next = NULL ;
struct timeval tv = timeval_current ( ) ;
NTTIME now = timeval_to_nttime ( & tv ) ;
NTSTATUS status ;
int ret ;
db = secrets_db_ctx ( ) ;
ret = dbwrap_transaction_start ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_start() failed for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
status = secrets_fetch_or_upgrade_domain_info ( domain , frame , & info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_fetch_or_upgrade_domain_info(%s) failed \n " ,
domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
prev = info - > next_change ;
info - > next_change = NULL ;
next = talloc_zero ( frame , struct secrets_domain_info1_change ) ;
if ( next = = NULL ) {
DBG_ERR ( " talloc_zero failed \n " ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
if ( prev ! = NULL ) {
* next = * prev ;
} else {
status = secrets_domain_info_password_create ( next ,
cleartext_unix ,
info - > salt_principal ,
now , dcname ,
& next - > password ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_domain_info_password_create(next) failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
}
next - > local_status = NT_STATUS_OK ;
next - > remote_status = NT_STATUS_NOT_COMMITTED ;
next - > change_time = now ;
next - > change_server = dcname ;
info - > next_change = next ;
secrets_debug_domain_info ( DBGLVL_INFO , info , " prepare_change " ) ;
2017-08-17 22:42:34 +03:00
status = secrets_store_domain_info ( info , false /* upgrade */ ) ;
2017-05-19 17:28:17 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_store_domain_info() failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
/*
* We now reparse it .
*/
status = secrets_fetch_domain_info ( domain , frame , & info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_fetch_domain_info(%s) failed \n " , domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
ret = dbwrap_transaction_commit ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_commit() failed for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
* pinfo = talloc_move ( mem_ctx , & info ) ;
if ( prev ! = NULL ) {
* pprev = talloc_move ( mem_ctx , & prev ) ;
} else {
* pprev = NULL ;
}
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
}
static NTSTATUS secrets_check_password_change ( const struct secrets_domain_info1 * cookie ,
TALLOC_CTX * mem_ctx ,
struct secrets_domain_info1 * * pstored )
{
const char * domain = cookie - > domain_info . name . string ;
struct secrets_domain_info1 * stored = NULL ;
struct secrets_domain_info1_change * sn = NULL ;
struct secrets_domain_info1_change * cn = NULL ;
NTSTATUS status ;
int cmp ;
if ( cookie - > next_change = = NULL ) {
DBG_ERR ( " cookie->next_change == NULL for %s. \n " , domain ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
if ( cookie - > next_change - > password = = NULL ) {
DBG_ERR ( " cookie->next_change->password == NULL for %s. \n " , domain ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
if ( cookie - > password = = NULL ) {
DBG_ERR ( " cookie->password == NULL for %s. \n " , domain ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
/*
* Here we check that the given strucure still contains the
* same secrets_domain_info1_change as currently stored .
*
* There ' s always a gap between secrets_prepare_password_change ( )
* and the callers of secrets_check_password_change ( ) .
*/
status = secrets_fetch_domain_info ( domain , mem_ctx , & stored ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_fetch_domain_info(%s) failed \n " , domain ) ;
return status ;
}
if ( stored - > next_change = = NULL ) {
/*
* We hit a race . . . , the administrator
* rejoined or something similar happened .
*/
DBG_ERR ( " stored->next_change == NULL for %s. \n " , domain ) ;
TALLOC_FREE ( stored ) ;
return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT ;
}
if ( stored - > password_last_change ! = cookie - > password_last_change ) {
struct timeval store_tv ;
struct timeval_buf store_buf ;
struct timeval cookie_tv ;
struct timeval_buf cookie_buf ;
nttime_to_timeval ( & store_tv , stored - > password_last_change ) ;
nttime_to_timeval ( & cookie_tv , cookie - > password_last_change ) ;
DBG_ERR ( " password_last_change differs %s != %s for %s. \n " ,
timeval_str_buf ( & store_tv , false , false , & store_buf ) ,
timeval_str_buf ( & cookie_tv , false , false , & cookie_buf ) ,
domain ) ;
TALLOC_FREE ( stored ) ;
return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT ;
}
sn = stored - > next_change ;
cn = cookie - > next_change ;
if ( sn - > change_time ! = cn - > change_time ) {
struct timeval store_tv ;
struct timeval_buf store_buf ;
struct timeval cookie_tv ;
struct timeval_buf cookie_buf ;
nttime_to_timeval ( & store_tv , sn - > change_time ) ;
nttime_to_timeval ( & cookie_tv , cn - > change_time ) ;
DBG_ERR ( " next change_time differs %s != %s for %s. \n " ,
timeval_str_buf ( & store_tv , false , false , & store_buf ) ,
timeval_str_buf ( & cookie_tv , false , false , & cookie_buf ) ,
domain ) ;
TALLOC_FREE ( stored ) ;
return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT ;
}
if ( sn - > password - > change_time ! = cn - > password - > change_time ) {
struct timeval store_tv ;
struct timeval_buf store_buf ;
struct timeval cookie_tv ;
struct timeval_buf cookie_buf ;
nttime_to_timeval ( & store_tv , sn - > password - > change_time ) ;
nttime_to_timeval ( & cookie_tv , cn - > password - > change_time ) ;
DBG_ERR ( " next password.change_time differs %s != %s for %s. \n " ,
timeval_str_buf ( & store_tv , false , false , & store_buf ) ,
timeval_str_buf ( & cookie_tv , false , false , & cookie_buf ) ,
domain ) ;
TALLOC_FREE ( stored ) ;
return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT ;
}
cmp = memcmp ( sn - > password - > nt_hash . hash ,
cn - > password - > nt_hash . hash ,
16 ) ;
if ( cmp ! = 0 ) {
DBG_ERR ( " next password.nt_hash differs for %s. \n " ,
domain ) ;
TALLOC_FREE ( stored ) ;
return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT ;
}
cmp = memcmp ( stored - > password - > nt_hash . hash ,
cookie - > password - > nt_hash . hash ,
16 ) ;
if ( cmp ! = 0 ) {
DBG_ERR ( " password.nt_hash differs for %s. \n " ,
domain ) ;
TALLOC_FREE ( stored ) ;
return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT ;
}
* pstored = stored ;
return NT_STATUS_OK ;
}
static NTSTATUS secrets_abort_password_change ( const char * change_server ,
NTSTATUS local_status ,
NTSTATUS remote_status ,
const struct secrets_domain_info1 * cookie ,
bool defer )
{
const char * domain = cookie - > domain_info . name . string ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct db_context * db = NULL ;
struct secrets_domain_info1 * info = NULL ;
const char * reason = defer ? " defer_change " : " failed_change " ;
struct timeval tv = timeval_current ( ) ;
NTTIME now = timeval_to_nttime ( & tv ) ;
NTSTATUS status ;
int ret ;
db = secrets_db_ctx ( ) ;
ret = dbwrap_transaction_start ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_start() failed for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
/*
* secrets_check_password_change ( )
* checks that cookie - > next_change
* is valid and the same as store
* in the database .
*/
status = secrets_check_password_change ( cookie , frame , & info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_check_password_change(%s) failed \n " , domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
/*
* Remember the last server and error .
*/
info - > next_change - > change_server = change_server ;
info - > next_change - > change_time = now ;
info - > next_change - > local_status = local_status ;
info - > next_change - > remote_status = remote_status ;
/*
* Make sure the next automatic change is deferred .
*/
if ( defer ) {
info - > password_last_change = now ;
}
secrets_debug_domain_info ( DBGLVL_WARNING , info , reason ) ;
2017-08-17 22:42:34 +03:00
status = secrets_store_domain_info ( info , false /* upgrade */ ) ;
2017-05-19 17:28:17 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_store_domain_info() failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
ret = dbwrap_transaction_commit ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_commit() failed for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
}
NTSTATUS secrets_failed_password_change ( const char * change_server ,
NTSTATUS local_status ,
NTSTATUS remote_status ,
const struct secrets_domain_info1 * cookie )
{
static const bool defer = false ;
return secrets_abort_password_change ( change_server ,
local_status ,
remote_status ,
cookie , defer ) ;
}
NTSTATUS secrets_defer_password_change ( const char * change_server ,
NTSTATUS local_status ,
NTSTATUS remote_status ,
const struct secrets_domain_info1 * cookie )
{
static const bool defer = true ;
return secrets_abort_password_change ( change_server ,
local_status ,
remote_status ,
cookie , defer ) ;
}
NTSTATUS secrets_finish_password_change ( const char * change_server ,
NTTIME change_time ,
const struct secrets_domain_info1 * cookie )
{
const char * domain = cookie - > domain_info . name . string ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct db_context * db = NULL ;
struct secrets_domain_info1 * info = NULL ;
struct secrets_domain_info1_change * nc = NULL ;
NTSTATUS status ;
int ret ;
db = secrets_db_ctx ( ) ;
ret = dbwrap_transaction_start ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_start() failed for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
/*
* secrets_check_password_change ( ) checks that cookie - > next_change is
* valid and the same as store in the database .
*/
status = secrets_check_password_change ( cookie , frame , & info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_check_password_change(%s) failed \n " , domain ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
nc = info - > next_change ;
nc - > password - > change_server = change_server ;
nc - > password - > change_time = change_time ;
info - > password_last_change = change_time ;
info - > password_changes + = 1 ;
info - > next_change = NULL ;
info - > older_password = info - > old_password ;
info - > old_password = info - > password ;
info - > password = nc - > password ;
secrets_debug_domain_info ( DBGLVL_WARNING , info , " finish_change " ) ;
2017-08-17 22:42:34 +03:00
status = secrets_store_domain_info ( info , false /* upgrade */ ) ;
2017-05-19 17:28:17 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " secrets_store_domain_info() failed "
" for %s - %s \n " , domain , nt_errstr ( status ) ) ;
dbwrap_transaction_cancel ( db ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
ret = dbwrap_transaction_commit ( db ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " dbwrap_transaction_commit() failed for %s \n " ,
domain ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
}