2004-06-18 01:39:51 +04:00
/*
Unix SMB / CIFS implementation .
kerberos keytab utility library
Copyright ( C ) Andrew Tridgell 2001
Copyright ( C ) Remus Koos 2001
Copyright ( C ) Luke Howard 2003
Copyright ( C ) Jim McDonough ( jmcd @ us . ibm . com ) 2003
2007-06-29 12:56:35 +04:00
Copyright ( C ) Guenther Deschner 2003 , 2007
2004-06-18 01:39:51 +04:00
Copyright ( C ) Rakesh Patel 2004
Copyright ( C ) Dan Perry 2004
2004-06-18 03:07:20 +04:00
Copyright ( C ) Jeremy Allison 2004
2006-07-11 22:45:22 +04:00
Copyright ( C ) Gerald Carter 2006
2004-06-18 01:39:51 +04: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
2006-07-11 22:45:22 +04:00
/* This MAX_NAME_LEN is a constant defined in krb5.h */
# ifndef MAX_KEYTAB_NAME_LEN
# define MAX_KEYTAB_NAME_LEN 1100
# endif
2007-06-29 12:56:35 +04:00
/**********************************************************************
* Open a krb5 keytab with flags , handles readonly or readwrite access and
* allows to process non - default keytab names .
* @ param context krb5_context
* @ param keytab_name_req string
* @ param write_access BOOL if writable keytab is required
* @ param krb5_keytab pointer to krb5_keytab ( close with krb5_kt_close ( ) )
* @ return krb5_error_code
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
krb5_error_code smb_krb5_open_keytab ( krb5_context context ,
const char * keytab_name_req ,
BOOL write_access ,
krb5_keytab * keytab )
{
krb5_error_code ret = 0 ;
TALLOC_CTX * mem_ctx ;
char keytab_string [ MAX_KEYTAB_NAME_LEN ] ;
BOOL found_valid_name = False ;
const char * pragma = " FILE " ;
const char * tmp = NULL ;
if ( ! write_access & & ! keytab_name_req ) {
/* caller just wants to read the default keytab readonly, so be it */
return krb5_kt_default ( context , keytab ) ;
}
mem_ctx = talloc_init ( " smb_krb5_open_keytab " ) ;
if ( ! mem_ctx ) {
return ENOMEM ;
}
# ifdef HAVE_WRFILE_KEYTAB
if ( write_access ) {
pragma = " WRFILE " ;
}
# endif
if ( keytab_name_req ) {
if ( strlen ( keytab_name_req ) > MAX_KEYTAB_NAME_LEN ) {
ret = KRB5_CONFIG_NOTENUFSPACE ;
goto out ;
}
if ( ( strncmp ( keytab_name_req , " WRFILE:/ " , 8 ) = = 0 ) | |
( strncmp ( keytab_name_req , " FILE:/ " , 6 ) = = 0 ) ) {
tmp = keytab_name_req ;
goto resolve ;
}
if ( keytab_name_req [ 0 ] ! = ' / ' ) {
ret = KRB5_KT_BADNAME ;
goto out ;
}
tmp = talloc_asprintf ( mem_ctx , " %s:%s " , pragma , keytab_name_req ) ;
if ( ! tmp ) {
ret = ENOMEM ;
goto out ;
}
goto resolve ;
}
/* we need to handle more complex keytab_strings, like:
* " ANY:FILE:/etc/krb5.keytab,krb4:/etc/srvtab " */
ret = krb5_kt_default_name ( context , & keytab_string [ 0 ] , MAX_KEYTAB_NAME_LEN - 2 ) ;
if ( ret ) {
goto out ;
}
DEBUG ( 10 , ( " smb_krb5_open_keytab: krb5_kt_default_name returned %s \n " , keytab_string ) ) ;
tmp = talloc_strdup ( mem_ctx , keytab_string ) ;
if ( ! tmp ) {
ret = ENOMEM ;
goto out ;
}
if ( strncmp ( tmp , " ANY: " , 4 ) = = 0 ) {
tmp + = 4 ;
}
memset ( & keytab_string , ' \0 ' , sizeof ( keytab_string ) ) ;
while ( next_token ( & tmp , keytab_string , " , " , sizeof ( keytab_string ) ) ) {
if ( strncmp ( keytab_string , " WRFILE: " , 7 ) = = 0 ) {
found_valid_name = True ;
tmp = keytab_string ;
tmp + = 7 ;
}
if ( strncmp ( keytab_string , " FILE: " , 5 ) = = 0 ) {
found_valid_name = True ;
tmp = keytab_string ;
tmp + = 5 ;
}
if ( found_valid_name ) {
if ( tmp [ 0 ] ! = ' / ' ) {
ret = KRB5_KT_BADNAME ;
goto out ;
}
tmp = talloc_asprintf ( mem_ctx , " %s:%s " , pragma , tmp ) ;
if ( ! tmp ) {
ret = ENOMEM ;
goto out ;
}
break ;
}
}
if ( ! found_valid_name ) {
ret = KRB5_KT_UNKNOWN_TYPE ;
goto out ;
}
resolve :
DEBUG ( 10 , ( " smb_krb5_open_keytab: resolving: %s \n " , tmp ) ) ;
ret = krb5_kt_resolve ( context , tmp , keytab ) ;
out :
TALLOC_FREE ( mem_ctx ) ;
return ret ;
}
2006-07-11 22:45:22 +04:00
2004-06-18 03:07:20 +04:00
/**********************************************************************
2006-07-11 22:45:22 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-18 03:07:20 +04:00
2006-07-11 22:45:22 +04:00
static int smb_krb5_kt_add_entry ( krb5_context context , krb5_keytab keytab ,
krb5_kvno kvno , const char * princ_s ,
krb5_enctype * enctypes , krb5_data password )
2004-06-18 01:39:51 +04:00
{
2004-06-18 03:07:20 +04:00
krb5_error_code ret = 0 ;
2004-06-24 23:48:52 +04:00
krb5_kt_cursor cursor ;
2004-06-18 03:07:20 +04:00
krb5_keytab_entry kt_entry ;
krb5_principal princ = NULL ;
2004-06-18 01:39:51 +04:00
int i ;
char * ktprinc = NULL ;
2004-06-18 03:07:20 +04:00
ZERO_STRUCT ( kt_entry ) ;
2004-06-24 23:48:52 +04:00
ZERO_STRUCT ( cursor ) ;
2006-07-11 22:45:22 +04:00
2006-04-24 19:57:54 +04:00
ret = smb_krb5_parse_name ( context , princ_s , & princ ) ;
2004-06-18 01:39:51 +04:00
if ( ret ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 1 , ( " smb_krb5_kt_add_entry: smb_krb5_parse_name(%s) failed (%s) \n " , princ_s , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
/* Seek and delete old keytab entries */
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( ret ! = KRB5_KT_END & & ret ! = ENOENT ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 3 , ( " smb_krb5_kt_add_entry: Will try to delete old keytab entries \n " ) ) ;
2004-06-18 03:07:20 +04:00
while ( ! krb5_kt_next_entry ( context , keytab , & kt_entry , & cursor ) ) {
2004-11-03 05:18:51 +03:00
BOOL compare_name_ok = False ;
2004-06-18 01:39:51 +04:00
2006-04-24 19:57:54 +04:00
ret = smb_krb5_unparse_name ( context , kt_entry . principal , & ktprinc ) ;
2004-06-18 03:07:20 +04:00
if ( ret ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 1 , ( " smb_krb5_kt_add_entry: smb_krb5_unparse_name failed (%s) \n " ,
2006-04-24 19:57:54 +04:00
error_message ( ret ) ) ) ;
2004-06-18 03:07:20 +04:00
goto out ;
}
2004-06-18 01:39:51 +04:00
/*---------------------------------------------------------------------------
* Save the entries with kvno - 1. This is what microsoft does
* to allow people with existing sessions that have kvno - 1 to still
* work . Otherwise , when the password for the machine changes , all
* kerberizied sessions will ' break ' until either the client reboots or
* the client ' s session key expires and they get a new session ticket
* with the new kvno .
*/
# ifdef HAVE_KRB5_KT_COMPARE
2004-11-03 05:18:51 +03:00
compare_name_ok = ( krb5_kt_compare ( context , & kt_entry , princ , 0 , 0 ) = = True ) ;
2004-06-18 01:39:51 +04:00
# else
2004-11-03 05:18:51 +03:00
compare_name_ok = ( strcmp ( ktprinc , princ_s ) = = 0 ) ;
2004-06-18 01:39:51 +04:00
# endif
2004-11-03 05:18:51 +03:00
if ( ! compare_name_ok ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 10 , ( " smb_krb5_kt_add_entry: ignoring keytab entry principal %s, kvno = %d \n " ,
2004-11-03 05:18:51 +03:00
ktprinc , kt_entry . vno ) ) ;
}
2006-04-24 19:57:54 +04:00
SAFE_FREE ( ktprinc ) ;
2004-06-18 04:24:53 +04:00
2004-11-03 05:18:51 +03:00
if ( compare_name_ok ) {
if ( kt_entry . vno = = kvno - 1 ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 5 , ( " smb_krb5_kt_add_entry: Saving previous (kvno %d) entry for principal: %s. \n " ,
2004-11-03 05:18:51 +03:00
kvno - 1 , princ_s ) ) ;
} else {
2007-03-17 01:40:51 +03:00
DEBUG ( 5 , ( " smb_krb5_kt_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it. \n " ,
2004-11-03 05:18:51 +03:00
princ_s , kt_entry . vno ) ) ;
ret = krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
ZERO_STRUCT ( cursor ) ;
if ( ret ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 1 , ( " smb_krb5_kt_add_entry: krb5_kt_end_seq_get() failed (%s) \n " ,
2004-11-03 05:18:51 +03:00
error_message ( ret ) ) ) ;
goto out ;
}
ret = krb5_kt_remove_entry ( context , keytab , & kt_entry ) ;
if ( ret ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 1 , ( " smb_krb5_kt_add_entry: krb5_kt_remove_entry failed (%s) \n " ,
2004-11-03 05:18:51 +03:00
error_message ( ret ) ) ) ;
goto out ;
}
2007-03-17 01:40:51 +03:00
DEBUG ( 5 , ( " smb_krb5_kt_add_entry: removed old entry for principal: %s (kvno %d). \n " ,
2004-11-03 05:18:51 +03:00
princ_s , kt_entry . vno ) ) ;
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( ret ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 1 , ( " smb_krb5_kt_add_entry: krb5_kt_start_seq failed (%s) \n " ,
2004-11-03 05:18:51 +03:00
error_message ( ret ) ) ) ;
goto out ;
}
ret = smb_krb5_kt_free_entry ( context , & kt_entry ) ;
ZERO_STRUCT ( kt_entry ) ;
if ( ret ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 1 , ( " smb_krb5_kt_add_entry: krb5_kt_remove_entry failed (%s) \n " ,
2004-11-03 05:18:51 +03:00
error_message ( ret ) ) ) ;
goto out ;
}
continue ;
2004-06-18 01:39:51 +04:00
}
}
2004-06-18 04:24:53 +04:00
/* Not a match, just free this entry and continue. */
2004-06-24 09:56:44 +04:00
ret = smb_krb5_kt_free_entry ( context , & kt_entry ) ;
2004-06-18 04:24:53 +04:00
ZERO_STRUCT ( kt_entry ) ;
2004-06-18 01:39:51 +04:00
if ( ret ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 1 , ( " smb_krb5_kt_add_entry: smb_krb5_kt_free_entry failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
}
ret = krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
2004-06-24 23:48:52 +04:00
ZERO_STRUCT ( cursor ) ;
2004-06-18 01:39:51 +04:00
if ( ret ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 1 , ( " smb_krb5_kt_add_entry: krb5_kt_end_seq_get failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
}
2004-06-18 04:24:53 +04:00
/* Ensure we don't double free. */
ZERO_STRUCT ( kt_entry ) ;
2004-06-24 23:48:52 +04:00
ZERO_STRUCT ( cursor ) ;
2004-06-18 01:39:51 +04:00
2004-06-18 04:24:53 +04:00
/* If we get here, we have deleted all the old entries with kvno's not equal to the current kvno-1. */
2004-06-18 01:39:51 +04:00
2004-06-18 04:24:53 +04:00
/* Now add keytab entries for all encryption types */
for ( i = 0 ; enctypes [ i ] ; i + + ) {
krb5_keyblock * keyp ;
2004-06-18 01:39:51 +04:00
# if !defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) && !defined(HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK)
# error krb5_keytab_entry has no key or keyblock member
# endif
# ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY /* MIT */
2004-06-18 04:24:53 +04:00
keyp = & kt_entry . key ;
2004-06-18 01:39:51 +04:00
# endif
# ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */
2004-06-18 04:24:53 +04:00
keyp = & kt_entry . keyblock ;
2004-06-18 01:39:51 +04:00
# endif
2004-06-18 04:24:53 +04:00
if ( create_kerberos_key_from_string ( context , princ , & password , keyp , enctypes [ i ] ) ) {
continue ;
}
kt_entry . principal = princ ;
kt_entry . vno = kvno ;
2007-03-17 01:40:51 +03:00
DEBUG ( 3 , ( " smb_krb5_kt_add_entry: adding keytab entry for (%s) with encryption type (%d) and version (%d) \n " ,
2004-06-18 04:24:53 +04:00
princ_s , enctypes [ i ] , kt_entry . vno ) ) ;
ret = krb5_kt_add_entry ( context , keytab , & kt_entry ) ;
2004-06-23 01:58:35 +04:00
krb5_free_keyblock_contents ( context , keyp ) ;
2004-06-18 04:24:53 +04:00
ZERO_STRUCT ( kt_entry ) ;
2004-06-18 01:39:51 +04:00
if ( ret ) {
2007-03-17 01:40:51 +03:00
DEBUG ( 1 , ( " smb_krb5_kt_add_entry: adding entry to keytab failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
}
2004-06-18 04:24:53 +04:00
2004-06-18 01:39:51 +04:00
out :
2004-06-18 03:07:20 +04:00
{
krb5_keytab_entry zero_kt_entry ;
ZERO_STRUCT ( zero_kt_entry ) ;
if ( memcmp ( & zero_kt_entry , & kt_entry , sizeof ( krb5_keytab_entry ) ) ) {
2004-06-24 09:56:44 +04:00
smb_krb5_kt_free_entry ( context , & kt_entry ) ;
2004-06-18 03:07:20 +04:00
}
}
if ( princ ) {
krb5_free_principal ( context , princ ) ;
}
2006-07-11 22:45:22 +04:00
2004-06-24 23:48:52 +04:00
{
krb5_kt_cursor zero_csr ;
ZERO_STRUCT ( zero_csr ) ;
if ( ( memcmp ( & cursor , & zero_csr , sizeof ( krb5_kt_cursor ) ) ! = 0 ) & & keytab ) {
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
}
2004-06-18 01:39:51 +04:00
}
2006-07-11 22:45:22 +04:00
return ( int ) ret ;
}
/**********************************************************************
Adds a single service principal , i . e . ' host ' to the system keytab
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int ads_keytab_add_entry ( ADS_STRUCT * ads , const char * srvPrinc )
{
krb5_error_code ret = 0 ;
krb5_context context = NULL ;
krb5_keytab keytab = NULL ;
krb5_data password ;
krb5_kvno kvno ;
krb5_enctype enctypes [ 4 ] = { ENCTYPE_DES_CBC_CRC , ENCTYPE_DES_CBC_MD5 , 0 , 0 } ;
char * princ_s = NULL , * short_princ_s = NULL ;
char * password_s = NULL ;
char * my_fqdn ;
TALLOC_CTX * ctx = NULL ;
char * machine_name ;
# if defined(ENCTYPE_ARCFOUR_HMAC)
enctypes [ 2 ] = ENCTYPE_ARCFOUR_HMAC ;
# endif
initialize_krb5_error_table ( ) ;
ret = krb5_init_context ( & context ) ;
if ( ret ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: could not krb5_init_context: %s \n " , error_message ( ret ) ) ) ;
return - 1 ;
}
2007-06-29 12:56:35 +04:00
ret = smb_krb5_open_keytab ( context , NULL , True , & keytab ) ;
2006-07-11 22:45:22 +04:00
if ( ret ) {
2007-06-29 12:56:35 +04:00
DEBUG ( 1 , ( " ads_keytab_add_entry: smb_krb5_open_keytab failed (%s) \n " , error_message ( ret ) ) ) ;
2006-07-11 22:45:22 +04:00
goto out ;
}
/* retrieve the password */
if ( ! secrets_init ( ) ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: secrets_init failed \n " ) ) ;
ret = - 1 ;
goto out ;
}
password_s = secrets_fetch_machine_password ( lp_workgroup ( ) , NULL , NULL ) ;
if ( ! password_s ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: failed to fetch machine password \n " ) ) ;
ret = - 1 ;
goto out ;
}
password . data = password_s ;
password . length = strlen ( password_s ) ;
/* we need the dNSHostName value here */
if ( ( ctx = talloc_init ( " ads_keytab_add_entry " ) ) = = NULL ) {
DEBUG ( 0 , ( " ads_keytab_add_entry: talloc() failed! \n " ) ) ;
ret = - 1 ;
goto out ;
}
if ( ( my_fqdn = ads_get_dnshostname ( ads , ctx , global_myname ( ) ) ) = = NULL ) {
DEBUG ( 0 , ( " ads_keytab_add_entry: unable to determine machine account's dns name in AD! \n " ) ) ;
ret = - 1 ;
goto out ;
}
if ( ( machine_name = ads_get_samaccountname ( ads , ctx , global_myname ( ) ) ) = = NULL ) {
DEBUG ( 0 , ( " ads_keytab_add_entry: unable to determine machine account's short name in AD! \n " ) ) ;
ret = - 1 ;
goto out ;
}
/*strip the trailing '$' */
machine_name [ strlen ( machine_name ) - 1 ] = ' \0 ' ;
/* Construct our principal */
if ( strchr_m ( srvPrinc , ' @ ' ) ) {
/* It's a fully-named principal. */
asprintf ( & princ_s , " %s " , srvPrinc ) ;
} else if ( srvPrinc [ strlen ( srvPrinc ) - 1 ] = = ' $ ' ) {
/* It's the machine account, as used by smbclient clients. */
asprintf ( & princ_s , " %s@%s " , srvPrinc , lp_realm ( ) ) ;
} else {
/* It's a normal service principal. Add the SPN now so that we
* can obtain credentials for it and double - check the salt value
* used to generate the service ' s keys . */
asprintf ( & princ_s , " %s/%s@%s " , srvPrinc , my_fqdn , lp_realm ( ) ) ;
asprintf ( & short_princ_s , " %s/%s@%s " , srvPrinc , machine_name , lp_realm ( ) ) ;
/* According to http://support.microsoft.com/kb/326985/en-us,
certain principal names are automatically mapped to the host / . . .
principal in the AD account . So only create these in the
keytab , not in AD . - - jerry */
if ( ! strequal ( srvPrinc , " cifs " ) & & ! strequal ( srvPrinc , " host " ) ) {
DEBUG ( 3 , ( " ads_keytab_add_entry: Attempting to add/update '%s' \n " , princ_s ) ) ;
if ( ! ADS_ERR_OK ( ads_add_service_principal_name ( ads , global_myname ( ) , my_fqdn , srvPrinc ) ) ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: ads_add_service_principal_name failed. \n " ) ) ;
goto out ;
}
}
}
kvno = ( krb5_kvno ) ads_get_kvno ( ads , global_myname ( ) ) ;
if ( kvno = = - 1 ) { /* -1 indicates failure, everything else is OK */
DEBUG ( 1 , ( " ads_keytab_add_entry: ads_get_kvno failed to determine the system's kvno. \n " ) ) ;
ret = - 1 ;
goto out ;
}
/* add the fqdn principal to the keytab */
ret = smb_krb5_kt_add_entry ( context , keytab , kvno , princ_s , enctypes , password ) ;
if ( ret ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: Failed to add entry to keytab file \n " ) ) ;
goto out ;
}
/* add the short principal name if we have one */
if ( short_princ_s ) {
ret = smb_krb5_kt_add_entry ( context , keytab , kvno , short_princ_s , enctypes , password ) ;
if ( ret ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: Failed to add short entry to keytab file \n " ) ) ;
goto out ;
}
}
out :
SAFE_FREE ( princ_s ) ;
SAFE_FREE ( short_princ_s ) ;
TALLOC_FREE ( ctx ) ;
2004-06-18 03:07:20 +04:00
if ( keytab ) {
krb5_kt_close ( context , keytab ) ;
2004-06-18 01:39:51 +04:00
}
2004-06-18 03:07:20 +04:00
if ( context ) {
krb5_free_context ( context ) ;
2004-06-18 01:39:51 +04:00
}
2004-06-18 03:07:20 +04:00
return ( int ) ret ;
2004-06-18 01:39:51 +04:00
}
2004-06-18 04:24:53 +04:00
/**********************************************************************
2004-06-19 03:15:42 +04:00
Flushes all entries from the system keytab .
2004-06-18 04:24:53 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-18 01:39:51 +04:00
int ads_keytab_flush ( ADS_STRUCT * ads )
{
2004-06-18 06:07:42 +04:00
krb5_error_code ret = 0 ;
krb5_context context = NULL ;
krb5_keytab keytab = NULL ;
2004-06-24 23:48:52 +04:00
krb5_kt_cursor cursor ;
2004-06-18 06:07:42 +04:00
krb5_keytab_entry kt_entry ;
2004-06-18 01:39:51 +04:00
krb5_kvno kvno ;
2004-06-18 06:07:42 +04:00
ZERO_STRUCT ( kt_entry ) ;
2004-06-24 23:48:52 +04:00
ZERO_STRUCT ( cursor ) ;
2004-06-18 01:39:51 +04:00
initialize_krb5_error_table ( ) ;
ret = krb5_init_context ( & context ) ;
if ( ret ) {
2004-06-18 06:07:42 +04:00
DEBUG ( 1 , ( " ads_keytab_flush: could not krb5_init_context: %s \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
return ret ;
}
2007-06-29 12:56:35 +04:00
ret = smb_krb5_open_keytab ( context , NULL , True , & keytab ) ;
2004-06-18 01:39:51 +04:00
if ( ret ) {
2007-06-29 12:56:35 +04:00
DEBUG ( 1 , ( " ads_keytab_flush: smb_krb5_open_keytab failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
kvno = ( krb5_kvno ) ads_get_kvno ( ads , global_myname ( ) ) ;
if ( kvno = = - 1 ) { /* -1 indicates a failure */
2004-06-18 06:07:42 +04:00
DEBUG ( 1 , ( " ads_keytab_flush: Error determining the system's kvno. \n " ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( ret ! = KRB5_KT_END & & ret ! = ENOENT ) {
2004-06-19 03:15:42 +04:00
while ( ! krb5_kt_next_entry ( context , keytab , & kt_entry , & cursor ) ) {
2004-06-18 01:39:51 +04:00
ret = krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
2004-06-24 23:48:52 +04:00
ZERO_STRUCT ( cursor ) ;
2004-06-18 01:39:51 +04:00
if ( ret ) {
2004-06-19 03:15:42 +04:00
DEBUG ( 1 , ( " ads_keytab_flush: krb5_kt_end_seq_get() failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
2004-06-19 03:15:42 +04:00
ret = krb5_kt_remove_entry ( context , keytab , & kt_entry ) ;
2004-06-18 01:39:51 +04:00
if ( ret ) {
2004-06-19 03:15:42 +04:00
DEBUG ( 1 , ( " ads_keytab_flush: krb5_kt_remove_entry failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( ret ) {
2004-06-19 03:15:42 +04:00
DEBUG ( 1 , ( " ads_keytab_flush: krb5_kt_start_seq failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
2004-06-24 09:56:44 +04:00
ret = smb_krb5_kt_free_entry ( context , & kt_entry ) ;
2004-06-19 03:15:42 +04:00
ZERO_STRUCT ( kt_entry ) ;
2004-06-18 01:39:51 +04:00
if ( ret ) {
2004-06-19 03:15:42 +04:00
DEBUG ( 1 , ( " ads_keytab_flush: krb5_kt_remove_entry failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
}
}
2004-06-19 03:15:42 +04:00
/* Ensure we don't double free. */
ZERO_STRUCT ( kt_entry ) ;
2004-06-24 23:48:52 +04:00
ZERO_STRUCT ( cursor ) ;
2004-06-19 03:15:42 +04:00
2004-06-22 04:48:59 +04:00
if ( ! ADS_ERR_OK ( ads_clear_service_principal_names ( ads , global_myname ( ) ) ) ) {
2004-06-19 03:15:42 +04:00
DEBUG ( 1 , ( " ads_keytab_flush: Error while clearing service principal listings in LDAP. \n " ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
out :
2004-06-18 06:07:42 +04:00
{
krb5_keytab_entry zero_kt_entry ;
ZERO_STRUCT ( zero_kt_entry ) ;
if ( memcmp ( & zero_kt_entry , & kt_entry , sizeof ( krb5_keytab_entry ) ) ) {
2004-06-24 09:56:44 +04:00
smb_krb5_kt_free_entry ( context , & kt_entry ) ;
2004-06-18 06:07:42 +04:00
}
}
2004-06-24 23:48:52 +04:00
{
krb5_kt_cursor zero_csr ;
ZERO_STRUCT ( zero_csr ) ;
if ( ( memcmp ( & cursor , & zero_csr , sizeof ( krb5_kt_cursor ) ) ! = 0 ) & & keytab ) {
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
}
2004-06-18 06:07:42 +04:00
}
if ( keytab ) {
krb5_kt_close ( context , keytab ) ;
}
if ( context ) {
krb5_free_context ( context ) ;
}
2004-06-18 01:39:51 +04:00
return ret ;
}
2004-06-19 03:15:42 +04:00
/**********************************************************************
Adds all the required service principals to the system keytab .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-18 01:39:51 +04:00
int ads_keytab_create_default ( ADS_STRUCT * ads )
{
2004-06-19 03:15:42 +04:00
krb5_error_code ret = 0 ;
krb5_context context = NULL ;
krb5_keytab keytab = NULL ;
2004-06-24 23:48:52 +04:00
krb5_kt_cursor cursor ;
2004-06-19 03:15:42 +04:00
krb5_keytab_entry kt_entry ;
2004-06-18 01:39:51 +04:00
krb5_kvno kvno ;
int i , found = 0 ;
2006-07-11 22:45:22 +04:00
char * sam_account_name , * upn ;
2005-03-11 23:59:16 +03:00
char * * oldEntries = NULL , * princ_s [ 26 ] ;
2006-07-11 22:45:22 +04:00
TALLOC_CTX * ctx = NULL ;
fstring machine_name ;
2005-03-11 23:59:16 +03:00
memset ( princ_s , ' \0 ' , sizeof ( princ_s ) ) ;
2004-06-18 01:39:51 +04:00
2006-07-11 22:45:22 +04:00
fstrcpy ( machine_name , global_myname ( ) ) ;
/* these are the main ones we need */
if ( ( ret = ads_keytab_add_entry ( ads , " host " ) ) ! = 0 ) {
2004-06-19 03:15:42 +04:00
DEBUG ( 1 , ( " ads_keytab_create_default: ads_keytab_add_entry failed while adding 'host'. \n " ) ) ;
2004-06-18 01:39:51 +04:00
return ret ;
}
2006-07-11 22:45:22 +04:00
#if 0 /* don't create the CIFS/... keytab entries since no one except smbd
really needs them and we will fall back to verifying against secrets . tdb */
if ( ( ret = ads_keytab_add_entry ( ads , " cifs " ) ) ! = 0 ) {
2004-06-19 03:15:42 +04:00
DEBUG ( 1 , ( " ads_keytab_create_default: ads_keytab_add_entry failed while adding 'cifs'. \n " ) ) ;
2004-06-18 01:39:51 +04:00
return ret ;
}
2006-07-11 22:45:22 +04:00
# endif
2004-06-18 01:39:51 +04:00
2006-07-11 22:45:22 +04:00
if ( ( ctx = talloc_init ( " ads_keytab_create_default " ) ) = = NULL ) {
DEBUG ( 0 , ( " ads_keytab_create_default: talloc() failed! \n " ) ) ;
return - 1 ;
}
/* now add the userPrincipalName and sAMAccountName entries */
2007-01-03 00:29:09 +03:00
2006-07-11 22:45:22 +04:00
if ( ( sam_account_name = ads_get_samaccountname ( ads , ctx , machine_name ) ) = = NULL ) {
DEBUG ( 0 , ( " ads_keytab_add_entry: unable to determine machine account's name in AD! \n " ) ) ;
TALLOC_FREE ( ctx ) ;
return - 1 ;
}
2007-01-03 00:29:09 +03:00
/* upper case the sAMAccountName to make it easier for apps to
know what case to use in the keytab file */
strupper_m ( sam_account_name ) ;
2006-07-11 22:45:22 +04:00
if ( ( ret = ads_keytab_add_entry ( ads , sam_account_name ) ) ! = 0 ) {
DEBUG ( 1 , ( " ads_keytab_create_default: ads_keytab_add_entry failed while adding sAMAccountName (%s) \n " ,
sam_account_name ) ) ;
return ret ;
}
/* remember that not every machine account will have a upn */
upn = ads_get_upn ( ads , ctx , machine_name ) ;
if ( upn ) {
if ( ( ret = ads_keytab_add_entry ( ads , upn ) ) ! = 0 ) {
DEBUG ( 1 , ( " ads_keytab_create_default: ads_keytab_add_entry failed while adding UPN (%s) \n " ,
upn ) ) ;
TALLOC_FREE ( ctx ) ;
return ret ;
2004-10-30 04:34:58 +04:00
}
}
2006-07-11 22:45:22 +04:00
TALLOC_FREE ( ctx ) ;
/* Now loop through the keytab and update any other existing entries... */
kvno = ( krb5_kvno ) ads_get_kvno ( ads , machine_name ) ;
2004-06-18 01:39:51 +04:00
if ( kvno = = - 1 ) {
2004-06-19 03:15:42 +04:00
DEBUG ( 1 , ( " ads_keytab_create_default: ads_get_kvno failed to determine the system's kvno. \n " ) ) ;
2004-06-18 01:39:51 +04:00
return - 1 ;
}
2006-07-11 22:45:22 +04:00
DEBUG ( 3 , ( " ads_keytab_create_default: Searching for keytab entries to "
" preserve and update. \n " ) ) ;
2004-06-19 03:15:42 +04:00
ZERO_STRUCT ( kt_entry ) ;
2004-06-24 23:48:52 +04:00
ZERO_STRUCT ( cursor ) ;
2004-06-19 03:15:42 +04:00
2004-06-18 01:39:51 +04:00
initialize_krb5_error_table ( ) ;
ret = krb5_init_context ( & context ) ;
if ( ret ) {
2004-06-19 03:15:42 +04:00
DEBUG ( 1 , ( " ads_keytab_create_default: could not krb5_init_context: %s \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
return ret ;
}
ret = krb5_kt_default ( context , & keytab ) ;
if ( ret ) {
2004-06-19 03:15:42 +04:00
DEBUG ( 1 , ( " ads_keytab_create_default: krb5_kt_default failed (%s) \n " , error_message ( ret ) ) ) ;
goto done ;
2004-06-18 01:39:51 +04:00
}
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( ret ! = KRB5_KT_END & & ret ! = ENOENT ) {
2004-06-19 03:15:42 +04:00
while ( ( ret = krb5_kt_next_entry ( context , keytab , & kt_entry , & cursor ) ) = = 0 ) {
2004-06-24 09:56:44 +04:00
smb_krb5_kt_free_entry ( context , & kt_entry ) ;
2004-06-19 03:15:42 +04:00
ZERO_STRUCT ( kt_entry ) ;
2004-06-18 01:39:51 +04:00
found + + ;
}
}
2004-06-19 03:15:42 +04:00
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
2004-06-24 23:48:52 +04:00
ZERO_STRUCT ( cursor ) ;
2004-06-18 01:39:51 +04:00
2004-06-19 03:15:42 +04:00
/*
* Hmmm . There is no " rewind " function for the keytab . This means we have a race condition
* where someone else could add entries after we ' ve counted them . Re - open asap to minimise
* the race . JRA .
*/
DEBUG ( 3 , ( " ads_keytab_create_default: Found %d entries in the keytab. \n " , found ) ) ;
2004-06-18 01:39:51 +04:00
if ( ! found ) {
goto done ;
}
2004-12-07 21:25:53 +03:00
oldEntries = SMB_MALLOC_ARRAY ( char * , found ) ;
2004-06-18 01:39:51 +04:00
if ( ! oldEntries ) {
2004-06-19 03:15:42 +04:00
DEBUG ( 1 , ( " ads_keytab_create_default: Failed to allocate space to store the old keytab entries (malloc failed?). \n " ) ) ;
ret = - 1 ;
goto done ;
2004-06-18 01:39:51 +04:00
}
2004-06-19 03:15:42 +04:00
memset ( oldEntries , ' \0 ' , found * sizeof ( char * ) ) ;
2004-06-18 01:39:51 +04:00
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( ret ! = KRB5_KT_END & & ret ! = ENOENT ) {
2004-07-07 03:42:58 +04:00
while ( krb5_kt_next_entry ( context , keytab , & kt_entry , & cursor ) = = 0 ) {
2004-06-19 03:15:42 +04:00
if ( kt_entry . vno ! = kvno ) {
2004-06-19 04:54:54 +04:00
char * ktprinc = NULL ;
2004-06-19 03:15:42 +04:00
char * p ;
/* This returns a malloc'ed string in ktprinc. */
2006-04-24 19:57:54 +04:00
ret = smb_krb5_unparse_name ( context , kt_entry . principal , & ktprinc ) ;
2004-06-19 03:15:42 +04:00
if ( ret ) {
2006-04-24 19:57:54 +04:00
DEBUG ( 1 , ( " smb_krb5_unparse_name failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-21 23:10:25 +04:00
goto done ;
2004-06-19 03:15:42 +04:00
}
/*
* From looking at the krb5 source they don ' t seem to take locale
* or mb strings into account . Maybe this is because they assume utf8 ?
* In this case we may need to convert from utf8 to mb charset here ? JRA .
*/
2004-10-30 04:34:58 +04:00
p = strchr_m ( ktprinc , ' @ ' ) ;
if ( p ) {
* p = ' \0 ' ;
}
2004-06-19 03:15:42 +04:00
p = strchr_m ( ktprinc , ' / ' ) ;
if ( p ) {
* p = ' \0 ' ;
2004-06-18 01:39:51 +04:00
}
for ( i = 0 ; i < found ; i + + ) {
if ( ! oldEntries [ i ] ) {
oldEntries [ i ] = ktprinc ;
break ;
}
if ( ! strcmp ( oldEntries [ i ] , ktprinc ) ) {
2006-04-24 19:57:54 +04:00
SAFE_FREE ( ktprinc ) ;
2004-06-18 01:39:51 +04:00
break ;
}
}
2004-06-23 04:20:31 +04:00
if ( i = = found ) {
2006-04-24 19:57:54 +04:00
SAFE_FREE ( ktprinc ) ;
2004-06-23 04:20:31 +04:00
}
2004-06-18 01:39:51 +04:00
}
2004-06-24 09:56:44 +04:00
smb_krb5_kt_free_entry ( context , & kt_entry ) ;
2004-06-19 03:15:42 +04:00
ZERO_STRUCT ( kt_entry ) ;
2004-06-18 01:39:51 +04:00
}
2004-07-07 03:42:58 +04:00
ret = 0 ;
2004-06-18 01:39:51 +04:00
for ( i = 0 ; oldEntries [ i ] ; i + + ) {
2004-06-22 04:48:59 +04:00
ret | = ads_keytab_add_entry ( ads , oldEntries [ i ] ) ;
2006-04-24 19:57:54 +04:00
SAFE_FREE ( oldEntries [ i ] ) ;
2004-06-18 01:39:51 +04:00
}
2004-06-19 03:15:42 +04:00
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
2004-06-18 01:39:51 +04:00
}
2004-06-24 23:48:52 +04:00
ZERO_STRUCT ( cursor ) ;
2004-06-18 01:39:51 +04:00
done :
2004-06-19 03:15:42 +04:00
SAFE_FREE ( oldEntries ) ;
{
krb5_keytab_entry zero_kt_entry ;
ZERO_STRUCT ( zero_kt_entry ) ;
if ( memcmp ( & zero_kt_entry , & kt_entry , sizeof ( krb5_keytab_entry ) ) ) {
2004-06-24 09:56:44 +04:00
smb_krb5_kt_free_entry ( context , & kt_entry ) ;
2004-06-19 03:15:42 +04:00
}
}
2004-06-24 23:48:52 +04:00
{
krb5_kt_cursor zero_csr ;
ZERO_STRUCT ( zero_csr ) ;
if ( ( memcmp ( & cursor , & zero_csr , sizeof ( krb5_kt_cursor ) ) ! = 0 ) & & keytab ) {
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
}
2004-06-19 03:15:42 +04:00
}
if ( keytab ) {
krb5_kt_close ( context , keytab ) ;
}
if ( context ) {
krb5_free_context ( context ) ;
}
2004-06-18 01:39:51 +04:00
return ret ;
}
2007-04-23 12:40:54 +04:00
/**********************************************************************
List system keytab .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-06-29 13:01:29 +04:00
int ads_keytab_list ( const char * keytab_name )
2007-04-23 12:40:54 +04:00
{
krb5_error_code ret = 0 ;
krb5_context context = NULL ;
krb5_keytab keytab = NULL ;
krb5_kt_cursor cursor ;
krb5_keytab_entry kt_entry ;
ZERO_STRUCT ( kt_entry ) ;
ZERO_STRUCT ( cursor ) ;
initialize_krb5_error_table ( ) ;
ret = krb5_init_context ( & context ) ;
if ( ret ) {
DEBUG ( 1 , ( " ads_keytab_list: could not krb5_init_context: %s \n " , error_message ( ret ) ) ) ;
return ret ;
}
2007-06-29 12:56:35 +04:00
2007-06-29 13:01:29 +04:00
ret = smb_krb5_open_keytab ( context , keytab_name , False , & keytab ) ;
2007-04-23 12:40:54 +04:00
if ( ret ) {
2007-06-29 12:56:35 +04:00
DEBUG ( 1 , ( " ads_keytab_list: smb_krb5_open_keytab failed (%s) \n " , error_message ( ret ) ) ) ;
2007-04-23 12:40:54 +04:00
goto out ;
}
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( ret ) {
goto out ;
}
printf ( " Vno Type Principal \n " ) ;
while ( krb5_kt_next_entry ( context , keytab , & kt_entry , & cursor ) = = 0 ) {
char * princ_s = NULL ;
char * etype_s = NULL ;
krb5_enctype enctype = 0 ;
ret = smb_krb5_unparse_name ( context , kt_entry . principal , & princ_s ) ;
if ( ret ) {
goto out ;
}
enctype = smb_get_enctype_from_kt_entry ( & kt_entry ) ;
ret = smb_krb5_enctype_to_string ( context , enctype , & etype_s ) ;
if ( ret ) {
SAFE_FREE ( princ_s ) ;
goto out ;
}
printf ( " %3d %s \t \t %s \n " , kt_entry . vno , etype_s , princ_s ) ;
SAFE_FREE ( princ_s ) ;
SAFE_FREE ( etype_s ) ;
ret = smb_krb5_kt_free_entry ( context , & kt_entry ) ;
if ( ret ) {
goto out ;
}
}
ret = krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
if ( ret ) {
goto out ;
}
/* Ensure we don't double free. */
ZERO_STRUCT ( kt_entry ) ;
ZERO_STRUCT ( cursor ) ;
out :
{
krb5_keytab_entry zero_kt_entry ;
ZERO_STRUCT ( zero_kt_entry ) ;
if ( memcmp ( & zero_kt_entry , & kt_entry , sizeof ( krb5_keytab_entry ) ) ) {
smb_krb5_kt_free_entry ( context , & kt_entry ) ;
}
}
{
krb5_kt_cursor zero_csr ;
ZERO_STRUCT ( zero_csr ) ;
if ( ( memcmp ( & cursor , & zero_csr , sizeof ( krb5_kt_cursor ) ) ! = 0 ) & & keytab ) {
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
}
}
if ( keytab ) {
krb5_kt_close ( context , keytab ) ;
}
if ( context ) {
krb5_free_context ( context ) ;
}
return ret ;
}
2004-06-18 01:39:51 +04:00
# endif /* HAVE_KRB5 */