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
Copyright ( C ) Guenther Deschner 2003
Copyright ( C ) Rakesh Patel 2004
Copyright ( C ) Dan Perry 2004
2004-06-18 03:07:20 +04:00
Copyright ( C ) Jeremy Allison 2004
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
2004-06-18 03:07:20 +04:00
/**********************************************************************
2004-06-19 03:15:42 +04:00
Adds a single service principal , i . e . ' host ' to the system keytab
2004-06-18 03:07:20 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-22 04:48:59 +04:00
int ads_keytab_add_entry ( ADS_STRUCT * ads , const char * srvPrinc )
2004-06-18 01:39:51 +04:00
{
2004-06-18 03:07:20 +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 03:07:20 +04:00
krb5_keytab_entry kt_entry ;
krb5_principal princ = NULL ;
2004-06-18 01:39:51 +04:00
krb5_data password ;
krb5_enctype * enctypes = NULL ;
krb5_kvno kvno ;
char * principal = NULL ;
char * princ_s = NULL ;
char * password_s = NULL ;
2004-06-24 09:56:44 +04:00
# ifndef MAX_KEYTAB_NAME_LEN
# define MAX_KEYTAB_NAME_LEN 1100
# endif
2004-06-18 01:39:51 +04:00
char keytab_name [ MAX_KEYTAB_NAME_LEN ] ; /* This MAX_NAME_LEN is a constant defined in krb5.h */
2004-06-18 03:07:20 +04:00
fstring my_fqdn ;
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 ) ;
2004-06-18 01:39:51 +04:00
initialize_krb5_error_table ( ) ;
ret = krb5_init_context ( & context ) ;
if ( ret ) {
2004-06-18 03:07:20 +04:00
DEBUG ( 1 , ( " ads_keytab_add_entry: could not krb5_init_context: %s \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
return - 1 ;
}
# ifdef HAVE_WRFILE_KEYTAB /* MIT */
keytab_name [ 0 ] = ' W ' ;
keytab_name [ 1 ] = ' R ' ;
ret = krb5_kt_default_name ( context , ( char * ) & keytab_name [ 2 ] , MAX_KEYTAB_NAME_LEN - 4 ) ;
# else /* Heimdal */
ret = krb5_kt_default_name ( context , ( char * ) & keytab_name [ 0 ] , MAX_KEYTAB_NAME_LEN - 2 ) ;
# endif
if ( ret ) {
2004-06-18 03:07:20 +04:00
DEBUG ( 1 , ( " ads_keytab_add_entry: krb5_kt_default_name failed (%s) \n " , error_message ( ret ) ) ) ;
goto out ;
2004-06-18 01:39:51 +04:00
}
2004-06-18 03:07:20 +04:00
DEBUG ( 2 , ( " ads_keytab_add_entry: Using default system keytab: %s \n " , ( char * ) & keytab_name ) ) ;
2004-06-18 01:39:51 +04:00
ret = krb5_kt_resolve ( context , ( char * ) & keytab_name , & keytab ) ;
if ( ret ) {
2004-06-18 03:07:20 +04:00
DEBUG ( 1 , ( " ads_keytab_add_entry: krb5_kt_resolve failed (%s) \n " , error_message ( ret ) ) ) ;
goto out ;
2004-06-18 01:39:51 +04:00
}
/* retrieve the password */
if ( ! secrets_init ( ) ) {
2004-06-18 03:07:20 +04:00
DEBUG ( 1 , ( " ads_keytab_add_entry: secrets_init failed \n " ) ) ;
2004-06-18 01:39:51 +04:00
ret = - 1 ;
goto out ;
}
password_s = secrets_fetch_machine_password ( lp_workgroup ( ) , NULL , NULL ) ;
if ( ! password_s ) {
2004-06-18 03:07:20 +04:00
DEBUG ( 1 , ( " ads_keytab_add_entry: failed to fetch machine password \n " ) ) ;
2004-06-18 01:39:51 +04:00
ret = - 1 ;
goto out ;
}
password . data = password_s ;
password . length = strlen ( password_s ) ;
/* Construct our principal */
2004-06-18 03:07:20 +04:00
name_to_fqdn ( my_fqdn , global_myname ( ) ) ;
strlower_m ( my_fqdn ) ;
2004-10-30 04:34:58 +04:00
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 ( ) ) ;
/* Update the directory with the SPN */
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 ( ) , srvPrinc ) ) ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: ads_add_service_principal_name failed. \n " ) ) ;
goto out ;
}
}
ret = get_kerberos_allowed_etypes ( context , & enctypes ) ;
if ( ret ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: get_kerberos_allowed_etypes failed (%s) \n " , error_message ( ret ) ) ) ;
goto out ;
}
/* Guess at how the KDC is salting keys for this principal. */
2004-11-03 00:28:14 +03:00
kerberos_derive_salting_principal ( princ_s ) ;
2004-06-18 01:39:51 +04:00
ret = krb5_parse_name ( context , princ_s , & princ ) ;
if ( ret ) {
2004-06-18 03:07:20 +04:00
DEBUG ( 1 , ( " ads_keytab_add_entry: krb5_parse_name(%s) failed (%s) \n " , princ_s , 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 failure, everything else is OK */
2004-06-18 03:07:20 +04:00
DEBUG ( 1 , ( " ads_keytab_add_entry: ads_get_kvno failed to determine the system's kvno. \n " ) ) ;
2004-06-18 01:39:51 +04:00
ret = - 1 ;
goto out ;
}
/* Seek and delete old keytab entries */
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( ret ! = KRB5_KT_END & & ret ! = ENOENT ) {
2004-06-18 03:07:20 +04:00
DEBUG ( 3 , ( " ads_keytab_add_entry: Will try to delete old keytab entries \n " ) ) ;
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
2004-06-18 04:24:53 +04:00
ret = krb5_unparse_name ( context , kt_entry . principal , & ktprinc ) ;
2004-06-18 03:07:20 +04:00
if ( ret ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: krb5_unparse_name failed (%s) \n " , error_message ( ret ) ) ) ;
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 ) {
DEBUG ( 10 , ( " ads_keytab_add_entry: ignoring keytab entry principal %s, kvno = %d \n " ,
ktprinc , kt_entry . vno ) ) ;
}
2004-06-21 23:10:25 +04:00
krb5_free_unparsed_name ( context , ktprinc ) ;
2004-06-19 04:54:54 +04:00
ktprinc = NULL ;
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 ) {
DEBUG ( 5 , ( " ads_keytab_add_entry: Saving previous (kvno %d) entry for principal: %s. \n " ,
kvno - 1 , princ_s ) ) ;
} else {
DEBUG ( 5 , ( " ads_keytab_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it. \n " ,
princ_s , kt_entry . vno ) ) ;
ret = krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
ZERO_STRUCT ( cursor ) ;
if ( ret ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: krb5_kt_end_seq_get() failed (%s) \n " ,
error_message ( ret ) ) ) ;
goto out ;
}
ret = krb5_kt_remove_entry ( context , keytab , & kt_entry ) ;
if ( ret ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: krb5_kt_remove_entry failed (%s) \n " ,
error_message ( ret ) ) ) ;
goto out ;
}
DEBUG ( 5 , ( " ads_keytab_add_entry: removed old entry for principal: %s (kvno %d). \n " ,
princ_s , kt_entry . vno ) ) ;
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( ret ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: krb5_kt_start_seq failed (%s) \n " ,
error_message ( ret ) ) ) ;
goto out ;
}
ret = smb_krb5_kt_free_entry ( context , & kt_entry ) ;
ZERO_STRUCT ( kt_entry ) ;
if ( ret ) {
DEBUG ( 1 , ( " ads_keytab_add_entry: krb5_kt_remove_entry failed (%s) \n " ,
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 ) {
2004-06-24 09:56:44 +04:00
DEBUG ( 1 , ( " ads_keytab_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 ) {
2004-06-18 04:24:53 +04:00
DEBUG ( 1 , ( " ads_keytab_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 ;
DEBUG ( 3 , ( " ads_keytab_add_entry: adding keytab entry for (%s) with encryption type (%d) and version (%d) \n " ,
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 ) {
2004-06-18 04:24:53 +04:00
DEBUG ( 1 , ( " ads_keytab_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
krb5_kt_close ( context , keytab ) ;
keytab = NULL ; /* Done with keytab now. No double free. */
2004-06-18 01:39:51 +04:00
out :
2004-06-18 03:07:20 +04:00
SAFE_FREE ( principal ) ;
SAFE_FREE ( password_s ) ;
SAFE_FREE ( princ_s ) ;
{
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 ) ;
}
2004-06-18 01:39:51 +04:00
if ( enctypes ) {
2004-06-18 03:07:20 +04:00
free_kerberos_etypes ( context , enctypes ) ;
2004-06-18 01:39:51 +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
}
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 ;
char keytab_name [ MAX_KEYTAB_NAME_LEN ] ;
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 ;
}
# ifdef HAVE_WRFILE_KEYTAB
keytab_name [ 0 ] = ' W ' ;
keytab_name [ 1 ] = ' R ' ;
ret = krb5_kt_default_name ( context , ( char * ) & keytab_name [ 2 ] , MAX_KEYTAB_NAME_LEN - 4 ) ;
# else
ret = krb5_kt_default_name ( context , ( char * ) & keytab_name [ 0 ] , MAX_KEYTAB_NAME_LEN - 2 ) ;
# endif
if ( ret ) {
2004-06-18 06:07:42 +04:00
DEBUG ( 1 , ( " ads_keytab_flush: krb5_kt_default failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
2004-06-18 06:07:42 +04:00
DEBUG ( 3 , ( " ads_keytab_flush: Using default keytab: %s \n " , ( char * ) & keytab_name ) ) ;
2004-06-18 01:39:51 +04:00
ret = krb5_kt_resolve ( context , ( char * ) & keytab_name , & keytab ) ;
if ( ret ) {
2004-06-18 06:07:42 +04:00
DEBUG ( 1 , ( " ads_keytab_flush: krb5_kt_default failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
ret = krb5_kt_resolve ( context , ( char * ) & keytab_name , & keytab ) ;
if ( ret ) {
2004-06-18 06:07:42 +04:00
DEBUG ( 1 , ( " ads_keytab_flush: krb5_kt_default 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 ;
2005-03-11 23:59:16 +03:00
fstring my_fqdn , my_Fqdn , my_name , my_NAME , my_host_realm ;
2004-10-30 05:32:05 +04:00
char * p_fqdn ;
2004-06-18 01:39:51 +04:00
int i , found = 0 ;
2005-03-11 23:59:16 +03:00
char * * oldEntries = NULL , * princ_s [ 26 ] ;
memset ( princ_s , ' \0 ' , sizeof ( princ_s ) ) ;
2004-06-18 01:39:51 +04:00
2004-06-22 04:48:59 +04:00
ret = ads_keytab_add_entry ( ads , " host " ) ;
2004-06-18 01:39:51 +04:00
if ( ret ) {
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 ;
}
2004-06-22 04:48:59 +04:00
ret = ads_keytab_add_entry ( ads , " cifs " ) ;
2004-06-18 01:39:51 +04:00
if ( ret ) {
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 ;
}
2004-10-30 04:34:58 +04:00
fstrcpy ( my_name , global_myname ( ) ) ;
strlower_m ( my_name ) ;
2004-10-30 05:32:05 +04:00
2004-10-30 04:34:58 +04:00
fstrcpy ( my_NAME , global_myname ( ) ) ;
strupper_m ( my_NAME ) ;
2004-10-30 05:32:05 +04:00
my_fqdn [ 0 ] = ' \0 ' ;
2004-10-30 04:34:58 +04:00
name_to_fqdn ( my_fqdn , global_myname ( ) ) ;
strlower_m ( my_fqdn ) ;
2004-10-30 05:32:05 +04:00
p_fqdn = strchr_m ( my_fqdn , ' . ' ) ;
fstrcpy ( my_Fqdn , my_NAME ) ;
if ( p_fqdn ) {
fstrcat ( my_Fqdn , p_fqdn ) ;
}
2005-03-11 23:59:16 +03:00
fstrcpy ( my_host_realm , my_name ) ;
fstrcat ( my_host_realm , " . " ) ;
fstrcat ( my_host_realm , lp_realm ( ) ) ;
strlower_m ( my_host_realm ) ;
2004-10-30 04:34:58 +04:00
asprintf ( & princ_s [ 0 ] , " %s$@%s " , my_name , lp_realm ( ) ) ;
asprintf ( & princ_s [ 1 ] , " %s$@%s " , my_NAME , lp_realm ( ) ) ;
asprintf ( & princ_s [ 2 ] , " host/%s@%s " , my_name , lp_realm ( ) ) ;
asprintf ( & princ_s [ 3 ] , " host/%s@%s " , my_NAME , lp_realm ( ) ) ;
asprintf ( & princ_s [ 4 ] , " host/%s@%s " , my_fqdn , lp_realm ( ) ) ;
asprintf ( & princ_s [ 5 ] , " host/%s@%s " , my_Fqdn , lp_realm ( ) ) ;
asprintf ( & princ_s [ 6 ] , " HOST/%s@%s " , my_name , lp_realm ( ) ) ;
asprintf ( & princ_s [ 7 ] , " HOST/%s@%s " , my_NAME , lp_realm ( ) ) ;
asprintf ( & princ_s [ 8 ] , " HOST/%s@%s " , my_fqdn , lp_realm ( ) ) ;
asprintf ( & princ_s [ 9 ] , " HOST/%s@%s " , my_Fqdn , lp_realm ( ) ) ;
asprintf ( & princ_s [ 10 ] , " cifs/%s@%s " , my_name , lp_realm ( ) ) ;
asprintf ( & princ_s [ 11 ] , " cifs/%s@%s " , my_NAME , lp_realm ( ) ) ;
asprintf ( & princ_s [ 12 ] , " cifs/%s@%s " , my_fqdn , lp_realm ( ) ) ;
asprintf ( & princ_s [ 13 ] , " cifs/%s@%s " , my_Fqdn , lp_realm ( ) ) ;
asprintf ( & princ_s [ 14 ] , " CIFS/%s@%s " , my_name , lp_realm ( ) ) ;
asprintf ( & princ_s [ 15 ] , " CIFS/%s@%s " , my_NAME , lp_realm ( ) ) ;
asprintf ( & princ_s [ 16 ] , " CIFS/%s@%s " , my_fqdn , lp_realm ( ) ) ;
asprintf ( & princ_s [ 17 ] , " CIFS/%s@%s " , my_Fqdn , lp_realm ( ) ) ;
2005-03-11 23:59:16 +03:00
asprintf ( & princ_s [ 18 ] , " cifs/%s.%s@%s " , my_name , lp_realm ( ) , lp_realm ( ) ) ;
asprintf ( & princ_s [ 19 ] , " CIFS/%s.%s@%s " , my_name , lp_realm ( ) , lp_realm ( ) ) ;
asprintf ( & princ_s [ 20 ] , " host/%s.%s@%s " , my_name , lp_realm ( ) , lp_realm ( ) ) ;
asprintf ( & princ_s [ 21 ] , " HOST/%s.%s@%s " , my_name , lp_realm ( ) , lp_realm ( ) ) ;
/* when dnsdomain == realm, don't add duplicate principal */
if ( ! strequal ( my_host_realm , my_fqdn ) ) {
asprintf ( & princ_s [ 22 ] , " cifs/%s@%s " , my_host_realm , lp_realm ( ) ) ;
asprintf ( & princ_s [ 23 ] , " CIFS/%s@%s " , my_host_realm , lp_realm ( ) ) ;
asprintf ( & princ_s [ 24 ] , " host/%s@%s " , my_host_realm , lp_realm ( ) ) ;
asprintf ( & princ_s [ 25 ] , " HOST/%s@%s " , my_host_realm , lp_realm ( ) ) ;
}
2004-10-30 04:34:58 +04:00
for ( i = 0 ; i < sizeof ( princ_s ) / sizeof ( princ_s [ 0 ] ) ; i + + ) {
if ( princ_s [ i ] ! = NULL ) {
ret = ads_keytab_add_entry ( ads , princ_s [ i ] ) ;
if ( ret ! = 0 ) {
DEBUG ( 1 , ( " ads_keytab_create_default: ads_keytab_add_entry failed while adding '%s'. \n " , princ_s [ i ] ) ) ;
}
SAFE_FREE ( princ_s [ i ] ) ;
}
}
2004-06-18 01:39:51 +04:00
kvno = ( krb5_kvno ) ads_get_kvno ( ads , global_myname ( ) ) ;
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 ;
}
2004-06-19 03:15:42 +04:00
DEBUG ( 3 , ( " ads_keytab_create_default: Searching for keytab entries to preserve and update. \n " ) ) ;
2004-06-18 01:39:51 +04:00
/* Now loop through the keytab and update any other existing entries... */
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. */
ret = krb5_unparse_name ( context , kt_entry . principal , & ktprinc ) ;
if ( ret ) {
DEBUG ( 1 , ( " 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 ) ) {
2004-06-23 04:20:31 +04:00
krb5_free_unparsed_name ( context , ktprinc ) ;
2004-06-18 01:39:51 +04:00
break ;
}
}
2004-06-23 04:20:31 +04:00
if ( i = = found ) {
krb5_free_unparsed_name ( context , ktprinc ) ;
}
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 ] ) ;
2004-06-21 23:10:25 +04:00
krb5_free_unparsed_name ( context , 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 ;
}
# endif /* HAVE_KRB5 */