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 13:42:14 +04:00
Copyright ( C ) Guenther Deschner 2003
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2004-06-18 01:39:51 +04: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/>.
2004-06-18 01:39:51 +04:00
*/
# include "includes.h"
2009-11-27 17:52:57 +03:00
# include "smb_krb5.h"
2010-07-02 02:32:52 +04:00
# include "ads.h"
2010-08-05 04:25:37 +04:00
# include "secrets.h"
2004-06-18 01:39:51 +04:00
# ifdef HAVE_KRB5
2004-06-18 03:07:20 +04:00
/**********************************************************************
2006-07-11 22:45:22 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-18 03:07:20 +04:00
2010-08-18 12:16:41 +04:00
static krb5_error_code seek_and_delete_old_entries ( krb5_context context ,
krb5_keytab keytab ,
krb5_kvno kvno ,
const char * princ_s ,
krb5_principal princ ,
bool flush ,
bool keep_old_entries )
2004-06-18 01:39:51 +04:00
{
2010-08-18 12:16:41 +04:00
krb5_error_code ret ;
2004-06-24 23:48:52 +04:00
krb5_kt_cursor cursor ;
2010-08-18 12:16:41 +04:00
krb5_kt_cursor zero_csr ;
2004-06-18 03:07:20 +04:00
krb5_keytab_entry kt_entry ;
2010-08-18 12:16:41 +04:00
krb5_keytab_entry zero_kt_entry ;
2004-06-18 01:39:51 +04:00
char * ktprinc = NULL ;
2004-06-24 23:48:52 +04:00
ZERO_STRUCT ( cursor ) ;
2010-08-18 12:16:41 +04:00
ZERO_STRUCT ( zero_csr ) ;
ZERO_STRUCT ( kt_entry ) ;
ZERO_STRUCT ( zero_kt_entry ) ;
2004-06-18 01:39:51 +04:00
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
2010-08-19 15:35:01 +04:00
if ( ret = = KRB5_KT_END | | ret = = ENOENT ) {
2010-08-18 12:16:41 +04:00
/* no entries */
return 0 ;
}
DEBUG ( 3 , ( __location__ " : Will try to delete old keytab entries \n " ) ) ;
while ( ! krb5_kt_next_entry ( context , keytab , & kt_entry , & cursor ) ) {
bool name_ok = False ;
2004-06-18 01:39:51 +04:00
2010-08-18 12:16:41 +04:00
if ( ! flush & & ( princ_s ! = NULL ) ) {
ret = smb_krb5_unparse_name ( talloc_tos ( ) , context ,
kt_entry . principal ,
& ktprinc ) ;
2004-06-18 03:07:20 +04:00
if ( ret ) {
2010-08-18 12:16:41 +04:00
DEBUG ( 1 , ( __location__
" : smb_krb5_unparse_name failed "
" (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 03:07:20 +04:00
goto out ;
}
2004-06-18 01:39:51 +04:00
# ifdef HAVE_KRB5_KT_COMPARE
2010-08-18 12:16:41 +04:00
name_ok = krb5_kt_compare ( context , & kt_entry ,
princ , 0 , 0 ) ;
2004-06-18 01:39:51 +04:00
# else
2010-08-18 12:16:41 +04:00
name_ok = ( strcmp ( ktprinc , princ_s ) = = 0 ) ;
2004-06-18 01:39:51 +04:00
# endif
2004-11-03 05:18:51 +03:00
2010-08-18 12:16:41 +04:00
if ( ! name_ok ) {
DEBUG ( 10 , ( __location__ " : ignoring keytab "
" entry principal %s, kvno = %d \n " ,
ktprinc , kt_entry . vno ) ) ;
/* Not a match,
* just free this entry and continue . */
ret = smb_krb5_kt_free_entry ( context ,
& kt_entry ) ;
ZERO_STRUCT ( kt_entry ) ;
if ( ret ) {
DEBUG ( 1 , ( __location__
" : smb_krb5_kt_free_entry "
" failed (%s) \n " ,
error_message ( ret ) ) ) ;
goto out ;
}
TALLOC_FREE ( ktprinc ) ;
continue ;
2004-11-03 05:18:51 +03:00
}
2009-03-18 08:23:27 +03:00
TALLOC_FREE ( ktprinc ) ;
2010-08-18 12:16:41 +04:00
}
2004-06-18 04:24:53 +04:00
2010-08-18 12:16:41 +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 .
*/
if ( ! flush & & ( kt_entry . vno = = kvno - 1 ) ) {
DEBUG ( 5 , ( __location__ " : Saving previous (kvno %d) "
" entry for principal: %s. \n " ,
kvno - 1 , princ_s ) ) ;
continue ;
}
2004-06-18 01:39:51 +04:00
2010-08-18 12:16:41 +04:00
if ( keep_old_entries ) {
DEBUG ( 5 , ( __location__ " : Saving old (kvno %d) "
" entry for principal: %s. \n " ,
kvno , princ_s ) ) ;
continue ;
2004-06-18 01:39:51 +04:00
}
2010-08-18 12:16:41 +04:00
DEBUG ( 5 , ( __location__ " : Found old entry for principal: %s "
" (kvno %d) - trying to remove it. \n " ,
princ_s , kt_entry . vno ) ) ;
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 ) {
2010-08-18 12:16:41 +04:00
DEBUG ( 1 , ( __location__ " : krb5_kt_end_seq_get() "
" failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
2010-08-18 12:16:41 +04:00
ret = krb5_kt_remove_entry ( context , keytab , & kt_entry ) ;
if ( ret ) {
DEBUG ( 1 , ( __location__ " : krb5_kt_remove_entry() "
" failed (%s) \n " , error_message ( ret ) ) ) ;
goto out ;
}
DEBUG ( 5 , ( __location__ " : 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 , ( __location__ " : 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 , ( __location__ " : krb5_kt_remove_entry() "
" failed (%s) \n " , error_message ( ret ) ) ) ;
goto out ;
}
}
out :
if ( memcmp ( & zero_kt_entry , & kt_entry , sizeof ( krb5_keytab_entry ) ) ) {
smb_krb5_kt_free_entry ( context , & kt_entry ) ;
}
if ( keytab ) {
if ( memcmp ( & cursor , & zero_csr , sizeof ( krb5_kt_cursor ) ) ! = 0 ) {
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
}
2004-06-18 01:39:51 +04:00
}
2010-08-18 12:16:41 +04:00
return ret ;
}
2010-08-18 17:36:54 +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 ,
bool no_salt ,
bool keep_old_entries )
2010-08-18 12:16:41 +04:00
{
krb5_error_code ret ;
krb5_keytab_entry kt_entry ;
krb5_principal princ = NULL ;
int i ;
2004-06-18 04:24:53 +04:00
ZERO_STRUCT ( kt_entry ) ;
2004-06-18 01:39:51 +04:00
2010-08-18 12:16:41 +04:00
ret = smb_krb5_parse_name ( context , princ_s , & princ ) ;
if ( ret ) {
DEBUG ( 1 , ( __location__ " : smb_krb5_parse_name(%s) "
" failed (%s) \n " , princ_s , error_message ( ret ) ) ) ;
goto out ;
}
/* Seek and delete old keytab entries */
ret = seek_and_delete_old_entries ( context , keytab , kvno ,
princ_s , princ , false ,
keep_old_entries ) ;
if ( ret ) {
goto out ;
}
/* 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
2008-08-22 16:58:01 +04:00
keyp = KRB5_KT_KEY ( & kt_entry ) ;
2010-08-18 12:16:41 +04:00
if ( create_kerberos_key_from_string ( context , princ ,
& password , keyp ,
enctypes [ i ] , no_salt ) ) {
2004-06-18 04:24:53 +04:00
continue ;
}
kt_entry . principal = princ ;
kt_entry . vno = kvno ;
2010-08-18 12:16:41 +04:00
DEBUG ( 3 , ( __location__ " : adding keytab entry for (%s) with "
" encryption type (%d) and version (%d) \n " ,
princ_s , enctypes [ i ] , kt_entry . vno ) ) ;
2004-06-18 04:24:53 +04:00
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 ) {
2010-08-18 12:16:41 +04:00
DEBUG ( 1 , ( __location__ " : adding entry to keytab "
" failed (%s) \n " , error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
}
out :
2004-06-18 03:07:20 +04:00
if ( princ ) {
krb5_free_principal ( context , princ ) ;
}
2010-08-18 12:16:41 +04:00
2006-07-11 22:45:22 +04:00
return ( int ) ret ;
}
2011-04-15 14:37:55 +04:00
# ifdef HAVE_ADS
2006-07-11 22:45:22 +04:00
/**********************************************************************
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 ;
2010-08-18 12:33:32 +04:00
krb5_enctype enctypes [ 4 ] = {
ENCTYPE_DES_CBC_CRC ,
ENCTYPE_DES_CBC_MD5 ,
ENCTYPE_ARCFOUR_HMAC ,
0
} ;
char * princ_s = NULL ;
char * short_princ_s = NULL ;
2006-07-11 22:45:22 +04:00
char * password_s = NULL ;
char * my_fqdn ;
2010-08-18 12:33:32 +04:00
TALLOC_CTX * tmpctx = NULL ;
2006-07-11 22:45:22 +04:00
char * machine_name ;
2010-08-18 12:33:32 +04:00
ADS_STATUS aderr ;
2006-07-11 22:45:22 +04:00
initialize_krb5_error_table ( ) ;
ret = krb5_init_context ( & context ) ;
if ( ret ) {
2010-08-18 12:33:32 +04:00
DEBUG ( 1 , ( __location__ " : could not krb5_init_context: %s \n " ,
error_message ( ret ) ) ) ;
2006-07-11 22:45:22 +04:00
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 ) {
2010-08-18 12:33:32 +04:00
DEBUG ( 1 , ( __location__ " : 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 ( ) ) {
2010-08-18 12:33:32 +04:00
DEBUG ( 1 , ( __location__ " : secrets_init failed \n " ) ) ;
2006-07-11 22:45:22 +04:00
ret = - 1 ;
goto out ;
}
password_s = secrets_fetch_machine_password ( lp_workgroup ( ) , NULL , NULL ) ;
if ( ! password_s ) {
2010-08-18 12:33:32 +04:00
DEBUG ( 1 , ( __location__ " : failed to fetch machine password \n " ) ) ;
2006-07-11 22:45:22 +04:00
ret = - 1 ;
goto out ;
}
2008-07-31 03:06:30 +04:00
ZERO_STRUCT ( password ) ;
2006-07-11 22:45:22 +04:00
password . data = password_s ;
password . length = strlen ( password_s ) ;
/* we need the dNSHostName value here */
2010-08-18 12:33:32 +04:00
tmpctx = talloc_init ( __location__ ) ;
if ( ! tmpctx ) {
DEBUG ( 0 , ( __location__ " : talloc_init() failed! \n " ) ) ;
2006-07-11 22:45:22 +04:00
ret = - 1 ;
goto out ;
}
2010-08-18 12:33:32 +04:00
2011-06-09 09:31:03 +04:00
my_fqdn = ads_get_dnshostname ( ads , tmpctx , lp_netbios_name ( ) ) ;
2010-08-18 12:33:32 +04:00
if ( ! my_fqdn ) {
DEBUG ( 0 , ( __location__ " : unable to determine machine "
" account's dns name in AD! \n " ) ) ;
2006-07-11 22:45:22 +04:00
ret = - 1 ;
2010-08-18 12:33:32 +04:00
goto out ;
2006-07-11 22:45:22 +04:00
}
2010-08-18 12:33:32 +04:00
2011-06-09 09:31:03 +04:00
machine_name = ads_get_samaccountname ( ads , tmpctx , lp_netbios_name ( ) ) ;
2010-08-18 12:33:32 +04:00
if ( ! machine_name ) {
DEBUG ( 0 , ( __location__ " : unable to determine machine "
" account's short name in AD! \n " ) ) ;
2006-07-11 22:45:22 +04:00
ret = - 1 ;
2010-08-18 12:33:32 +04:00
goto out ;
2006-07-11 22:45:22 +04:00
}
/*strip the trailing '$' */
machine_name [ strlen ( machine_name ) - 1 ] = ' \0 ' ;
2010-08-18 12:33:32 +04:00
/* Construct our principal */
2006-07-11 22:45:22 +04:00
if ( strchr_m ( srvPrinc , ' @ ' ) ) {
/* It's a fully-named principal. */
2010-08-18 12:33:32 +04:00
princ_s = talloc_asprintf ( tmpctx , " %s " , srvPrinc ) ;
if ( ! princ_s ) {
2008-12-23 22:56:48 +03:00
ret = - 1 ;
goto out ;
}
2006-07-11 22:45:22 +04:00
} else if ( srvPrinc [ strlen ( srvPrinc ) - 1 ] = = ' $ ' ) {
/* It's the machine account, as used by smbclient clients. */
2010-08-18 12:33:32 +04:00
princ_s = talloc_asprintf ( tmpctx , " %s@%s " ,
srvPrinc , lp_realm ( ) ) ;
if ( ! princ_s ) {
2008-12-23 22:56:48 +03:00
ret = - 1 ;
goto out ;
}
2006-07-11 22:45:22 +04:00
} 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 . */
2010-08-18 12:33:32 +04:00
princ_s = talloc_asprintf ( tmpctx , " %s/%s@%s " ,
srvPrinc , my_fqdn , lp_realm ( ) ) ;
if ( ! princ_s ) {
2008-12-23 22:56:48 +03:00
ret = - 1 ;
goto out ;
}
2010-08-18 12:33:32 +04:00
short_princ_s = talloc_asprintf ( tmpctx , " %s/%s@%s " ,
srvPrinc , machine_name ,
lp_realm ( ) ) ;
if ( ! princ_s ) {
2008-12-23 22:56:48 +03:00
ret = - 1 ;
goto out ;
}
2010-08-18 12:33:32 +04:00
/* 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 , ( __location__ " : Attempting to add/update "
" '%s' \n " , princ_s ) ) ;
aderr = ads_add_service_principal_name ( ads ,
2011-06-09 09:31:03 +04:00
lp_netbios_name ( ) , my_fqdn , srvPrinc ) ;
2010-08-18 12:33:32 +04:00
if ( ! ADS_ERR_OK ( aderr ) ) {
DEBUG ( 1 , ( __location__ " : failed to "
" ads_add_service_principal_name. \n " ) ) ;
2006-07-11 22:45:22 +04:00
goto out ;
}
}
}
2011-06-09 09:31:03 +04:00
kvno = ( krb5_kvno ) ads_get_machine_kvno ( ads , lp_netbios_name ( ) ) ;
2010-08-18 12:33:32 +04:00
if ( kvno = = - 1 ) {
/* -1 indicates failure, everything else is OK */
DEBUG ( 1 , ( __location__ " : ads_get_machine_kvno failed to "
" determine the system's kvno. \n " ) ) ;
2006-07-11 22:45:22 +04:00
ret = - 1 ;
goto out ;
}
2010-08-18 12:33:32 +04:00
2006-07-11 22:45:22 +04:00
/* add the fqdn principal to the keytab */
2010-08-18 12:33:32 +04:00
ret = smb_krb5_kt_add_entry ( context , keytab , kvno ,
2010-08-18 17:36:54 +04:00
princ_s , enctypes , password ,
false , false ) ;
2010-08-18 12:33:32 +04:00
if ( ret ) {
DEBUG ( 1 , ( __location__ " : Failed to add entry to keytab \n " ) ) ;
2006-07-11 22:45:22 +04:00
goto out ;
}
2010-08-18 12:33:32 +04:00
2006-07-11 22:45:22 +04:00
/* add the short principal name if we have one */
2010-08-18 12:33:32 +04:00
if ( short_princ_s ) {
ret = smb_krb5_kt_add_entry ( context , keytab , kvno ,
2010-08-18 17:36:54 +04:00
short_princ_s , enctypes , password ,
false , false ) ;
2010-08-18 12:33:32 +04:00
if ( ret ) {
DEBUG ( 1 , ( __location__
" : Failed to add short entry to keytab \n " ) ) ;
2006-07-11 22:45:22 +04:00
goto out ;
}
}
out :
2010-08-18 12:33:32 +04:00
TALLOC_FREE ( tmpctx ) ;
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-18 01:39:51 +04:00
krb5_kvno kvno ;
2010-08-18 12:16:41 +04:00
ADS_STATUS aderr ;
2004-06-24 23:48:52 +04:00
2004-06-18 01:39:51 +04:00
initialize_krb5_error_table ( ) ;
ret = krb5_init_context ( & context ) ;
if ( ret ) {
2010-08-18 12:16:41 +04:00
DEBUG ( 1 , ( __location__ " : 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 ) {
2010-08-18 12:16:41 +04:00
DEBUG ( 1 , ( __location__ " : smb_krb5_open_keytab failed (%s) \n " ,
error_message ( ret ) ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
2011-06-09 09:31:03 +04:00
kvno = ( krb5_kvno ) ads_get_machine_kvno ( ads , lp_netbios_name ( ) ) ;
2010-08-18 12:16:41 +04:00
if ( kvno = = - 1 ) {
/* -1 indicates a failure */
DEBUG ( 1 , ( __location__ " : Error determining the kvno. \n " ) ) ;
2004-06-18 01:39:51 +04:00
goto out ;
}
2010-08-18 12:16:41 +04:00
/* Seek and delete old keytab entries */
ret = seek_and_delete_old_entries ( context , keytab , kvno ,
NULL , NULL , true , false ) ;
if ( ret ) {
goto out ;
2004-06-18 01:39:51 +04:00
}
2004-06-19 03:15:42 +04:00
2011-06-09 09:31:03 +04:00
aderr = ads_clear_service_principal_names ( ads , lp_netbios_name ( ) ) ;
2010-08-18 12:16:41 +04:00
if ( ! ADS_ERR_OK ( aderr ) ) {
DEBUG ( 1 , ( __location__ " : 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
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 ] ;
2010-08-18 14:09:27 +04:00
TALLOC_CTX * tmpctx = NULL ;
char * machine_name ;
2006-07-11 22:45:22 +04:00
/* these are the main ones we need */
2010-08-18 14:09:27 +04:00
ret = ads_keytab_add_entry ( ads , " host " ) ;
if ( ret ! = 0 ) {
DEBUG ( 1 , ( __location__ " : ads_keytab_add_entry failed while "
" adding 'host' principal. \n " ) ) ;
2004-06-18 01:39:51 +04:00
return ret ;
}
2006-07-11 22:45:22 +04:00
2010-08-18 14:09:27 +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 */
ret = ads_keytab_add_entry ( ads , " cifs " ) ) ;
if ( ret ! = 0 ) {
DEBUG ( 1 , ( __location__ " : 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
2010-08-18 14:09:27 +04:00
memset ( princ_s , ' \0 ' , sizeof ( princ_s ) ) ;
ZERO_STRUCT ( kt_entry ) ;
ZERO_STRUCT ( cursor ) ;
initialize_krb5_error_table ( ) ;
ret = krb5_init_context ( & context ) ;
if ( ret ) {
DEBUG ( 1 , ( __location__ " : could not krb5_init_context: %s \n " ,
error_message ( ret ) ) ) ;
return ret ;
2006-07-11 22:45:22 +04:00
}
2010-08-18 14:09:27 +04:00
tmpctx = talloc_init ( __location__ ) ;
if ( ! tmpctx ) {
DEBUG ( 0 , ( __location__ " : talloc_init() failed! \n " ) ) ;
ret = - 1 ;
goto done ;
}
2007-01-03 00:29:09 +03:00
2011-06-09 09:31:03 +04:00
machine_name = talloc_strdup ( tmpctx , lp_netbios_name ( ) ) ;
2010-08-18 14:09:27 +04:00
if ( ! machine_name ) {
ret = - 1 ;
goto done ;
2006-07-11 22:45:22 +04:00
}
2010-08-18 14:09:27 +04:00
/* now add the userPrincipalName and sAMAccountName entries */
sam_account_name = ads_get_samaccountname ( ads , tmpctx , machine_name ) ;
if ( ! sam_account_name ) {
DEBUG ( 0 , ( __location__ " : unable to determine machine "
" account's name in AD! \n " ) ) ;
ret = - 1 ;
goto done ;
}
2007-01-03 00:29:09 +03:00
2010-08-18 14:09:27 +04: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 ) ;
2007-01-03 00:29:09 +03:00
2010-08-18 14:09:27 +04:00
ret = ads_keytab_add_entry ( ads , sam_account_name ) ;
if ( ret ! = 0 ) {
DEBUG ( 1 , ( __location__ " : ads_keytab_add_entry() failed "
" while adding sAMAccountName (%s) \n " ,
sam_account_name ) ) ;
goto done ;
2006-07-11 22:45:22 +04:00
}
2010-08-18 14:09:27 +04:00
2006-07-11 22:45:22 +04:00
/* remember that not every machine account will have a upn */
2010-08-18 14:09:27 +04:00
upn = ads_get_upn ( ads , tmpctx , machine_name ) ;
if ( upn ) {
ret = ads_keytab_add_entry ( ads , upn ) ;
if ( ret ! = 0 ) {
DEBUG ( 1 , ( __location__ " : ads_keytab_add_entry() "
" failed while adding UPN (%s) \n " , upn ) ) ;
goto done ;
2004-10-30 04:34:58 +04:00
}
}
2010-08-18 14:09:27 +04:00
/* Now loop through the keytab and update any other existing entries */
kvno = ( krb5_kvno ) ads_get_machine_kvno ( ads , machine_name ) ;
2004-06-18 01:39:51 +04:00
if ( kvno = = - 1 ) {
2010-08-18 14:09:27 +04:00
DEBUG ( 1 , ( __location__ " : ads_get_machine_kvno() failed to "
" determine the system's kvno. \n " ) ) ;
goto done ;
2004-06-18 01:39:51 +04:00
}
2004-06-19 03:15:42 +04:00
2010-08-18 14:09:27 +04:00
DEBUG ( 3 , ( __location__ " : Searching for keytab entries to preserve "
" and update. \n " ) ) ;
2007-06-29 13:54:39 +04:00
ret = smb_krb5_open_keytab ( context , NULL , True , & keytab ) ;
2004-06-18 01:39:51 +04:00
if ( ret ) {
2010-08-18 14:09:27 +04:00
DEBUG ( 1 , ( __location__ " : smb_krb5_open_keytab failed (%s) \n " ,
error_message ( ret ) ) ) ;
2007-06-29 13:58:11 +04:00
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 ) {
2010-08-18 14:09:27 +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
/*
2010-08-18 14:09:27 +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 .
2004-06-19 03:15:42 +04:00
*/
2010-08-18 14:09:27 +04:00
DEBUG ( 3 , ( __location__ " : Found %d entries in the keytab. \n " , found ) ) ;
2004-06-18 01:39:51 +04:00
if ( ! found ) {
goto done ;
}
2010-08-18 14:09:27 +04:00
oldEntries = talloc_array ( tmpctx , char * , found ) ;
2004-06-18 01:39:51 +04:00
if ( ! oldEntries ) {
2010-08-18 14:09:27 +04:00
DEBUG ( 1 , ( __location__ " : Failed to allocate space to store "
" the old keytab entries (talloc failed?). \n " ) ) ;
2004-06-19 03:15:42 +04:00
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 ) ;
2010-08-18 14:09:27 +04:00
if ( ret = = KRB5_KT_END | | ret = = ENOENT ) {
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
ZERO_STRUCT ( cursor ) ;
goto done ;
}
2004-06-19 03:15:42 +04:00
2010-08-18 14:09:27 +04:00
while ( krb5_kt_next_entry ( context , keytab , & kt_entry , & cursor ) = = 0 ) {
if ( kt_entry . vno ! = kvno ) {
char * ktprinc = NULL ;
char * p ;
2004-10-30 04:34:58 +04:00
2010-08-18 14:09:27 +04:00
/* This returns a malloc'ed string in ktprinc. */
ret = smb_krb5_unparse_name ( oldEntries , context ,
kt_entry . principal ,
& ktprinc ) ;
if ( ret ) {
DEBUG ( 1 , ( __location__
" : smb_krb5_unparse_name failed "
" (%s) \n " , error_message ( ret ) ) ) ;
goto done ;
}
/*
* 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 .
*/
p = strchr_m ( ktprinc , ' @ ' ) ;
if ( p ) {
* p = ' \0 ' ;
}
p = strchr_m ( ktprinc , ' / ' ) ;
if ( p ) {
* p = ' \0 ' ;
}
for ( i = 0 ; i < found ; i + + ) {
if ( ! oldEntries [ i ] ) {
oldEntries [ i ] = ktprinc ;
break ;
2004-06-18 01:39:51 +04:00
}
2010-08-18 14:09:27 +04:00
if ( ! strcmp ( oldEntries [ i ] , ktprinc ) ) {
2009-03-18 08:23:27 +03:00
TALLOC_FREE ( ktprinc ) ;
2010-08-18 14:09:27 +04:00
break ;
2004-06-23 04:20:31 +04:00
}
2004-06-18 01:39:51 +04:00
}
2010-08-18 14:09:27 +04:00
if ( i = = found ) {
TALLOC_FREE ( ktprinc ) ;
}
2004-06-18 01:39:51 +04:00
}
2010-08-18 14:09:27 +04:00
smb_krb5_kt_free_entry ( context , & kt_entry ) ;
ZERO_STRUCT ( kt_entry ) ;
2004-06-18 01:39:51 +04:00
}
2010-08-18 14:09:27 +04:00
ret = 0 ;
for ( i = 0 ; oldEntries [ i ] ; i + + ) {
ret | = ads_keytab_add_entry ( ads , oldEntries [ i ] ) ;
TALLOC_FREE ( oldEntries [ i ] ) ;
}
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
done :
2009-03-18 08:23:27 +03:00
TALLOC_FREE ( oldEntries ) ;
2010-08-18 14:09:27 +04:00
TALLOC_FREE ( tmpctx ) ;
2004-06-19 03:15:42 +04:00
{
krb5_keytab_entry zero_kt_entry ;
ZERO_STRUCT ( zero_kt_entry ) ;
2010-08-18 14:09:27 +04:00
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 ) ;
2010-08-18 14:09:27 +04:00
if ( ( memcmp ( & cursor , & zero_csr ,
sizeof ( krb5_kt_cursor ) ) ! = 0 ) & & keytab ) {
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
2004-06-24 23:48:52 +04:00
}
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
2011-04-15 14:37:55 +04:00
# endif /* HAVE_ADS */
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 ) {
2010-08-18 14:46:53 +04:00
DEBUG ( 1 , ( __location__ " : could not krb5_init_context: %s \n " ,
error_message ( ret ) ) ) ;
2007-04-23 12:40:54 +04:00
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 ) {
2010-08-18 14:46:53 +04:00
DEBUG ( 1 , ( __location__ " : 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 ) {
2010-08-31 16:27:56 +04:00
ZERO_STRUCT ( cursor ) ;
2007-04-23 12:40:54 +04:00
goto out ;
}
2012-01-06 20:48:58 +04:00
printf ( " Vno Type Principal \n " ) ;
2007-04-23 12:40:54 +04:00
while ( krb5_kt_next_entry ( context , keytab , & kt_entry , & cursor ) = = 0 ) {
2010-08-18 14:46:53 +04:00
2007-04-23 12:40:54 +04:00
char * princ_s = NULL ;
char * etype_s = NULL ;
krb5_enctype enctype = 0 ;
2010-08-18 14:46:53 +04:00
ret = smb_krb5_unparse_name ( talloc_tos ( ) , context ,
kt_entry . principal , & princ_s ) ;
2007-04-23 12:40:54 +04:00
if ( ret ) {
goto out ;
}
enctype = smb_get_enctype_from_kt_entry ( & kt_entry ) ;
ret = smb_krb5_enctype_to_string ( context , enctype , & etype_s ) ;
2010-08-18 14:46:53 +04:00
if ( ret & &
( asprintf ( & etype_s , " UNKNOWN: %d \n " , enctype ) = = - 1 ) ) {
TALLOC_FREE ( princ_s ) ;
goto out ;
2007-04-23 12:40:54 +04:00
}
2012-01-06 20:48:58 +04:00
printf ( " %3d %-43s %s \n " , kt_entry . vno , etype_s , princ_s ) ;
2007-04-23 12:40:54 +04:00
2009-03-18 08:23:27 +03:00
TALLOC_FREE ( princ_s ) ;
2007-04-23 12:40:54 +04:00
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 ) ;
2010-08-18 14:46:53 +04:00
if ( memcmp ( & zero_kt_entry , & kt_entry ,
sizeof ( krb5_keytab_entry ) ) ) {
2007-04-23 12:40:54 +04:00
smb_krb5_kt_free_entry ( context , & kt_entry ) ;
}
}
{
krb5_kt_cursor zero_csr ;
ZERO_STRUCT ( zero_csr ) ;
2010-08-18 14:46:53 +04:00
if ( ( memcmp ( & cursor , & zero_csr ,
sizeof ( krb5_kt_cursor ) ) ! = 0 ) & & keytab ) {
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
2007-04-23 12:40:54 +04:00
}
}
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 */