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
2007-07-10 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2005-05-15 23:42:11 +00: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 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-05-15 23:42:11 +00:00
*/
# include "includes.h"
# include "system/kerberos.h"
# include "auth/kerberos/kerberos.h"
2006-11-06 11:18:32 +00:00
# include "auth/credentials/credentials.h"
2008-04-02 04:53:27 +02:00
# include "auth/credentials/credentials_proto.h"
2006-11-07 00:48:36 +00:00
# include "auth/credentials/credentials_krb5.h"
2005-05-15 23:42:11 +00:00
2005-06-22 02:12:26 +00:00
struct principal_container {
struct smb_krb5_context * smb_krb5_context ;
krb5_principal principal ;
} ;
2008-09-09 17:37:33 +02:00
static krb5_error_code free_principal ( struct principal_container * pc )
2006-05-24 07:32:17 +00:00
{
2005-06-22 02:12:26 +00:00
/* 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 ;
}
2006-11-06 11:18:32 +00:00
static 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 )
2005-06-22 02:12:26 +00:00
{
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-12-22 06:50:04 +00:00
/* This song-and-dance effectivly puts the principal
* into talloc , so we can ' t loose it . */
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 ) . */
2008-03-17 15:22:52 +11: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 )
2005-09-05 10:53:14 +00:00
{
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-22 06:50:04 +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 ;
2006-11-06 11:18:32 +00:00
int tries ;
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
2006-11-06 11:18:32 +00:00
tries = 2 ;
while ( tries - - ) {
if ( password ) {
ret = kerberos_kinit_password_cc ( smb_krb5_context - > krb5_context , ccache ,
princ ,
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 " ) ) ;
return EINVAL ;
}
ret = krb5_keyblock_init ( smb_krb5_context - > krb5_context ,
2009-08-18 12:08:37 +10:00
ENCTYPE_ARCFOUR_HMAC ,
2006-11-06 11:18:32 +00:00
mach_pwd - > hash , sizeof ( mach_pwd - > hash ) ,
& keyblock ) ;
if ( ret = = 0 ) {
ret = kerberos_kinit_keyblock_cc ( smb_krb5_context - > krb5_context , ccache ,
princ ,
& keyblock , NULL , & kdc_time ) ;
krb5_free_keyblock_contents ( smb_krb5_context - > krb5_context , & keyblock ) ;
}
2005-06-29 03:01:35 +00:00
}
2006-11-06 11:18:32 +00:00
if ( ret = = KRB5KRB_AP_ERR_SKEW | | ret = = KRB5_KDCREP_SKEW ) {
/* Perhaps we have been given an invalid skew, so try again without it */
time_t t = time ( NULL ) ;
krb5_set_real_time ( smb_krb5_context - > krb5_context , t , 0 ) ;
} else {
/* not a skew problem */
break ;
2005-06-29 03:01:35 +00:00
}
}
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
}
2006-05-07 18:21:55 +00:00
2006-11-06 11:18:32 +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 ) ) ;
krb5_set_real_time ( smb_krb5_context - > krb5_context , t + time_offset + 1 , 0 ) ;
}
2006-05-07 18:21:55 +00:00
if ( ret = = KRB5KDC_ERR_PREAUTH_FAILED & & cli_credentials_wrong_password ( credentials ) ) {
ret = kinit_to_ccache ( parent_ctx ,
credentials ,
smb_krb5_context ,
ccache ) ;
}
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
}
2007-05-18 07:58:37 +00:00
talloc_free ( mem_ctx ) ;
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
2008-09-09 17:37:33 +02:00
static krb5_error_code free_keytab ( struct keytab_container * ktc )
2006-05-24 07:32:17 +00:00
{
2008-09-09 17:37:33 +02:00
return krb5_kt_close ( ktc - > smb_krb5_context - > krb5_context , ktc - > keytab ) ;
2005-06-22 02:12:26 +00:00
}
2008-09-09 17:37:33 +02:00
krb5_error_code smb_krb5_open_keytab ( TALLOC_CTX * mem_ctx ,
2005-12-21 22:02:52 +00:00
struct smb_krb5_context * smb_krb5_context ,
const char * keytab_name , struct keytab_container * * ktc )
{
krb5_keytab keytab ;
2008-09-09 17:37:33 +02:00
krb5_error_code ret ;
2005-12-21 22:02:52 +00:00
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
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 ,
2007-04-28 16:38:06 +00:00
const char * * enctype_strings ,
2005-12-01 05:09:28 +00:00
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 ;
2005-12-01 05:09:28 +00:00
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
password . data = discard_const_p ( char * , password_s ) ;
password . length = strlen ( password_s ) ;
2007-04-28 16:38:06 +00:00
for ( i = 0 ; enctype_strings [ i ] ; i + + ) {
2005-12-01 05:09:28 +00:00
krb5_keytab_entry entry ;
2007-04-28 16:38:06 +00:00
krb5_enctype enctype ;
ret = krb5_string_to_enctype ( smb_krb5_context - > krb5_context , enctype_strings [ i ] , & enctype ) ;
if ( ret ! = 0 ) {
DEBUG ( 1 , ( " Failed to interpret %s as a krb5 encryption type: %s \n " ,
enctype_strings [ i ] ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
2005-12-01 05:09:28 +00:00
ret = create_kerberos_key_from_string ( smb_krb5_context - > krb5_context ,
2007-04-28 16:38:06 +00:00
salt_princ , & password , & entry . keyblock , enctype ) ;
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 ) ;
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 " ,
2007-04-28 16:38:06 +00:00
enctype_strings [ i ] ,
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 ) ;
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 ,
2007-04-28 16:38:06 +00:00
enctype_strings [ i ] ) ) ;
2005-12-01 05:09:28 +00:00
krb5_free_keyblock_contents ( smb_krb5_context - > krb5_context , & entry . keyblock ) ;
}
talloc_free ( mem_ctx ) ;
return 0 ;
}
2008-09-09 17:37:33 +02:00
static krb5_error_code create_keytab ( TALLOC_CTX * parent_ctx ,
2005-12-01 05:09:28 +00:00
struct cli_credentials * machine_account ,
struct smb_krb5_context * smb_krb5_context ,
2007-04-28 16:38:06 +00:00
const char * * enctype_strings ,
2005-12-04 12:17:02 +00:00
krb5_keytab keytab ,
2007-10-06 22:16:19 +00:00
bool add_old )
2005-12-01 05:09:28 +00:00
{
krb5_error_code ret ;
const char * password_s ;
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 ) {
krb5_keytab_entry entry ;
const struct samr_Password * mach_pwd ;
2007-04-28 16:38:06 +00:00
if ( ! str_list_check ( enctype_strings , " arcfour-hmac-md5 " ) ) {
DEBUG ( 1 , ( " Asked to create keytab, but with only an NT hash supplied, "
" but not listing arcfour-hmac-md5 as an enc type to include in the keytab! \n " ) ) ;
talloc_free ( mem_ctx ) ;
return EINVAL ;
}
/* If we don't have the plaintext password, try for
* the MD4 password hash */
2005-06-29 03:01:35 +00:00
mach_pwd = cli_credentials_get_nt_hash ( machine_account , mem_ctx ) ;
if ( ! mach_pwd ) {
2007-02-06 05:41:04 +00:00
/* OK, nothing to do here */
2006-01-24 05:31:08 +00:00
talloc_free ( mem_ctx ) ;
2007-02-06 05:41:04 +00:00
return 0 ;
2005-06-29 03:01:35 +00:00
}
ret = krb5_keyblock_init ( smb_krb5_context - > krb5_context ,
2006-05-08 09:24:07 +00:00
ETYPE_ARCFOUR_HMAC_MD5 ,
2005-06-29 03:01:35 +00:00
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 ) ) ) ;
2006-01-24 05:31:08 +00:00
talloc_free ( 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
}
2007-04-28 16:38:06 +00:00
DEBUG ( 5 , ( " Added %s(kvno %d) to keytab (arcfour-hmac-md5) \n " ,
2005-10-28 02:29:32 +00:00
cli_credentials_get_principal ( machine_account , mem_ctx ) ,
2007-04-28 16:38:06 +00:00
cli_credentials_get_kvno ( machine_account ) ) ) ;
2005-10-28 02:29:32 +00:00
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 ,
2007-04-28 16:38:06 +00:00
kvno , password_s , smb_krb5_context ,
enctype_strings , 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 ,
2007-04-28 16:38:06 +00:00
kvno - 1 , old_secret , smb_krb5_context ,
enctype_strings , keytab ) ;
2005-12-01 05:09:28 +00:00
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 ,
2007-10-06 22:16:19 +00:00
krb5_keytab keytab , bool * found_previous )
2005-12-01 05:09:28 +00:00
{
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 ;
}
2007-10-06 22:16:19 +00:00
* found_previous = false ;
2005-12-01 05:09:28 +00:00
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 ;
2006-01-24 05:31:08 +00:00
case HEIM_ERR_OPNOTSUPP :
2005-12-01 05:09:28 +00:00
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 .
*
2005-12-22 06:50:04 +00:00
* Also , the enumeration locks a FILE : keytab
2005-12-01 05:09:28 +00:00
*/
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 {
2007-10-06 22:16:19 +00:00
* 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
2008-09-09 17:37:33 +02:00
krb5_error_code smb_krb5_update_keytab ( TALLOC_CTX * parent_ctx ,
2005-12-21 22:02:52 +00:00
struct cli_credentials * machine_account ,
struct smb_krb5_context * smb_krb5_context ,
2007-04-28 16:38:06 +00:00
const char * * enctype_strings ,
2005-12-21 22:02:52 +00:00
struct keytab_container * keytab_container )
2005-12-01 05:09:28 +00:00
{
krb5_error_code ret ;
2007-10-06 22:16:19 +00:00
bool found_previous ;
2005-12-01 05:09:28 +00:00
TALLOC_CTX * mem_ctx = talloc_new ( parent_ctx ) ;
if ( ! mem_ctx ) {
return ENOMEM ;
}
2007-04-28 16:38:06 +00:00
2005-12-01 05:09:28 +00:00
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 ,
2007-04-28 16:38:06 +00:00
enctype_strings ,
2005-12-04 12:17:02 +00:00
keytab_container - > keytab ,
2007-10-06 22:16:19 +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
2008-09-09 17:37:33 +02:00
krb5_error_code smb_krb5_create_memory_keytab ( TALLOC_CTX * parent_ctx ,
2007-04-28 16:38:06 +00:00
struct cli_credentials * machine_account ,
struct smb_krb5_context * smb_krb5_context ,
const char * * enctype_strings ,
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 ;
}
2007-04-28 16:38:06 +00:00
ret = smb_krb5_update_keytab ( mem_ctx , machine_account , smb_krb5_context , enctype_strings , * 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