2001-12-20 10:46:24 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-12-20 10:46:24 +03:00
krb5 set password implementation
Copyright ( C ) Remus Koos 2001 ( remuskoos @ yahoo . com )
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2001-12-20 10:46:24 +03:00
( 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2001-12-20 10:46:24 +03:00
*/
# include "includes.h"
2010-07-02 02:32:52 +04:00
# include "ads.h"
2010-08-05 04:25:37 +04:00
# include "secrets.h"
2017-05-23 18:41:34 +03:00
# include "librpc/gen_ndr/ndr_secrets.h"
2001-12-20 10:46:24 +03:00
# ifdef HAVE_KRB5
ADS_STATUS ads_change_trust_account_password ( ADS_STRUCT * ads , char * host_principal )
{
2017-05-23 18:41:34 +03:00
const char * password = NULL ;
const char * new_password = NULL ;
2004-11-02 05:21:26 +03:00
ADS_STATUS ret ;
2017-05-23 18:41:34 +03:00
const char * domain = lp_workgroup ( ) ;
struct secrets_domain_info1 * info = NULL ;
struct secrets_domain_info1_change * prev = NULL ;
const DATA_BLOB * cleartext_blob = NULL ;
DATA_BLOB pw_blob = data_blob_null ;
DATA_BLOB new_pw_blob = data_blob_null ;
NTSTATUS status ;
struct timeval tv = timeval_current ( ) ;
NTTIME now = timeval_to_nttime ( & tv ) ;
int role = lp_server_role ( ) ;
bool ok ;
if ( role ! = ROLE_DOMAIN_MEMBER ) {
DBG_ERR ( " Machine account password change only supported on a DOMAIN_MEMBER. \n " ) ;
return ADS_ERROR_NT ( NT_STATUS_INVALID_SERVER_STATE ) ;
2004-11-02 05:21:26 +03:00
}
2001-12-20 10:46:24 +03:00
2016-08-23 11:38:58 +03:00
new_password = trust_pw_new_value ( talloc_tos ( ) , SEC_CHAN_WKSTA , SEC_ADS ) ;
if ( new_password = = NULL ) {
ret = ADS_ERROR_SYSTEM ( errno ) ;
DEBUG ( 1 , ( " Failed to generate machine password \n " ) ) ;
2017-05-23 18:41:34 +03:00
return ret ;
}
status = secrets_prepare_password_change ( domain ,
ads - > auth . kdc_server ,
new_password ,
talloc_tos ( ) ,
& info , & prev ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ADS_ERROR_NT ( status ) ;
}
if ( prev ! = NULL ) {
status = NT_STATUS_REQUEST_NOT_ACCEPTED ;
secrets_failed_password_change ( " localhost " ,
status ,
NT_STATUS_NOT_COMMITTED ,
info ) ;
return ADS_ERROR_NT ( status ) ;
}
cleartext_blob = & info - > password - > cleartext_blob ;
ok = convert_string_talloc ( talloc_tos ( ) , 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 password of %s - %s \n " ,
domain , nt_errstr ( status ) ) ;
return ADS_ERROR_NT ( status ) ;
}
password = ( const char * ) pw_blob . data ;
cleartext_blob = & info - > next_change - > password - > cleartext_blob ;
ok = convert_string_talloc ( talloc_tos ( ) , CH_UTF16MUNGED , CH_UNIX ,
cleartext_blob - > data ,
cleartext_blob - > length ,
( void * * ) & new_pw_blob . data ,
& new_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 new_password of %s - %s \n " ,
domain , nt_errstr ( status ) ) ;
secrets_failed_password_change ( " localhost " ,
status ,
NT_STATUS_NOT_COMMITTED ,
info ) ;
return ADS_ERROR_NT ( status ) ;
2016-08-23 11:38:58 +03:00
}
2017-05-23 18:41:34 +03:00
new_password = ( const char * ) new_pw_blob . data ;
2013-02-01 16:14:05 +04:00
2006-06-09 14:50:28 +04:00
ret = kerberos_set_password ( ads - > auth . kdc_server , host_principal , password , host_principal , new_password , ads - > auth . time_offset ) ;
2003-02-24 05:55:00 +03:00
2004-11-02 05:21:26 +03:00
if ( ! ADS_ERR_OK ( ret ) ) {
2017-05-23 18:41:34 +03:00
status = ads_ntstatus ( ret ) ;
DBG_ERR ( " kerberos_set_password(%s, %s) "
" failed for new_password of %s - %s \n " ,
ads - > auth . kdc_server , host_principal ,
domain , nt_errstr ( status ) ) ;
secrets_failed_password_change ( ads - > auth . kdc_server ,
NT_STATUS_NOT_COMMITTED ,
status ,
info ) ;
return ret ;
2004-11-02 05:21:26 +03:00
}
2001-12-20 10:46:24 +03:00
2017-05-23 18:41:34 +03:00
status = secrets_finish_password_change ( ads - > auth . kdc_server , now , info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-11-02 05:21:26 +03:00
DEBUG ( 1 , ( " Failed to save machine password \n " ) ) ;
2017-05-23 18:41:34 +03:00
return ADS_ERROR_NT ( status ) ;
2004-11-02 05:21:26 +03:00
}
2001-12-20 10:46:24 +03:00
2017-05-23 18:41:34 +03:00
return ADS_SUCCESS ;
2001-12-20 10:46:24 +03:00
}
# endif
2018-01-29 20:51:15 +03:00
/**
* @ brief Parses windows style SPN service / host : port / servicename
* serviceclass - A string that identifies the general class of service
* e . g . ' http '
* host - A netbios name or fully - qualified DNS name
* port - An optional TCP or UDP port number
* servicename - An optional distinguished name , GUID , DNS name or
* DNS name of an SRV or MX record . ( not needed for host
* based services )
*
* @ param [ in ] ctx - Talloc context .
* @ param [ in ] srvprinc - The service principal
*
* @ return - struct spn_struct containing the fields parsed or NULL
* if srvprinc could not be parsed .
*/
struct spn_struct * parse_spn ( TALLOC_CTX * ctx , const char * srvprinc )
{
struct spn_struct * result = NULL ;
char * tmp = NULL ;
char * port_str = NULL ;
char * host_str = NULL ;
result = talloc_zero ( ctx , struct spn_struct ) ;
if ( result = = NULL ) {
DBG_ERR ( " Out of memory \n " ) ;
return NULL ;
}
result - > serviceclass = talloc_strdup ( result , srvprinc ) ;
if ( result - > serviceclass = = NULL ) {
DBG_ERR ( " Out of memory \n " ) ;
2018-08-21 22:22:42 +03:00
goto fail ;
2018-01-29 20:51:15 +03:00
}
result - > port = - 1 ;
tmp = strchr_m ( result - > serviceclass , ' / ' ) ;
if ( tmp = = NULL ) {
/* illegal */
DBG_ERR ( " Failed to parse spn %s, no host definition \n " ,
srvprinc ) ;
2018-08-21 22:22:42 +03:00
goto fail ;
2018-01-29 20:51:15 +03:00
}
/* terminate service principal */
* tmp = ' \0 ' ;
tmp + + ;
host_str = tmp ;
tmp = strchr_m ( host_str , ' : ' ) ;
if ( tmp ! = NULL ) {
* tmp = ' \0 ' ;
tmp + + ;
port_str = tmp ;
} else {
tmp = host_str ;
}
tmp = strchr_m ( tmp , ' / ' ) ;
if ( tmp ! = NULL ) {
* tmp = ' \0 ' ;
tmp + + ;
result - > servicename = tmp ;
}
if ( strlen ( host_str ) = = 0 ) {
/* illegal */
DBG_ERR ( " Failed to parse spn %s, illegal host definition \n " ,
srvprinc ) ;
2018-08-21 22:22:42 +03:00
goto fail ;
2018-01-29 20:51:15 +03:00
}
result - > host = host_str ;
if ( result - > servicename ! = NULL & & ( strlen ( result - > servicename ) = = 0 ) ) {
DBG_ERR ( " Failed to parse spn %s, empty servicename "
" definition \n " , srvprinc ) ;
2018-08-21 22:22:42 +03:00
goto fail ;
2018-01-29 20:51:15 +03:00
}
if ( port_str ! = NULL ) {
if ( strlen ( port_str ) = = 0 ) {
DBG_ERR ( " Failed to parse spn %s, empty port "
" definition \n " , srvprinc ) ;
2018-08-21 22:22:42 +03:00
goto fail ;
2018-01-29 20:51:15 +03:00
}
result - > port = ( int32_t ) strtol ( port_str , NULL , 10 ) ;
if ( result - > port < = 0
| | result - > port > 65535
| | errno = = ERANGE ) {
DBG_ERR ( " Failed to parse spn %s, port number "
" convertion failed \n " , srvprinc ) ;
errno = 0 ;
2018-08-21 22:22:42 +03:00
goto fail ;
2018-01-29 20:51:15 +03:00
}
}
return result ;
2018-08-21 22:22:42 +03:00
fail :
TALLOC_FREE ( result ) ;
return NULL ;
2018-01-29 20:51:15 +03:00
}