2001-11-24 17:16:41 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-11-24 17:16:41 +03:00
kerberos utility library
Copyright ( C ) Andrew Tridgell 2001
2001-12-20 06:54:52 +03:00
Copyright ( C ) Remus Koos 2001
2005-01-14 22:26:13 +03:00
Copyright ( C ) Nalin Dahyabhai < nalin @ redhat . com > 2004.
2004-10-30 02:38:10 +04:00
Copyright ( C ) Jeremy Allison 2004.
2001-11-24 17:16:41 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# ifdef HAVE_KRB5
2004-10-30 02:38:10 +04:00
# define LIBADS_CCACHE_NAME "MEMORY:libads"
2002-07-15 14:35:28 +04:00
/*
we use a prompter to avoid a crash bug in the kerberos libs when
dealing with empty passwords
this prompter is just a string copy . . .
*/
static krb5_error_code
kerb_prompter ( krb5_context ctx , void * data ,
const char * name ,
const char * banner ,
int num_prompts ,
krb5_prompt prompts [ ] )
{
if ( num_prompts = = 0 ) return 0 ;
2004-10-30 02:38:10 +04:00
memset ( prompts [ 0 ] . reply - > data , ' \0 ' , prompts [ 0 ] . reply - > length ) ;
2002-07-15 14:35:28 +04:00
if ( prompts [ 0 ] . reply - > length > 0 ) {
2002-10-24 05:05:30 +04:00
if ( data ) {
strncpy ( prompts [ 0 ] . reply - > data , data , prompts [ 0 ] . reply - > length - 1 ) ;
prompts [ 0 ] . reply - > length = strlen ( prompts [ 0 ] . reply - > data ) ;
} else {
prompts [ 0 ] . reply - > length = 0 ;
}
2002-07-15 14:35:28 +04:00
}
return 0 ;
}
2001-12-06 08:41:53 +03:00
/*
2004-10-30 02:38:10 +04:00
simulate a kinit , putting the tgt in the given cache location . If cache_name = = NULL
place in default cache location .
2001-12-06 08:41:53 +03:00
remus @ snapserver . com
*/
2004-10-30 02:38:10 +04:00
int kerberos_kinit_password ( const char * principal ,
const char * password ,
int time_offset ,
time_t * expire_time ,
const char * cache_name )
2001-12-06 08:41:53 +03:00
{
2004-05-07 06:48:03 +04:00
krb5_context ctx = NULL ;
2001-12-06 08:41:53 +03:00
krb5_error_code code = 0 ;
2004-05-07 06:48:03 +04:00
krb5_ccache cc = NULL ;
2001-12-06 08:41:53 +03:00
krb5_principal me ;
krb5_creds my_creds ;
2001-12-13 14:30:13 +03:00
2001-12-06 08:41:53 +03:00
if ( ( code = krb5_init_context ( & ctx ) ) )
return code ;
2002-09-25 19:19:00 +04:00
if ( time_offset ! = 0 ) {
krb5_set_real_time ( ctx , time ( NULL ) + time_offset , 0 ) ;
}
2001-12-06 08:41:53 +03:00
2004-10-30 02:38:10 +04:00
if ( ( code = krb5_cc_resolve ( ctx , cache_name ?
cache_name : krb5_cc_default_name ( ctx ) , & cc ) ) ) {
2001-12-06 08:41:53 +03:00
krb5_free_context ( ctx ) ;
return code ;
}
if ( ( code = krb5_parse_name ( ctx , principal , & me ) ) ) {
krb5_free_context ( ctx ) ;
return code ;
}
2005-10-18 07:24:00 +04:00
if ( ( code = krb5_get_init_creds_password ( ctx , & my_creds , me , CONST_DISCARD ( char * , password ) ,
2002-07-15 14:35:28 +04:00
kerb_prompter ,
2004-06-25 00:37:54 +04:00
NULL , 0 , NULL , NULL ) ) ) {
2001-12-06 08:41:53 +03:00
krb5_free_principal ( ctx , me ) ;
krb5_free_context ( ctx ) ;
return code ;
}
if ( ( code = krb5_cc_initialize ( ctx , cc , me ) ) ) {
krb5_free_cred_contents ( ctx , & my_creds ) ;
krb5_free_principal ( ctx , me ) ;
krb5_free_context ( ctx ) ;
return code ;
}
if ( ( code = krb5_cc_store_cred ( ctx , cc , & my_creds ) ) ) {
krb5_cc_close ( ctx , cc ) ;
krb5_free_cred_contents ( ctx , & my_creds ) ;
krb5_free_principal ( ctx , me ) ;
krb5_free_context ( ctx ) ;
return code ;
}
2004-03-24 20:32:55 +03:00
if ( expire_time )
* expire_time = ( time_t ) my_creds . times . endtime ;
2001-12-06 08:41:53 +03:00
krb5_cc_close ( ctx , cc ) ;
krb5_free_cred_contents ( ctx , & my_creds ) ;
krb5_free_principal ( ctx , me ) ;
krb5_free_context ( ctx ) ;
return 0 ;
}
2001-12-05 12:46:53 +03:00
2001-12-06 08:41:53 +03:00
/* run kinit to setup our ccache */
int ads_kinit_password ( ADS_STRUCT * ads )
2001-12-05 12:46:53 +03:00
{
char * s ;
2001-12-06 08:41:53 +03:00
int ret ;
2001-12-06 10:33:35 +03:00
2002-10-01 17:10:57 +04:00
if ( asprintf ( & s , " %s@%s " , ads - > auth . user_name , ads - > auth . realm ) = = - 1 ) {
return KRB5_CC_NOMEM ;
}
if ( ! ads - > auth . password ) {
return KRB5_LIBOS_CANTREADPWD ;
}
2004-10-30 02:38:10 +04:00
ret = kerberos_kinit_password ( s , ads - > auth . password , ads - > auth . time_offset ,
& ads - > auth . expire , NULL ) ;
2001-12-11 08:15:52 +03:00
2001-12-06 08:41:53 +03:00
if ( ret ) {
2001-12-13 14:30:13 +03:00
DEBUG ( 0 , ( " kerberos_kinit_password %s failed: %s \n " ,
2001-12-08 14:18:56 +03:00
s , error_message ( ret ) ) ) ;
2001-12-06 08:41:53 +03:00
}
2001-12-09 03:45:51 +03:00
free ( s ) ;
2001-12-06 08:41:53 +03:00
return ret ;
2001-12-05 12:46:53 +03:00
}
2004-03-24 20:32:55 +03:00
int ads_kdestroy ( const char * cc_name )
{
krb5_error_code code ;
2004-05-07 06:48:03 +04:00
krb5_context ctx = NULL ;
krb5_ccache cc = NULL ;
2004-03-24 20:32:55 +03:00
if ( ( code = krb5_init_context ( & ctx ) ) ) {
2004-08-21 00:18:28 +04:00
DEBUG ( 3 , ( " ads_kdestroy: kdb5_init_context failed: %s \n " ,
error_message ( code ) ) ) ;
2004-03-24 20:32:55 +03:00
return code ;
}
if ( ! cc_name ) {
if ( ( code = krb5_cc_default ( ctx , & cc ) ) ) {
krb5_free_context ( ctx ) ;
return code ;
}
} else {
if ( ( code = krb5_cc_resolve ( ctx , cc_name , & cc ) ) ) {
2004-08-21 00:18:28 +04:00
DEBUG ( 3 , ( " ads_kdestroy: krb5_cc_resolve failed: %s \n " ,
error_message ( code ) ) ) ;
2004-03-24 20:32:55 +03:00
krb5_free_context ( ctx ) ;
return code ;
}
}
if ( ( code = krb5_cc_destroy ( ctx , cc ) ) ) {
2004-08-21 00:18:28 +04:00
DEBUG ( 3 , ( " ads_kdestroy: krb5_cc_destroy failed: %s \n " ,
error_message ( code ) ) ) ;
2004-03-24 20:32:55 +03:00
}
krb5_free_context ( ctx ) ;
return code ;
}
2001-11-24 17:16:41 +03:00
2004-10-30 02:38:10 +04:00
/************************************************************************
Routine to fetch the salting principal for a service . Active
Directory may use a non - obvious principal name to generate the salt
when it determines the key to use for encrypting tickets for a service ,
and hopefully we detected that when we joined the domain .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * kerberos_secrets_fetch_salting_principal ( const char * service , int enctype )
{
char * key = NULL ;
char * ret = NULL ;
asprintf ( & key , " %s/%s/enctype=%d " , SECRETS_SALTING_PRINCIPAL , service , enctype ) ;
if ( ! key ) {
return NULL ;
}
ret = ( char * ) secrets_fetch ( key , NULL ) ;
SAFE_FREE ( key ) ;
return ret ;
}
/************************************************************************
Routine to get the salting principal for this service . Active
Directory may use a non - obvious principal name to generate the salt
when it determines the key to use for encrypting tickets for a service ,
and hopefully we detected that when we joined the domain .
Caller must free if return is not null .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
krb5_principal kerberos_fetch_salt_princ_for_host_princ ( krb5_context context ,
krb5_principal host_princ ,
int enctype )
{
char * unparsed_name = NULL , * salt_princ_s = NULL ;
krb5_principal ret_princ = NULL ;
if ( krb5_unparse_name ( context , host_princ , & unparsed_name ) ! = 0 ) {
return ( krb5_principal ) NULL ;
}
if ( ( salt_princ_s = kerberos_secrets_fetch_salting_principal ( unparsed_name , enctype ) ) = = NULL ) {
krb5_free_unparsed_name ( context , unparsed_name ) ;
return ( krb5_principal ) NULL ;
}
if ( krb5_parse_name ( context , salt_princ_s , & ret_princ ) ! = 0 ) {
krb5_free_unparsed_name ( context , unparsed_name ) ;
SAFE_FREE ( salt_princ_s ) ;
return ( krb5_principal ) NULL ;
}
krb5_free_unparsed_name ( context , unparsed_name ) ;
SAFE_FREE ( salt_princ_s ) ;
return ret_princ ;
}
/************************************************************************
Routine to set the salting principal for this service . Active
Directory may use a non - obvious principal name to generate the salt
when it determines the key to use for encrypting tickets for a service ,
and hopefully we detected that when we joined the domain .
Setting principal to NULL deletes this entry .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-05-02 21:49:43 +04:00
BOOL kerberos_secrets_store_salting_principal ( const char * service ,
2004-10-30 02:38:10 +04:00
int enctype ,
const char * principal )
{
char * key = NULL ;
BOOL ret = False ;
krb5_context context = NULL ;
krb5_principal princ = NULL ;
char * princ_s = NULL ;
char * unparsed_name = NULL ;
krb5_init_context ( & context ) ;
if ( ! context ) {
return False ;
}
if ( strchr_m ( service , ' @ ' ) ) {
asprintf ( & princ_s , " %s " , service ) ;
} else {
asprintf ( & princ_s , " %s@%s " , service , lp_realm ( ) ) ;
}
if ( krb5_parse_name ( context , princ_s , & princ ) ! = 0 ) {
goto out ;
}
if ( krb5_unparse_name ( context , princ , & unparsed_name ) ! = 0 ) {
goto out ;
}
asprintf ( & key , " %s/%s/enctype=%d " , SECRETS_SALTING_PRINCIPAL , unparsed_name , enctype ) ;
if ( ! key ) {
goto out ;
}
if ( ( principal ! = NULL ) & & ( strlen ( principal ) > 0 ) ) {
ret = secrets_store ( key , principal , strlen ( principal ) + 1 ) ;
} else {
ret = secrets_delete ( key ) ;
}
out :
SAFE_FREE ( key ) ;
SAFE_FREE ( princ_s ) ;
if ( unparsed_name ) {
krb5_free_unparsed_name ( context , unparsed_name ) ;
}
if ( context ) {
krb5_free_context ( context ) ;
}
return ret ;
}
/************************************************************************
Routine to get initial credentials as a service ticket for the local machine .
Returns a buffer initialized with krb5_mk_req_extended .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static krb5_error_code get_service_ticket ( krb5_context ctx ,
krb5_ccache ccache ,
const char * service_principal ,
int enctype ,
krb5_data * p_outbuf )
{
krb5_creds creds , * new_creds = NULL ;
char * service_s = NULL ;
char * machine_account = NULL , * password = NULL ;
krb5_data in_data ;
krb5_auth_context auth_context = NULL ;
krb5_error_code err = 0 ;
2004-12-23 01:07:04 +03:00
ZERO_STRUCT ( creds ) ;
2004-10-30 02:38:10 +04:00
asprintf ( & machine_account , " %s$@%s " , global_myname ( ) , lp_realm ( ) ) ;
if ( machine_account = = NULL ) {
goto out ;
}
password = secrets_fetch_machine_password ( lp_workgroup ( ) , NULL , NULL ) ;
if ( password = = NULL ) {
goto out ;
}
if ( ( err = kerberos_kinit_password ( machine_account , password , 0 , NULL , LIBADS_CCACHE_NAME ) ) ! = 0 ) {
DEBUG ( 0 , ( " get_service_ticket: kerberos_kinit_password %s@%s failed: %s \n " ,
machine_account ,
lp_realm ( ) ,
error_message ( err ) ) ) ;
goto out ;
}
/* Ok - the above call has gotten a TGT. Now we need to get a service
ticket to ourselves . */
/* Set up the enctype and client and server principal fields for krb5_get_credentials. */
kerberos_set_creds_enctype ( & creds , enctype ) ;
if ( ( err = krb5_cc_get_principal ( ctx , ccache , & creds . client ) ) ) {
DEBUG ( 3 , ( " get_service_ticket: krb5_cc_get_principal failed: %s \n " ,
error_message ( err ) ) ) ;
goto out ;
}
if ( strchr_m ( service_principal , ' @ ' ) ) {
asprintf ( & service_s , " %s " , service_principal ) ;
} else {
asprintf ( & service_s , " %s@%s " , service_principal , lp_realm ( ) ) ;
}
if ( ( err = krb5_parse_name ( ctx , service_s , & creds . server ) ) ) {
DEBUG ( 0 , ( " get_service_ticket: krb5_parse_name %s failed: %s \n " ,
service_s , error_message ( err ) ) ) ;
goto out ;
}
if ( ( err = krb5_get_credentials ( ctx , 0 , ccache , & creds , & new_creds ) ) ) {
2004-11-03 00:28:14 +03:00
DEBUG ( 5 , ( " get_service_ticket: krb5_get_credentials for %s enctype %d failed: %s \n " ,
service_s , enctype , error_message ( err ) ) ) ;
2004-10-30 02:38:10 +04:00
goto out ;
}
memset ( & in_data , ' \0 ' , sizeof ( in_data ) ) ;
if ( ( err = krb5_mk_req_extended ( ctx , & auth_context , 0 , & in_data ,
new_creds , p_outbuf ) ) ! = 0 ) {
DEBUG ( 0 , ( " get_service_ticket: krb5_mk_req_extended failed: %s \n " ,
error_message ( err ) ) ) ;
goto out ;
}
out :
if ( auth_context ) {
krb5_auth_con_free ( ctx , auth_context ) ;
}
if ( new_creds ) {
krb5_free_creds ( ctx , new_creds ) ;
}
if ( creds . server ) {
krb5_free_principal ( ctx , creds . server ) ;
}
if ( creds . client ) {
krb5_free_principal ( ctx , creds . client ) ;
}
SAFE_FREE ( service_s ) ;
SAFE_FREE ( password ) ;
SAFE_FREE ( machine_account ) ;
return err ;
}
/************************************************************************
Check if the machine password can be used in conjunction with the salting_principal
to generate a key which will successfully decrypt the AP_REQ already
gotten as a message to the local machine .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL verify_service_password ( krb5_context ctx ,
int enctype ,
const char * salting_principal ,
krb5_data * in_data )
{
BOOL ret = False ;
krb5_principal salting_kprinc = NULL ;
krb5_ticket * ticket = NULL ;
krb5_keyblock key ;
krb5_data passdata ;
char * salting_s = NULL ;
char * machine_account = NULL , * password = NULL ;
krb5_auth_context auth_context = NULL ;
krb5_error_code err ;
memset ( & passdata , ' \0 ' , sizeof ( passdata ) ) ;
memset ( & key , ' \0 ' , sizeof ( key ) ) ;
asprintf ( & machine_account , " %s$@%s " , global_myname ( ) , lp_realm ( ) ) ;
if ( machine_account = = NULL ) {
goto out ;
}
password = secrets_fetch_machine_password ( lp_workgroup ( ) , NULL , NULL ) ;
if ( password = = NULL ) {
goto out ;
}
if ( strchr_m ( salting_principal , ' @ ' ) ) {
asprintf ( & salting_s , " %s " , salting_principal ) ;
} else {
asprintf ( & salting_s , " %s@%s " , salting_principal , lp_realm ( ) ) ;
}
if ( ( err = krb5_parse_name ( ctx , salting_s , & salting_kprinc ) ) ) {
DEBUG ( 0 , ( " verify_service_password: krb5_parse_name %s failed: %s \n " ,
salting_s , error_message ( err ) ) ) ;
goto out ;
}
passdata . length = strlen ( password ) ;
passdata . data = ( char * ) password ;
if ( ( err = create_kerberos_key_from_string_direct ( ctx , salting_kprinc , & passdata , & key , enctype ) ) ) {
DEBUG ( 0 , ( " verify_service_password: create_kerberos_key_from_string %d failed: %s \n " ,
enctype , error_message ( err ) ) ) ;
goto out ;
}
if ( ( err = krb5_auth_con_init ( ctx , & auth_context ) ) ! = 0 ) {
DEBUG ( 0 , ( " verify_service_password: krb5_auth_con_init failed %s \n " , error_message ( err ) ) ) ;
goto out ;
}
if ( ( err = krb5_auth_con_setuseruserkey ( ctx , auth_context , & key ) ) ! = 0 ) {
DEBUG ( 0 , ( " verify_service_password: krb5_auth_con_setuseruserkey failed %s \n " , error_message ( err ) ) ) ;
goto out ;
}
if ( ! ( err = krb5_rd_req ( ctx , & auth_context , in_data , NULL , NULL , NULL , & ticket ) ) ) {
DEBUG ( 10 , ( " verify_service_password: decrypted message with enctype %u salt %s! \n " ,
( unsigned int ) enctype , salting_s ) ) ;
ret = True ;
}
out :
memset ( & passdata , 0 , sizeof ( passdata ) ) ;
krb5_free_keyblock_contents ( ctx , & key ) ;
if ( ticket ! = NULL ) {
krb5_free_ticket ( ctx , ticket ) ;
}
if ( salting_kprinc ) {
krb5_free_principal ( ctx , salting_kprinc ) ;
}
SAFE_FREE ( salting_s ) ;
SAFE_FREE ( password ) ;
SAFE_FREE ( machine_account ) ;
return ret ;
}
/************************************************************************
*
* From the current draft of kerberos - clarifications :
*
* It is not possible to reliably generate a user ' s key given a pass
* phrase without contacting the KDC , since it will not be known
* whether alternate salt or parameter values are required .
*
* And because our server has a password , we have this exact problem . We
* make multiple guesses as to which principal name provides the salt which
* the KDC is using .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void kerberos_derive_salting_principal_for_enctype ( const char * service_principal ,
krb5_context ctx ,
krb5_ccache ccache ,
krb5_enctype enctype ,
krb5_enctype * enctypes )
{
char * salting_principals [ 3 ] = { NULL , NULL , NULL } , * second_principal = NULL ;
krb5_error_code err = 0 ;
krb5_data outbuf ;
int i , j ;
memset ( & outbuf , ' \0 ' , sizeof ( outbuf ) ) ;
/* Check that the service_principal is useful. */
if ( ( service_principal = = NULL ) | | ( strlen ( service_principal ) = = 0 ) ) {
return ;
}
/* Generate our first guess -- the principal as-given. */
asprintf ( & salting_principals [ 0 ] , " %s " , service_principal ) ;
if ( ( salting_principals [ 0 ] = = NULL ) | | ( strlen ( salting_principals [ 0 ] ) = = 0 ) ) {
return ;
}
/* Generate our second guess -- the computer's principal, as Win2k3. */
asprintf ( & second_principal , " host/%s.%s " , global_myname ( ) , lp_realm ( ) ) ;
if ( second_principal ! = NULL ) {
strlower_m ( second_principal ) ;
asprintf ( & salting_principals [ 1 ] , " %s@%s " , second_principal , lp_realm ( ) ) ;
SAFE_FREE ( second_principal ) ;
}
if ( ( salting_principals [ 1 ] = = NULL ) | | ( strlen ( salting_principals [ 1 ] ) = = 0 ) ) {
goto out ;
}
/* Generate our third guess -- the computer's principal, as Win2k. */
asprintf ( & second_principal , " HOST/%s " , global_myname ( ) ) ;
if ( second_principal ! = NULL ) {
strlower_m ( second_principal + 5 ) ;
asprintf ( & salting_principals [ 2 ] , " %s@%s " ,
second_principal , lp_realm ( ) ) ;
SAFE_FREE ( second_principal ) ;
}
if ( ( salting_principals [ 2 ] = = NULL ) | | ( strlen ( salting_principals [ 2 ] ) = = 0 ) ) {
goto out ;
}
/* Get a service ticket for ourselves into our memory ccache. */
/* This will commonly fail if there is no principal by that name (and we're trying
many names ) . So don ' t print a debug 0 error . */
if ( ( err = get_service_ticket ( ctx , ccache , service_principal , enctype , & outbuf ) ) ! = 0 ) {
DEBUG ( 3 , ( " verify_service_password: get_service_ticket failed: %s \n " ,
error_message ( err ) ) ) ;
goto out ;
}
/* At this point we have a message to ourselves, salted only the KDC knows how. We
have to work out what that salting is . */
/* Try and find the correct salting principal. */
for ( i = 0 ; i < sizeof ( salting_principals ) / sizeof ( salting_principals [ i ] ) ; i + + ) {
if ( verify_service_password ( ctx , enctype , salting_principals [ i ] , & outbuf ) ) {
break ;
}
}
/* If we failed to get a match, return. */
if ( i > = sizeof ( salting_principals ) / sizeof ( salting_principals [ i ] ) ) {
goto out ;
}
/* If we succeeded, store the principal for use for all enctypes which
* share the same cipher and string - to - key function . Doing this here
* allows servers which just pass a keytab to krb5_rd_req ( ) to work
* correctly . */
for ( j = 0 ; enctypes [ j ] ! = 0 ; j + + ) {
if ( enctype ! = enctypes [ j ] ) {
/* If this enctype isn't compatible with the one which
* we used , skip it . */
if ( ! kerberos_compatible_enctypes ( ctx , enctypes [ j ] , enctype ) )
continue ;
}
/* If the principal which gives us the proper salt is the one
* which we would normally guess , don ' t bother noting anything
* in the secrets tdb . */
if ( strcmp ( service_principal , salting_principals [ i ] ) ! = 0 ) {
kerberos_secrets_store_salting_principal ( service_principal ,
enctypes [ j ] ,
salting_principals [ i ] ) ;
}
}
out :
kerberos_free_data_contents ( ctx , & outbuf ) ;
SAFE_FREE ( salting_principals [ 0 ] ) ;
SAFE_FREE ( salting_principals [ 1 ] ) ;
SAFE_FREE ( salting_principals [ 2 ] ) ;
SAFE_FREE ( second_principal ) ;
}
/************************************************************************
Go through all the possible enctypes for this principal .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-11-03 00:28:14 +03:00
static void kerberos_derive_salting_principal_direct ( krb5_context context ,
2004-10-30 02:38:10 +04:00
krb5_ccache ccache ,
krb5_enctype * enctypes ,
char * service_principal )
{
int i ;
/* Try for each enctype separately, because the rules are
* different for different enctypes . */
for ( i = 0 ; enctypes [ i ] ! = 0 ; i + + ) {
/* Delete secrets entry first. */
kerberos_secrets_store_salting_principal ( service_principal , 0 , NULL ) ;
# ifdef ENCTYPE_ARCFOUR_HMAC
if ( enctypes [ i ] = = ENCTYPE_ARCFOUR_HMAC ) {
/* Of course this'll always work, so just save
* ourselves the effort . */
continue ;
}
# endif
/* Try to figure out what's going on with this
* principal . */
kerberos_derive_salting_principal_for_enctype ( service_principal ,
context ,
ccache ,
enctypes [ i ] ,
enctypes ) ;
}
2004-11-03 00:28:14 +03:00
}
2004-10-30 04:34:58 +04:00
2004-11-03 00:28:14 +03:00
/************************************************************************
Wrapper function for the above .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-11-03 03:29:09 +03:00
BOOL kerberos_derive_salting_principal ( char * service_principal )
2004-11-03 00:28:14 +03:00
{
krb5_context context = NULL ;
krb5_enctype * enctypes = NULL ;
krb5_ccache ccache = NULL ;
krb5_error_code ret = 0 ;
initialize_krb5_error_table ( ) ;
if ( ( ret = krb5_init_context ( & context ) ) ! = 0 ) {
DEBUG ( 1 , ( " kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s \n " ,
error_message ( ret ) ) ) ;
2004-11-03 03:29:09 +03:00
return False ;
2004-11-03 00:28:14 +03:00
}
if ( ( ret = get_kerberos_allowed_etypes ( context , & enctypes ) ) ! = 0 ) {
DEBUG ( 1 , ( " kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s \n " ,
error_message ( ret ) ) ) ;
goto out ;
}
if ( ( ret = krb5_cc_resolve ( context , LIBADS_CCACHE_NAME , & ccache ) ) ! = 0 ) {
DEBUG ( 3 , ( " get_service_ticket: krb5_cc_resolve for %s failed: %s \n " ,
LIBADS_CCACHE_NAME , error_message ( ret ) ) ) ;
goto out ;
}
kerberos_derive_salting_principal_direct ( context , ccache , enctypes , service_principal ) ;
out :
if ( enctypes ) {
free_kerberos_etypes ( context , enctypes ) ;
}
if ( ccache ) {
krb5_cc_destroy ( context , ccache ) ;
}
if ( context ) {
krb5_free_context ( context ) ;
2004-10-30 04:34:58 +04:00
}
2004-11-03 03:29:09 +03:00
return ret ? False : True ;
2004-10-30 02:38:10 +04:00
}
/************************************************************************
Core function to try and determine what salt is being used for any keytab
keys .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL kerberos_derive_cifs_salting_principals ( void )
{
fstring my_fqdn ;
char * service = NULL ;
krb5_context context = NULL ;
krb5_enctype * enctypes = NULL ;
krb5_ccache ccache = NULL ;
krb5_error_code ret = 0 ;
BOOL retval = False ;
initialize_krb5_error_table ( ) ;
if ( ( ret = krb5_init_context ( & context ) ) ! = 0 ) {
DEBUG ( 1 , ( " kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s \n " ,
error_message ( ret ) ) ) ;
return False ;
}
if ( ( ret = get_kerberos_allowed_etypes ( context , & enctypes ) ) ! = 0 ) {
DEBUG ( 1 , ( " kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s \n " ,
error_message ( ret ) ) ) ;
goto out ;
}
if ( ( ret = krb5_cc_resolve ( context , LIBADS_CCACHE_NAME , & ccache ) ) ! = 0 ) {
DEBUG ( 3 , ( " get_service_ticket: krb5_cc_resolve for %s failed: %s \n " ,
LIBADS_CCACHE_NAME , error_message ( ret ) ) ) ;
goto out ;
}
if ( asprintf ( & service , " %s$ " , global_myname ( ) ) ! = - 1 ) {
strlower_m ( service ) ;
2004-11-03 00:28:14 +03:00
kerberos_derive_salting_principal_direct ( context , ccache , enctypes , service ) ;
2004-10-30 02:38:10 +04:00
SAFE_FREE ( service ) ;
}
if ( asprintf ( & service , " cifs/%s " , global_myname ( ) ) ! = - 1 ) {
strlower_m ( service ) ;
2004-11-03 00:28:14 +03:00
kerberos_derive_salting_principal_direct ( context , ccache , enctypes , service ) ;
2004-10-30 02:38:10 +04:00
SAFE_FREE ( service ) ;
}
if ( asprintf ( & service , " host/%s " , global_myname ( ) ) ! = - 1 ) {
strlower_m ( service ) ;
2004-11-03 00:28:14 +03:00
kerberos_derive_salting_principal_direct ( context , ccache , enctypes , service ) ;
2004-10-30 02:38:10 +04:00
SAFE_FREE ( service ) ;
}
if ( asprintf ( & service , " cifs/%s.%s " , global_myname ( ) , lp_realm ( ) ) ! = - 1 ) {
strlower_m ( service ) ;
2004-11-03 00:28:14 +03:00
kerberos_derive_salting_principal_direct ( context , ccache , enctypes , service ) ;
2004-10-30 02:38:10 +04:00
SAFE_FREE ( service ) ;
}
if ( asprintf ( & service , " host/%s.%s " , global_myname ( ) , lp_realm ( ) ) ! = - 1 ) {
strlower_m ( service ) ;
2004-11-03 00:28:14 +03:00
kerberos_derive_salting_principal_direct ( context , ccache , enctypes , service ) ;
2004-10-30 02:38:10 +04:00
SAFE_FREE ( service ) ;
}
name_to_fqdn ( my_fqdn , global_myname ( ) ) ;
if ( asprintf ( & service , " cifs/%s " , my_fqdn ) ! = - 1 ) {
strlower_m ( service ) ;
2004-11-03 00:28:14 +03:00
kerberos_derive_salting_principal_direct ( context , ccache , enctypes , service ) ;
2004-10-30 02:38:10 +04:00
SAFE_FREE ( service ) ;
}
if ( asprintf ( & service , " host/%s " , my_fqdn ) ! = - 1 ) {
strlower_m ( service ) ;
2004-11-03 00:28:14 +03:00
kerberos_derive_salting_principal_direct ( context , ccache , enctypes , service ) ;
2004-10-30 02:38:10 +04:00
SAFE_FREE ( service ) ;
}
retval = True ;
out :
if ( enctypes ) {
free_kerberos_etypes ( context , enctypes ) ;
}
if ( ccache ) {
krb5_cc_destroy ( context , ccache ) ;
}
if ( context ) {
krb5_free_context ( context ) ;
}
return retval ;
}
2001-11-24 17:16:41 +03:00
# endif