2005-05-15 23:42:11 +00:00
/*
Unix SMB / CIFS implementation .
Kerberos utility functions for GENSEC
2005-06-29 03:01:35 +00:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2004 - 2005
2005-05-15 23:42:11 +00: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"
# include "system/kerberos.h"
# include "system/time.h"
# include "system/network.h"
# include "auth/kerberos/kerberos.h"
# include "auth/auth.h"
2005-06-22 02:12:26 +00:00
struct principal_container {
struct smb_krb5_context * smb_krb5_context ;
krb5_principal principal ;
} ;
static int free_principal ( void * ptr ) {
struct principal_container * pc = ptr ;
/* current heimdal - 0.6.3, which we need anyway, fixes segfaults here */
krb5_free_principal ( pc - > smb_krb5_context - > krb5_context , pc - > principal ) ;
return 0 ;
}
krb5_error_code salt_principal_from_credentials ( TALLOC_CTX * parent_ctx ,
struct cli_credentials * machine_account ,
struct smb_krb5_context * smb_krb5_context ,
krb5_principal * salt_princ )
{
krb5_error_code ret ;
char * machine_username ;
char * salt_body ;
char * lower_realm ;
2005-12-04 12:17:02 +00:00
const char * salt_principal ;
2005-06-22 02:12:26 +00:00
struct principal_container * mem_ctx = talloc ( parent_ctx , struct principal_container ) ;
if ( ! mem_ctx ) {
return ENOMEM ;
}
2005-10-20 10:28:16 +00:00
salt_principal = cli_credentials_get_salt_principal ( machine_account ) ;
if ( salt_principal ) {
ret = krb5_parse_name ( smb_krb5_context - > krb5_context , salt_principal , salt_princ ) ;
} else {
machine_username = talloc_strdup ( mem_ctx , cli_credentials_get_username ( machine_account ) ) ;
if ( ! machine_username ) {
talloc_free ( mem_ctx ) ;
return ENOMEM ;
}
if ( machine_username [ strlen ( machine_username ) - 1 ] = = ' $ ' ) {
machine_username [ strlen ( machine_username ) - 1 ] = ' \0 ' ;
}
lower_realm = strlower_talloc ( mem_ctx , cli_credentials_get_realm ( machine_account ) ) ;
if ( ! lower_realm ) {
talloc_free ( mem_ctx ) ;
return ENOMEM ;
}
salt_body = talloc_asprintf ( mem_ctx , " %s.%s " , machine_username ,
lower_realm ) ;
if ( ! salt_body ) {
talloc_free ( mem_ctx ) ;
2005-06-22 02:12:26 +00:00
return ENOMEM ;
2005-10-20 10:28:16 +00:00
}
ret = krb5_make_principal ( smb_krb5_context - > krb5_context , salt_princ ,
cli_credentials_get_realm ( machine_account ) ,
" host " , salt_body , NULL ) ;
}
2005-06-22 02:12:26 +00:00
2005-09-05 10:53:14 +00:00
if ( ret = = 0 ) {
2005-06-22 02:12:26 +00:00
mem_ctx - > smb_krb5_context = talloc_reference ( mem_ctx , smb_krb5_context ) ;
mem_ctx - > principal = * salt_princ ;
talloc_set_destructor ( mem_ctx , free_principal ) ;
}
return ret ;
}
2005-05-15 23:42:11 +00:00
2005-12-01 05:09:28 +00:00
/* Obtain the principal set on this context. Requires a
* smb_krb5_context because we are doing krb5 principal parsing with
* the library routines . The returned princ is placed in the talloc
* system by means of a destructor ( do * not * free ) . */
2005-09-05 10:53:14 +00:00
krb5_error_code principal_from_credentials ( TALLOC_CTX * parent_ctx ,
struct cli_credentials * credentials ,
struct smb_krb5_context * smb_krb5_context ,
krb5_principal * princ )
{
krb5_error_code ret ;
const char * princ_string ;
struct principal_container * mem_ctx = talloc ( parent_ctx , struct principal_container ) ;
if ( ! mem_ctx ) {
return ENOMEM ;
}
princ_string = cli_credentials_get_principal ( credentials , mem_ctx ) ;
2005-12-01 05:09:28 +00:00
/* A NULL here has meaning, as the gssapi server case will then use the principal from the client */
2005-09-05 10:53:14 +00:00
if ( ! princ_string ) {
talloc_free ( mem_ctx ) ;
2005-10-20 03:47:55 +00:00
princ = NULL ;
return 0 ;
2005-09-05 10:53:14 +00:00
}
ret = krb5_parse_name ( smb_krb5_context - > krb5_context ,
princ_string , princ ) ;
if ( ret = = 0 ) {
2005-12-01 05:09:28 +00:00
/* This song-and-dance effectivly puts the principal
* into talloc , so we can ' t loose it . */
2005-09-05 10:53:14 +00:00
mem_ctx - > smb_krb5_context = talloc_reference ( mem_ctx , smb_krb5_context ) ;
mem_ctx - > principal = * princ ;
talloc_set_destructor ( mem_ctx , free_principal ) ;
}
return ret ;
}
2005-05-15 23:42:11 +00:00
/**
* Return a freshly allocated ccache ( destroyed by destructor on child
* of parent_ctx ) , for a given set of client credentials
*/
2005-08-29 04:30:22 +00:00
krb5_error_code kinit_to_ccache ( TALLOC_CTX * parent_ctx ,
2005-10-20 03:47:55 +00:00
struct cli_credentials * credentials ,
struct smb_krb5_context * smb_krb5_context ,
krb5_ccache ccache )
2005-05-15 23:42:11 +00:00
{
krb5_error_code ret ;
const char * password ;
time_t kdc_time = 0 ;
2005-09-05 10:53:14 +00:00
krb5_principal princ ;
2005-08-29 04:30:22 +00:00
TALLOC_CTX * mem_ctx = talloc_new ( parent_ctx ) ;
2005-05-15 23:42:11 +00:00
if ( ! mem_ctx ) {
2005-08-29 04:30:22 +00:00
return ENOMEM ;
2005-05-15 23:42:11 +00:00
}
2005-09-05 10:53:14 +00:00
ret = principal_from_credentials ( mem_ctx , credentials , smb_krb5_context , & princ ) ;
if ( ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
2005-05-15 23:42:11 +00:00
password = cli_credentials_get_password ( credentials ) ;
2005-06-29 03:01:35 +00:00
if ( password ) {
2005-08-29 04:30:22 +00:00
ret = kerberos_kinit_password_cc ( smb_krb5_context - > krb5_context , ccache ,
2005-09-05 10:53:14 +00:00
princ ,
2005-06-29 03:01:35 +00:00
password , NULL , & kdc_time ) ;
} else {
/* No password available, try to use a keyblock instead */
krb5_keyblock keyblock ;
const struct samr_Password * mach_pwd ;
mach_pwd = cli_credentials_get_nt_hash ( credentials , mem_ctx ) ;
if ( ! mach_pwd ) {
talloc_free ( mem_ctx ) ;
DEBUG ( 1 , ( " kinit_to_ccache: No password available for kinit \n " ) ) ;
2005-08-29 04:30:22 +00:00
return EINVAL ;
2005-06-29 03:01:35 +00:00
}
ret = krb5_keyblock_init ( smb_krb5_context - > krb5_context ,
ENCTYPE_ARCFOUR_HMAC ,
mach_pwd - > hash , sizeof ( mach_pwd - > hash ) ,
& keyblock ) ;
if ( ret = = 0 ) {
2005-08-29 04:30:22 +00:00
ret = kerberos_kinit_keyblock_cc ( smb_krb5_context - > krb5_context , ccache ,
2005-09-05 10:53:14 +00:00
princ ,
2005-06-29 03:01:35 +00:00
& keyblock , NULL , & kdc_time ) ;
2005-06-29 13:48:51 +00:00
krb5_free_keyblock_contents ( smb_krb5_context - > krb5_context , & keyblock ) ;
2005-06-29 03:01:35 +00:00
}
}
2005-05-15 23:42:11 +00:00
/* cope with ticket being in the future due to clock skew */
if ( ( unsigned ) kdc_time > time ( NULL ) ) {
time_t t = time ( NULL ) ;
int time_offset = ( unsigned ) kdc_time - t ;
DEBUG ( 4 , ( " Advancing clock by %d seconds to cope with clock skew \n " , time_offset ) ) ;
2005-06-04 11:17:05 +00:00
krb5_set_real_time ( smb_krb5_context - > krb5_context , t + time_offset + 1 , 0 ) ;
2005-05-15 23:42:11 +00:00
}
if ( ret = = KRB5KRB_AP_ERR_SKEW | | ret = = KRB5_KDCREP_SKEW ) {
DEBUG ( 1 , ( " kinit for %s failed (%s) \n " ,
cli_credentials_get_principal ( credentials , mem_ctx ) ,
2005-06-04 11:17:05 +00:00
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
2005-05-15 23:42:11 +00:00
ret , mem_ctx ) ) ) ;
talloc_free ( mem_ctx ) ;
2005-08-29 04:30:22 +00:00
return ret ;
2005-05-15 23:42:11 +00:00
}
if ( ret ) {
DEBUG ( 1 , ( " kinit for %s failed (%s) \n " ,
cli_credentials_get_principal ( credentials , mem_ctx ) ,
2005-06-04 11:17:05 +00:00
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
2005-05-15 23:42:11 +00:00
ret , mem_ctx ) ) ) ;
talloc_free ( mem_ctx ) ;
2005-08-29 04:30:22 +00:00
return ret ;
2005-05-15 23:42:11 +00:00
}
2005-08-29 04:30:22 +00:00
return 0 ;
2005-05-15 23:42:11 +00:00
}
2005-06-22 02:12:26 +00:00
static int free_keytab ( void * ptr ) {
struct keytab_container * ktc = ptr ;
krb5_kt_close ( ktc - > smb_krb5_context - > krb5_context , ktc - > keytab ) ;
return 0 ;
}
2005-12-21 22:02:52 +00:00
int smb_krb5_open_keytab ( TALLOC_CTX * mem_ctx ,
struct smb_krb5_context * smb_krb5_context ,
const char * keytab_name , struct keytab_container * * ktc )
{
krb5_keytab keytab ;
int ret ;
ret = krb5_kt_resolve ( smb_krb5_context - > krb5_context , keytab_name , & keytab ) ;
if ( ret ) {
DEBUG ( 1 , ( " failed to open krb5 keytab: %s \n " ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
return ret ;
}
* ktc = talloc ( mem_ctx , struct keytab_container ) ;
if ( ! * ktc ) {
return ENOMEM ;
}
( * ktc ) - > smb_krb5_context = talloc_reference ( * ktc , smb_krb5_context ) ;
( * ktc ) - > keytab = keytab ;
talloc_set_destructor ( * ktc , free_keytab ) ;
return 0 ;
}
2005-12-01 05:09:28 +00:00
struct enctypes_container {
struct smb_krb5_context * smb_krb5_context ;
krb5_enctype * enctypes ;
} ;
static int free_enctypes ( void * ptr ) {
struct enctypes_container * etc = ptr ;
free_kerberos_etypes ( etc - > smb_krb5_context - > krb5_context , etc - > enctypes ) ;
return 0 ;
}
static krb5_error_code keytab_add_keys ( TALLOC_CTX * parent_ctx ,
const char * princ_string ,
krb5_principal princ ,
krb5_principal salt_princ ,
int kvno ,
const char * password_s ,
struct smb_krb5_context * smb_krb5_context ,
krb5_keytab keytab )
2005-06-22 02:12:26 +00:00
{
2005-12-01 05:09:28 +00:00
int i ;
2005-06-22 02:12:26 +00:00
krb5_error_code ret ;
krb5_enctype * enctypes ;
2005-12-04 12:17:02 +00:00
char * enctype_string ;
2005-12-01 05:09:28 +00:00
struct enctypes_container * etc ;
krb5_data password ;
2005-10-20 03:47:55 +00:00
TALLOC_CTX * mem_ctx = talloc_new ( parent_ctx ) ;
2005-06-22 02:12:26 +00:00
if ( ! mem_ctx ) {
2005-10-20 03:47:55 +00:00
return ENOMEM ;
2005-06-22 02:12:26 +00:00
}
2005-12-01 05:09:28 +00:00
etc = talloc ( mem_ctx , struct enctypes_container ) ;
if ( ! etc ) {
talloc_free ( mem_ctx ) ;
return ENOMEM ;
}
ret = get_kerberos_allowed_etypes ( smb_krb5_context - > krb5_context ,
& enctypes ) ;
if ( ret ! = 0 ) {
DEBUG ( 1 , ( " keytab_add_keys: getting encrption types failed (%s) \n " ,
2005-06-22 02:12:26 +00:00
error_message ( ret ) ) ) ;
talloc_free ( mem_ctx ) ;
2005-10-20 03:47:55 +00:00
return ret ;
2005-06-22 02:12:26 +00:00
}
2005-12-01 05:09:28 +00:00
etc - > smb_krb5_context = talloc_reference ( etc , smb_krb5_context ) ;
etc - > enctypes = enctypes ;
2005-06-22 02:12:26 +00:00
2005-12-01 05:09:28 +00:00
talloc_set_destructor ( etc , free_enctypes ) ;
2005-06-22 02:12:26 +00:00
2005-12-01 05:09:28 +00:00
password . data = discard_const_p ( char * , password_s ) ;
password . length = strlen ( password_s ) ;
for ( i = 0 ; enctypes [ i ] ; i + + ) {
krb5_keytab_entry entry ;
ret = create_kerberos_key_from_string ( smb_krb5_context - > krb5_context ,
salt_princ , & password , & entry . keyblock , enctypes [ i ] ) ;
2005-12-04 12:17:02 +00:00
if ( ret ! = 0 ) {
2005-12-01 05:09:28 +00:00
talloc_free ( mem_ctx ) ;
return ret ;
}
entry . principal = princ ;
entry . vno = kvno ;
ret = krb5_kt_add_entry ( smb_krb5_context - > krb5_context , keytab , & entry ) ;
2005-12-04 12:17:02 +00:00
enctype_string = NULL ;
krb5_enctype_to_string ( smb_krb5_context - > krb5_context , enctypes [ i ] , & enctype_string ) ;
2005-12-01 05:09:28 +00:00
if ( ret ! = 0 ) {
2005-12-04 12:17:02 +00:00
DEBUG ( 1 , ( " Failed to add %s entry for %s(kvno %d) to keytab: %s \n " ,
enctype_string ,
2005-12-01 05:09:28 +00:00
princ_string ,
kvno ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
talloc_free ( mem_ctx ) ;
2005-12-04 12:17:02 +00:00
free ( enctype_string ) ;
2005-12-01 05:09:28 +00:00
krb5_free_keyblock_contents ( smb_krb5_context - > krb5_context , & entry . keyblock ) ;
return ret ;
}
DEBUG ( 5 , ( " Added %s(kvno %d) to keytab (%s) \n " ,
princ_string , kvno ,
enctype_string ) ) ;
free ( enctype_string ) ;
krb5_free_keyblock_contents ( smb_krb5_context - > krb5_context , & entry . keyblock ) ;
}
talloc_free ( mem_ctx ) ;
return 0 ;
}
static int create_keytab ( TALLOC_CTX * parent_ctx ,
struct cli_credentials * machine_account ,
struct smb_krb5_context * smb_krb5_context ,
2005-12-04 12:17:02 +00:00
krb5_keytab keytab ,
2005-12-01 05:09:28 +00:00
BOOL add_old )
{
krb5_error_code ret ;
const char * password_s ;
char * enctype_string ;
const char * old_secret ;
int kvno ;
krb5_principal salt_princ ;
krb5_principal princ ;
const char * princ_string ;
TALLOC_CTX * mem_ctx = talloc_new ( parent_ctx ) ;
if ( ! mem_ctx ) {
return ENOMEM ;
}
princ_string = cli_credentials_get_principal ( machine_account , mem_ctx ) ;
/* Get the principal we will store the new keytab entries under */
ret = principal_from_credentials ( mem_ctx , machine_account , smb_krb5_context , & princ ) ;
2005-06-22 02:12:26 +00:00
if ( ret ) {
2005-12-01 05:09:28 +00:00
DEBUG ( 1 , ( " create_keytab: makeing krb5 principal failed (%s) \n " ,
2005-09-05 10:53:14 +00:00
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
talloc_free ( mem_ctx ) ;
2005-10-20 03:47:55 +00:00
return ret ;
2005-09-05 10:53:14 +00:00
}
2005-12-01 05:09:28 +00:00
/* The salt used to generate these entries may be different however, fetch that */
ret = salt_principal_from_credentials ( mem_ctx , machine_account ,
smb_krb5_context ,
& salt_princ ) ;
2005-09-05 10:53:14 +00:00
if ( ret ) {
2005-12-01 05:09:28 +00:00
DEBUG ( 1 , ( " create_keytab: makeing salt principal failed (%s) \n " ,
2005-09-05 10:53:14 +00:00
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
talloc_free ( mem_ctx ) ;
2005-10-20 03:47:55 +00:00
return ret ;
2005-06-22 02:12:26 +00:00
}
2005-12-01 05:09:28 +00:00
/* Finally, do the dance to get the password to put in the entry */
2005-10-20 03:47:55 +00:00
password_s = cli_credentials_get_password ( machine_account ) ;
2005-06-29 03:01:35 +00:00
if ( ! password_s ) {
/* If we don't have the plaintext password, try for
* the MD4 password hash */
krb5_keytab_entry entry ;
const struct samr_Password * mach_pwd ;
mach_pwd = cli_credentials_get_nt_hash ( machine_account , mem_ctx ) ;
if ( ! mach_pwd ) {
talloc_free ( mem_ctx ) ;
2005-12-01 05:09:28 +00:00
DEBUG ( 1 , ( " create_keytab: Domain trust informaton for account %s not available \n " ,
2005-06-29 03:01:35 +00:00
cli_credentials_get_principal ( machine_account , mem_ctx ) ) ) ;
2005-10-20 03:47:55 +00:00
return EINVAL ;
2005-06-29 03:01:35 +00:00
}
ret = krb5_keyblock_init ( smb_krb5_context - > krb5_context ,
ENCTYPE_ARCFOUR_HMAC ,
mach_pwd - > hash , sizeof ( mach_pwd - > hash ) ,
& entry . keyblock ) ;
if ( ret ) {
2005-12-01 05:09:28 +00:00
DEBUG ( 1 , ( " create_keytab: krb5_keyblock_init failed: %s \n " ,
2005-06-29 03:01:35 +00:00
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
2005-10-20 03:47:55 +00:00
return ret ;
2005-06-29 03:01:35 +00:00
}
2005-09-05 10:53:14 +00:00
entry . principal = princ ;
2005-06-29 03:01:35 +00:00
entry . vno = cli_credentials_get_kvno ( machine_account ) ;
2005-10-20 03:47:55 +00:00
ret = krb5_kt_add_entry ( smb_krb5_context - > krb5_context , keytab , & entry ) ;
2005-06-29 03:01:35 +00:00
if ( ret ) {
DEBUG ( 1 , ( " Failed to add ARCFOUR_HMAC (only) entry for %s to keytab: %s " ,
cli_credentials_get_principal ( machine_account , mem_ctx ) ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
talloc_free ( mem_ctx ) ;
krb5_free_keyblock_contents ( smb_krb5_context - > krb5_context , & entry . keyblock ) ;
2005-10-20 03:47:55 +00:00
return ret ;
2005-06-29 03:01:35 +00:00
}
2005-12-04 12:17:02 +00:00
krb5_enctype_to_string ( smb_krb5_context - > krb5_context , ENCTYPE_ARCFOUR_HMAC , & enctype_string ) ;
2005-10-28 02:29:32 +00:00
DEBUG ( 5 , ( " Added %s(kvno %d) to keytab (%s) \n " ,
cli_credentials_get_principal ( machine_account , mem_ctx ) ,
cli_credentials_get_kvno ( machine_account ) ,
enctype_string ) ) ;
free ( enctype_string ) ;
2005-06-29 03:01:35 +00:00
krb5_free_keyblock_contents ( smb_krb5_context - > krb5_context , & entry . keyblock ) ;
2005-10-20 03:47:55 +00:00
2005-12-01 05:09:28 +00:00
/* Can't go any further, we only have this one key */
2005-10-20 03:47:55 +00:00
talloc_free ( mem_ctx ) ;
return 0 ;
2005-06-29 03:01:35 +00:00
}
2005-12-01 05:09:28 +00:00
kvno = cli_credentials_get_kvno ( machine_account ) ;
2005-06-29 03:01:35 +00:00
/* good, we actually have the real plaintext */
2005-12-01 05:09:28 +00:00
ret = keytab_add_keys ( mem_ctx , princ_string , princ , salt_princ ,
2005-12-04 12:17:02 +00:00
kvno , password_s , smb_krb5_context , keytab ) ;
2005-12-01 05:09:28 +00:00
if ( ! ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
2005-06-29 03:01:35 +00:00
2005-12-01 05:09:28 +00:00
if ( ! add_old | | kvno = = 0 ) {
talloc_free ( mem_ctx ) ;
return 0 ;
}
old_secret = cli_credentials_get_old_password ( machine_account ) ;
if ( ! old_secret ) {
talloc_free ( mem_ctx ) ;
return 0 ;
}
ret = keytab_add_keys ( mem_ctx , princ_string , princ , salt_princ ,
kvno - 1 , old_secret , smb_krb5_context , keytab ) ;
if ( ! ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
talloc_free ( mem_ctx ) ;
return 0 ;
}
/*
* Walk the keytab , looking for entries of this principal name , with KVNO other than current kvno - 1.
*
* These entries are now stale , we only keep the current , and previous entries around .
*
* Inspired by the code in Samba3 for ' use kerberos keytab ' .
*
*/
static krb5_error_code remove_old_entries ( TALLOC_CTX * parent_ctx ,
struct cli_credentials * machine_account ,
struct smb_krb5_context * smb_krb5_context ,
krb5_keytab keytab , BOOL * found_previous )
{
krb5_error_code ret , ret2 ;
krb5_kt_cursor cursor ;
krb5_principal princ ;
int kvno ;
TALLOC_CTX * mem_ctx = talloc_new ( parent_ctx ) ;
const char * princ_string ;
if ( ! mem_ctx ) {
return ENOMEM ;
}
* found_previous = False ;
princ_string = cli_credentials_get_principal ( machine_account , mem_ctx ) ;
/* Get the principal we will store the new keytab entries under */
ret = principal_from_credentials ( mem_ctx , machine_account , smb_krb5_context , & princ ) ;
2005-06-22 02:12:26 +00:00
if ( ret ) {
2005-12-01 05:09:28 +00:00
DEBUG ( 1 , ( " update_keytab: makeing krb5 principal failed (%s) \n " ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
2005-06-29 03:01:35 +00:00
talloc_free ( mem_ctx ) ;
2005-10-20 03:47:55 +00:00
return ret ;
2005-06-22 02:12:26 +00:00
}
2005-10-20 03:47:55 +00:00
kvno = cli_credentials_get_kvno ( machine_account ) ;
2005-12-01 05:09:28 +00:00
/* for each entry in the keytab */
ret = krb5_kt_start_seq_get ( smb_krb5_context - > krb5_context , keytab , & cursor ) ;
switch ( ret ) {
case 0 :
break ;
case ENOENT :
case KRB5_KT_END :
/* no point enumerating if there isn't anything here */
talloc_free ( mem_ctx ) ;
return 0 ;
default :
DEBUG ( 1 , ( " failed to open keytab for read of old entries: %s \n " ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
while ( ! ret ) {
2005-06-22 02:12:26 +00:00
krb5_keytab_entry entry ;
2005-12-01 05:09:28 +00:00
ret = krb5_kt_next_entry ( smb_krb5_context - > krb5_context , keytab , & entry , & cursor ) ;
2005-06-22 02:12:26 +00:00
if ( ret ) {
2005-12-01 05:09:28 +00:00
break ;
2005-06-22 02:12:26 +00:00
}
2005-12-01 05:09:28 +00:00
/* if it matches our principal */
if ( ! krb5_kt_compare ( smb_krb5_context - > krb5_context , & entry , princ , 0 , 0 ) ) {
/* Free the entry, it wasn't the one we were looking for anyway */
krb5_kt_free_entry ( smb_krb5_context - > krb5_context , & entry ) ;
continue ;
2005-06-22 02:12:26 +00:00
}
2005-10-28 02:29:32 +00:00
2005-12-01 05:09:28 +00:00
/* delete it, if it is not kvno -1 */
if ( entry . vno ! = ( kvno - 1 ) ) {
/* Release the enumeration. We are going to
* have to start this from the top again ,
* because deletes during enumeration may not
* always be consistant .
*
* Also , the enumeration locks the keytab
*/
2005-06-22 02:12:26 +00:00
2005-12-01 05:09:28 +00:00
krb5_kt_end_seq_get ( smb_krb5_context - > krb5_context , keytab , & cursor ) ;
ret = krb5_kt_remove_entry ( smb_krb5_context - > krb5_context , keytab , & entry ) ;
krb5_kt_free_entry ( smb_krb5_context - > krb5_context , & entry ) ;
/* Deleted: Restart from the top */
ret2 = krb5_kt_start_seq_get ( smb_krb5_context - > krb5_context , keytab , & cursor ) ;
if ( ret2 ) {
krb5_kt_free_entry ( smb_krb5_context - > krb5_context , & entry ) ;
DEBUG ( 1 , ( " failed to restart enumeration of keytab: %s \n " ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
2005-10-20 03:47:55 +00:00
talloc_free ( mem_ctx ) ;
2005-12-01 05:09:28 +00:00
return ret2 ;
2005-10-20 03:47:55 +00:00
}
2005-12-01 05:09:28 +00:00
2005-10-20 03:47:55 +00:00
if ( ret ) {
2005-12-01 05:09:28 +00:00
break ;
2005-10-20 03:47:55 +00:00
}
2005-12-01 05:09:28 +00:00
} else {
* found_previous = True ;
2005-10-20 03:47:55 +00:00
}
2005-12-01 05:09:28 +00:00
/* Free the entry, we don't need it any more */
krb5_kt_free_entry ( smb_krb5_context - > krb5_context , & entry ) ;
2005-10-20 03:47:55 +00:00
}
2005-12-01 05:09:28 +00:00
krb5_kt_end_seq_get ( smb_krb5_context - > krb5_context , keytab , & cursor ) ;
switch ( ret ) {
case 0 :
break ;
case ENOENT :
case KRB5_KT_END :
ret = 0 ;
break ;
default :
DEBUG ( 1 , ( " failed in deleting old entries for principal: %s: %s \n " ,
princ_string ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
}
talloc_free ( mem_ctx ) ;
return ret ;
}
2005-10-20 03:47:55 +00:00
2005-12-21 22:02:52 +00:00
int smb_krb5_update_keytab ( TALLOC_CTX * parent_ctx ,
struct cli_credentials * machine_account ,
struct smb_krb5_context * smb_krb5_context ,
struct keytab_container * keytab_container )
2005-12-01 05:09:28 +00:00
{
krb5_error_code ret ;
BOOL found_previous ;
TALLOC_CTX * mem_ctx = talloc_new ( parent_ctx ) ;
if ( ! mem_ctx ) {
return ENOMEM ;
}
ret = remove_old_entries ( mem_ctx , machine_account ,
smb_krb5_context , keytab_container - > keytab , & found_previous ) ;
if ( ret ! = 0 ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
/* Create a new keytab. If during the cleanout we found
* entires for kvno - 1 , then don ' t try and duplicate them .
* Otherwise , add kvno , and kvno - 1 */
ret = create_keytab ( mem_ctx , machine_account , smb_krb5_context ,
2005-12-04 12:17:02 +00:00
keytab_container - > keytab ,
2005-12-01 05:09:28 +00:00
found_previous ? False : True ) ;
2005-10-20 03:47:55 +00:00
talloc_free ( mem_ctx ) ;
2005-12-01 05:09:28 +00:00
return ret ;
2005-06-22 02:12:26 +00:00
}
2005-06-29 03:01:35 +00:00
2005-12-21 22:02:52 +00:00
int smb_krb5_create_memory_keytab ( TALLOC_CTX * parent_ctx ,
struct cli_credentials * machine_account ,
struct smb_krb5_context * smb_krb5_context ,
struct keytab_container * * keytab_container )
2005-12-01 05:09:28 +00:00
{
krb5_error_code ret ;
TALLOC_CTX * mem_ctx = talloc_new ( parent_ctx ) ;
2005-12-05 01:38:26 +00:00
const char * rand_string ;
const char * keytab_name ;
2005-12-01 05:09:28 +00:00
if ( ! mem_ctx ) {
return ENOMEM ;
}
* keytab_container = talloc ( mem_ctx , struct keytab_container ) ;
2005-12-05 01:38:26 +00:00
rand_string = generate_random_str ( mem_ctx , 16 ) ;
if ( ! rand_string ) {
talloc_free ( mem_ctx ) ;
return ENOMEM ;
}
keytab_name = talloc_asprintf ( mem_ctx , " MEMORY:%s " ,
rand_string ) ;
if ( ! keytab_name ) {
talloc_free ( mem_ctx ) ;
return ENOMEM ;
}
2005-12-21 22:02:52 +00:00
ret = smb_krb5_open_keytab ( mem_ctx , smb_krb5_context , keytab_name , keytab_container ) ;
2005-12-01 05:09:28 +00:00
if ( ret ) {
return ret ;
}
2005-12-21 22:02:52 +00:00
ret = smb_krb5_update_keytab ( mem_ctx , machine_account , smb_krb5_context , * keytab_container ) ;
2005-12-01 05:09:28 +00:00
if ( ret = = 0 ) {
talloc_steal ( parent_ctx , * keytab_container ) ;
2005-12-04 12:17:02 +00:00
} else {
* keytab_container = NULL ;
}
2005-12-01 05:09:28 +00:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2005-06-29 03:01:35 +00:00