2023-07-26 16:07:12 +02:00
/*
2005-05-15 23:42:11 +00:00
Unix SMB / CIFS implementation .
Kerberos utility functions for GENSEC
2023-07-26 16:07:12 +02:00
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 .
2023-07-26 16:07:12 +02:00
2005-05-15 23:42:11 +00:00
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 .
2023-07-26 16:07:12 +02:00
2005-05-15 23:42:11 +00:00
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"
2006-11-07 00:48:36 +00:00
# include "auth/credentials/credentials_krb5.h"
2010-05-01 10:33:08 +10:00
# include "auth/kerberos/kerberos_credentials.h"
2010-10-11 01:28:45 +02:00
# include "auth/kerberos/kerberos_util.h"
2005-05-15 23:42:11 +00:00
2012-03-31 01:27:02 -04:00
struct principal_container {
struct smb_krb5_context * smb_krb5_context ;
krb5_principal principal ;
const char * string_form ; /* Optional */
} ;
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 ;
}
2010-03-03 13:24:52 +11:00
2012-03-31 01:27:02 -04:00
static krb5_error_code parse_principal ( TALLOC_CTX * parent_ctx ,
2010-03-03 13:24:52 +11:00
const char * princ_string ,
struct smb_krb5_context * smb_krb5_context ,
krb5_principal * princ ,
const char * * error_string )
{
int ret ;
struct principal_container * mem_ctx ;
if ( princ_string = = NULL ) {
* princ = NULL ;
return 0 ;
}
2023-07-26 16:28:36 +02:00
/*
* Start with talloc ( ) , talloc_reference ( ) and only then call
* krb5_parse_name ( ) . If any of them fails , the cleanup code is simpler .
*/
mem_ctx = talloc ( parent_ctx , struct principal_container ) ;
if ( ! mem_ctx ) {
( * error_string ) = error_message ( ENOMEM ) ;
return ENOMEM ;
}
mem_ctx - > smb_krb5_context = talloc_reference ( mem_ctx ,
smb_krb5_context ) ;
if ( mem_ctx - > smb_krb5_context = = NULL ) {
( * error_string ) = error_message ( ENOMEM ) ;
talloc_free ( mem_ctx ) ;
return ENOMEM ;
}
2010-03-03 13:24:52 +11:00
ret = krb5_parse_name ( smb_krb5_context - > krb5_context ,
princ_string , princ ) ;
if ( ret ) {
2012-03-30 18:33:41 -04:00
( * error_string ) = smb_get_krb5_error_message (
smb_krb5_context - > krb5_context ,
ret , parent_ctx ) ;
2023-07-26 16:28:36 +02:00
talloc_free ( mem_ctx ) ;
2010-03-03 13:24:52 +11:00
return ret ;
}
2023-11-21 15:03:55 +13:00
/* This song-and-dance effectively puts the principal
2023-09-22 08:08:03 +12:00
* into talloc , so we can ' t lose it . */
2010-03-03 13:24:52 +11:00
mem_ctx - > principal = * princ ;
talloc_set_destructor ( mem_ctx , free_principal ) ;
return 0 ;
}
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 ) . */
2012-03-30 18:33:41 -04: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 ,
enum credentials_obtained * obtained ,
const char * * error_string )
2005-09-05 10:53:14 +00:00
{
krb5_error_code ret ;
const char * princ_string ;
2010-03-03 13:24:52 +11:00
TALLOC_CTX * mem_ctx = talloc_new ( parent_ctx ) ;
2011-12-06 15:56:44 +11:00
* obtained = CRED_UNINITIALISED ;
2005-09-05 10:53:14 +00:00
if ( ! mem_ctx ) {
2010-02-25 16:16:33 +11:00
( * error_string ) = error_message ( ENOMEM ) ;
2005-09-05 10:53:14 +00:00
return ENOMEM ;
}
2012-03-30 18:33:41 -04:00
princ_string = cli_credentials_get_principal_and_obtained ( credentials ,
mem_ctx ,
obtained ) ;
2005-09-05 10:53:14 +00:00
if ( ! princ_string ) {
2011-12-06 15:56:44 +11:00
* princ = NULL ;
return 0 ;
2005-09-05 10:53:14 +00:00
}
2010-03-03 13:24:52 +11:00
ret = parse_principal ( parent_ctx , princ_string ,
smb_krb5_context , princ , error_string ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
2005-09-05 10:53:14 +00:00
2010-03-03 13:24:52 +11: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 ) . */
2010-02-25 16:16:33 +11:00
2012-03-30 18:33:41 -04:00
static krb5_error_code impersonate_principal_from_credentials (
TALLOC_CTX * parent_ctx ,
struct cli_credentials * credentials ,
struct smb_krb5_context * smb_krb5_context ,
krb5_principal * princ ,
const char * * error_string )
2010-03-03 13:24:52 +11:00
{
2012-03-30 18:33:41 -04:00
return parse_principal ( parent_ctx ,
cli_credentials_get_impersonate_principal ( credentials ) ,
smb_krb5_context , princ , error_string ) ;
2005-09-05 10:53:14 +00:00
}
2015-04-17 15:53:06 +02:00
krb5_error_code smb_krb5_create_principals_array ( TALLOC_CTX * mem_ctx ,
krb5_context context ,
const char * account_name ,
const char * realm ,
uint32_t num_spns ,
const char * spns [ ] ,
uint32_t * pnum_principals ,
krb5_principal * * pprincipals ,
const char * * error_string )
{
krb5_error_code code ;
TALLOC_CTX * tmp_ctx ;
uint32_t num_principals = 0 ;
krb5_principal * principals ;
uint32_t i ;
tmp_ctx = talloc_new ( mem_ctx ) ;
if ( tmp_ctx = = NULL ) {
* error_string = " Cannot allocate tmp_ctx " ;
return ENOMEM ;
}
if ( realm = = NULL ) {
* error_string = " Cannot create principal without a realm " ;
code = EINVAL ;
goto done ;
}
if ( account_name = = NULL & & ( num_spns = = 0 | | spns = = NULL ) ) {
* error_string = " Cannot create principal without an account or SPN " ;
code = EINVAL ;
goto done ;
}
if ( account_name ! = NULL & & account_name [ 0 ] ! = ' \0 ' ) {
num_principals + + ;
}
num_principals + = num_spns ;
principals = talloc_zero_array ( tmp_ctx ,
krb5_principal ,
num_principals ) ;
if ( principals = = NULL ) {
* error_string = " Cannot allocate principals " ;
code = ENOMEM ;
goto done ;
}
for ( i = 0 ; i < num_spns ; i + + ) {
code = krb5_parse_name ( context , spns [ i ] , & ( principals [ i ] ) ) ;
if ( code ! = 0 ) {
* error_string = smb_get_krb5_error_message ( context ,
code ,
mem_ctx ) ;
goto done ;
}
}
if ( account_name ! = NULL & & account_name [ 0 ] ! = ' \0 ' ) {
code = smb_krb5_make_principal ( context ,
& ( principals [ i ] ) ,
realm ,
account_name ,
NULL ) ;
if ( code ! = 0 ) {
* error_string = smb_get_krb5_error_message ( context ,
code ,
mem_ctx ) ;
goto done ;
}
}
if ( pnum_principals ! = NULL ) {
* pnum_principals = num_principals ;
if ( pprincipals ! = NULL ) {
* pprincipals = talloc_steal ( mem_ctx , principals ) ;
}
}
code = 0 ;
done :
talloc_free ( tmp_ctx ) ;
return code ;
}
2005-05-15 23:42:11 +00:00
/**
* Return a freshly allocated ccache ( destroyed by destructor on child
2023-07-26 16:07:12 +02:00
* of parent_ctx ) , for a given set of client credentials
2005-05-15 23:42:11 +00:00
*/
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 ,
2023-11-20 14:12:19 +13:00
struct loadparm_context * lp_ctx ,
2010-10-11 16:53:08 +11:00
struct tevent_context * event_ctx ,
2010-02-25 16:16:33 +11:00
krb5_ccache ccache ,
2010-05-01 10:33:08 +10:00
enum credentials_obtained * obtained ,
2010-02-25 16:16:33 +11:00
const char * * error_string )
2005-05-15 23:42:11 +00:00
{
krb5_error_code ret ;
2011-04-22 11:22:50 +02:00
const char * password ;
const char * self_service ;
const char * target_service ;
2005-05-15 23:42:11 +00:00
time_t kdc_time = 0 ;
2005-09-05 10:53:14 +00:00
krb5_principal princ ;
2010-03-03 13:24:52 +11:00
krb5_principal impersonate_principal ;
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 ) ;
2010-09-16 14:13:29 +10:00
krb5_get_init_creds_opt * krb_options ;
2023-11-20 14:12:19 +13:00
struct cli_credentials * fast_creds ;
2005-05-15 23:42:11 +00:00
if ( ! mem_ctx ) {
2010-02-25 16:16:33 +11:00
( * error_string ) = strerror ( ENOMEM ) ;
2005-08-29 04:30:22 +00:00
return ENOMEM ;
2005-05-15 23:42:11 +00:00
}
2010-05-01 10:33:08 +10:00
ret = principal_from_credentials ( mem_ctx , credentials , smb_krb5_context , & princ , obtained , error_string ) ;
2005-09-05 10:53:14 +00:00
if ( ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
2011-12-06 15:56:44 +11:00
if ( princ = = NULL ) {
( * error_string ) = talloc_asprintf ( credentials , " principal, username or realm was not specified in the credentials " ) ;
talloc_free ( mem_ctx ) ;
return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN ;
}
2010-03-03 13:24:52 +11:00
ret = impersonate_principal_from_credentials ( mem_ctx , credentials , smb_krb5_context , & impersonate_principal , error_string ) ;
if ( ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
2011-04-22 11:22:50 +02:00
self_service = cli_credentials_get_self_service ( credentials ) ;
2010-03-03 13:24:52 +11:00
target_service = cli_credentials_get_target_service ( credentials ) ;
2005-05-15 23:42:11 +00:00
password = cli_credentials_get_password ( credentials ) ;
2005-06-29 03:01:35 +00:00
2010-09-16 14:13:29 +10:00
/* setup the krb5 options we want */
if ( ( ret = krb5_get_init_creds_opt_alloc ( smb_krb5_context - > krb5_context , & krb_options ) ) ) {
( * error_string ) = talloc_asprintf ( credentials , " krb5_get_init_creds_opt_alloc failed (%s) \n " ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
2012-04-26 16:50:53 -04:00
# ifdef SAMBA4_USES_HEIMDAL /* Disable for now MIT reads defaults when needed */
2010-09-16 14:13:29 +10:00
/* get the defaults */
krb5_get_init_creds_opt_set_default_flags ( smb_krb5_context - > krb5_context , NULL , NULL , krb_options ) ;
2012-04-26 16:50:53 -04:00
# endif
2010-09-16 14:13:29 +10:00
/* set if we want a forwardable ticket */
switch ( cli_credentials_get_krb_forwardable ( credentials ) ) {
case CRED_AUTO_KRB_FORWARDABLE :
break ;
case CRED_NO_KRB_FORWARDABLE :
krb5_get_init_creds_opt_set_forwardable ( krb_options , FALSE ) ;
break ;
case CRED_FORCE_KRB_FORWARDABLE :
krb5_get_init_creds_opt_set_forwardable ( krb_options , TRUE ) ;
break ;
}
2012-04-26 16:50:53 -04:00
# ifdef SAMBA4_USES_HEIMDAL /* FIXME: MIT does not have this yet */
2011-07-24 22:02:21 +02:00
/*
* In order to work against windows KDCs even if we use
* the netbios domain name as realm , we need to add the following
* flags :
* KRB5_INIT_CREDS_NO_C_CANON_CHECK ;
* KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK ;
2014-05-07 08:24:15 +02:00
*
* On MIT : Set pkinit_eku_checking to none
2011-07-24 22:02:21 +02:00
*/
krb5_get_init_creds_opt_set_win2k ( smb_krb5_context - > krb5_context ,
krb_options , true ) ;
2019-09-13 16:04:30 +02:00
krb5_get_init_creds_opt_set_canonicalize ( smb_krb5_context - > krb5_context ,
krb_options , true ) ;
2014-08-01 13:11:41 +02:00
# else /* MIT */
krb5_get_init_creds_opt_set_canonicalize ( krb_options , true ) ;
2012-04-26 16:50:53 -04:00
# endif
2011-07-24 22:02:21 +02:00
2023-11-20 14:12:19 +13:00
fast_creds = cli_credentials_get_krb5_fast_armor_credentials ( credentials ) ;
if ( fast_creds ! = NULL ) {
# ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_CCACHE
struct ccache_container * fast_ccc = NULL ;
const char * fast_error_string = NULL ;
ret = cli_credentials_get_ccache ( fast_creds , event_ctx , lp_ctx , & fast_ccc , & fast_error_string ) ;
if ( ret ! = 0 ) {
( * error_string ) = talloc_asprintf ( credentials ,
" Obtaining the Kerberos FAST armor credentials failed: %s \n " ,
fast_error_string ) ;
return ret ;
}
krb5_get_init_creds_opt_set_fast_ccache ( smb_krb5_context - > krb5_context ,
krb_options ,
fast_ccc - > ccache ) ;
# else
* error_string = talloc_strdup ( credentials ,
" Using Kerberos FAST "
" armor credentials not possible "
" with this Kerberos library. "
" Modern MIT or Samba's embedded "
" Heimdal required " ) ;
return EINVAL ;
# endif
}
# ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_FLAGS
{
bool require_fast ;
/*
2023-11-29 10:42:36 +13:00
* This ensures that if FAST was required , but no armor
* credentials cache was specified , we proceed with ( eg )
* anonymous PKINIT
2023-11-20 14:12:19 +13:00
*/
require_fast = cli_credentials_get_krb5_require_fast_armor ( credentials ) ;
if ( require_fast ) {
krb5_get_init_creds_opt_set_fast_flags ( smb_krb5_context - > krb5_context ,
krb_options ,
KRB5_FAST_REQUIRED ) ;
}
}
# endif
2006-11-06 11:18:32 +00:00
tries = 2 ;
while ( tries - - ) {
2012-04-26 16:54:42 -04:00
# ifdef SAMBA4_USES_HEIMDAL
2010-10-11 16:53:08 +11:00
struct tevent_context * previous_ev ;
/* Do this every time, in case we have weird recursive issues here */
ret = smb_krb5_context_set_event_ctx ( smb_krb5_context , event_ctx , & previous_ev ) ;
if ( ret ) {
talloc_free ( mem_ctx ) ;
2023-10-06 11:03:52 +13:00
krb5_get_init_creds_opt_free ( smb_krb5_context - > krb5_context , krb_options ) ;
2010-10-11 16:53:08 +11:00
return ret ;
}
2012-04-21 16:35:48 -04:00
# endif
2006-11-06 11:18:32 +00:00
if ( password ) {
2012-04-26 12:06:24 -04:00
if ( impersonate_principal ) {
2016-08-29 11:59:18 +02:00
ret = smb_krb5_kinit_s4u2_ccache ( smb_krb5_context - > krb5_context ,
ccache ,
princ ,
password ,
impersonate_principal ,
self_service ,
target_service ,
krb_options ,
NULL ,
& kdc_time ) ;
2012-04-26 12:06:24 -04:00
} else {
2016-08-29 11:47:11 +02:00
ret = smb_krb5_kinit_password_ccache ( smb_krb5_context - > krb5_context ,
ccache ,
princ ,
password ,
target_service ,
krb_options ,
NULL ,
& kdc_time ) ;
2012-04-26 12:06:24 -04:00
}
2010-03-03 13:24:52 +11:00
} else if ( impersonate_principal ) {
2010-10-11 16:53:08 +11:00
talloc_free ( mem_ctx ) ;
2010-03-03 13:24:52 +11:00
( * error_string ) = " INTERNAL error: Cannot impersonate principal with just a keyblock. A password must be specified in the credentials " ;
2023-10-06 11:03:52 +13:00
krb5_get_init_creds_opt_free ( smb_krb5_context - > krb5_context , krb_options ) ;
2023-10-06 11:04:06 +13:00
# ifdef SAMBA4_USES_HEIMDAL
smb_krb5_context_remove_event_ctx ( smb_krb5_context , previous_ev , event_ctx ) ;
# endif
2010-03-03 13:24:52 +11:00
return EINVAL ;
2006-11-06 11:18:32 +00:00
} else {
/* No password available, try to use a keyblock instead */
2023-07-26 16:07:12 +02:00
2006-11-06 11:18:32 +00:00
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 ) ;
2010-02-25 16:16:33 +11:00
( * error_string ) = " kinit_to_ccache: No password available for kinit \n " ;
2010-09-16 14:13:29 +10:00
krb5_get_init_creds_opt_free ( smb_krb5_context - > krb5_context , krb_options ) ;
2012-04-21 16:35:48 -04:00
# ifdef SAMBA4_USES_HEIMDAL
2010-10-11 16:53:08 +11:00
smb_krb5_context_remove_event_ctx ( smb_krb5_context , previous_ev , event_ctx ) ;
2012-04-21 16:35:48 -04:00
# endif
2006-11-06 11:18:32 +00:00
return EINVAL ;
}
2012-04-26 16:52:55 -04:00
ret = smb_krb5_keyblock_init_contents ( smb_krb5_context - > krb5_context ,
2009-08-18 12:08:37 +10:00
ENCTYPE_ARCFOUR_HMAC ,
2023-07-26 16:07:12 +02:00
mach_pwd - > hash , sizeof ( mach_pwd - > hash ) ,
2006-11-06 11:18:32 +00:00
& keyblock ) ;
2023-07-26 16:07:12 +02:00
2006-11-06 11:18:32 +00:00
if ( ret = = 0 ) {
2016-08-29 11:33:24 +02:00
ret = smb_krb5_kinit_keyblock_ccache ( smb_krb5_context - > krb5_context ,
ccache ,
princ ,
& keyblock ,
target_service ,
krb_options ,
NULL ,
& kdc_time ) ;
2006-11-06 11:18:32 +00:00
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
2012-04-21 16:35:48 -04:00
# ifdef SAMBA4_USES_HEIMDAL
2010-10-11 16:53:08 +11:00
smb_krb5_context_remove_event_ctx ( smb_krb5_context , previous_ev , event_ctx ) ;
2012-04-21 16:35:48 -04:00
# endif
2010-10-11 16:53:08 +11: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
}
}
2010-09-16 14:13:29 +10:00
krb5_get_init_creds_opt_free ( smb_krb5_context - > krb5_context , krb_options ) ;
2005-05-15 23:42:11 +00:00
if ( ret = = KRB5KRB_AP_ERR_SKEW | | ret = = KRB5_KDCREP_SKEW ) {
2010-02-25 16:16:33 +11:00
( * error_string ) = talloc_asprintf ( credentials , " kinit for %s failed (%s) \n " ,
cli_credentials_get_principal ( credentials , mem_ctx ) ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ;
2005-05-15 23:42:11 +00:00
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 ) ;
}
2023-07-26 16:07:12 +02:00
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 ,
2023-11-20 14:12:19 +13:00
lp_ctx ,
2010-10-11 16:53:08 +11:00
event_ctx ,
2010-05-01 10:33:08 +10:00
ccache , obtained ,
error_string ) ;
2006-05-07 18:21:55 +00:00
}
2010-09-16 14:13:29 +10:00
2005-05-15 23:42:11 +00:00
if ( ret ) {
2010-02-25 16:16:33 +11:00
( * error_string ) = talloc_asprintf ( credentials , " kinit for %s failed (%s) \n " ,
cli_credentials_get_principal ( credentials , mem_ctx ) ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ;
2005-05-15 23:42:11 +00:00
talloc_free ( mem_ctx ) ;
2005-08-29 04:30:22 +00:00
return ret ;
2014-08-01 13:11:41 +02:00
}
DEBUG ( 10 , ( " kinit for %s succeeded \n " ,
cli_credentials_get_principal ( credentials , mem_ctx ) ) ) ;
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
2011-04-14 15:42:42 +10:00
static krb5_error_code free_keytab_container ( 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
}
2011-04-14 15:42:42 +10:00
krb5_error_code smb_krb5_get_keytab_container ( TALLOC_CTX * mem_ctx ,
2012-03-30 19:33:53 -04:00
struct smb_krb5_context * smb_krb5_context ,
2012-03-31 03:23:19 -04:00
krb5_keytab opt_keytab ,
2012-03-30 19:33:53 -04:00
const char * keytab_name ,
struct keytab_container * * ktc )
2005-12-21 22:02:52 +00:00
{
krb5_keytab keytab ;
2008-09-09 17:37:33 +02:00
krb5_error_code ret ;
2012-03-31 03:23:19 -04:00
2023-07-26 16:28:36 +02:00
/*
* Start with talloc ( ) , talloc_reference ( ) and only then call
* krb5_kt_resolve ( ) . If any of them fails , the cleanup code is simpler .
*/
* ktc = talloc ( mem_ctx , struct keytab_container ) ;
if ( ! * ktc ) {
return ENOMEM ;
}
( * ktc ) - > smb_krb5_context = talloc_reference ( * ktc , smb_krb5_context ) ;
if ( ( * ktc ) - > smb_krb5_context = = NULL ) {
TALLOC_FREE ( * ktc ) ;
return ENOMEM ;
}
2012-03-31 03:23:19 -04:00
if ( opt_keytab ) {
keytab = opt_keytab ;
} else {
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 (
2012-03-30 19:33:53 -04:00
smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ) ;
2023-07-26 16:28:36 +02:00
TALLOC_FREE ( * ktc ) ;
2012-03-31 03:23:19 -04:00
return ret ;
}
2005-12-21 22:02:52 +00:00
}
( * ktc ) - > keytab = keytab ;
2012-08-30 07:49:21 +10:00
( * ktc ) - > password_based = false ;
2011-04-14 15:42:42 +10:00
talloc_set_destructor ( * ktc , free_keytab_container ) ;
2005-12-21 22:02:52 +00:00
return 0 ;
}
2015-04-17 15:53:41 +02:00
/*
* 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 ' .
*/
krb5_error_code smb_krb5_remove_obsolete_keytab_entries ( TALLOC_CTX * mem_ctx ,
krb5_context context ,
krb5_keytab keytab ,
uint32_t num_principals ,
krb5_principal * principals ,
krb5_kvno kvno ,
bool * found_previous ,
const char * * error_string )
{
TALLOC_CTX * tmp_ctx ;
krb5_error_code code ;
krb5_kt_cursor cursor ;
tmp_ctx = talloc_new ( mem_ctx ) ;
if ( tmp_ctx = = NULL ) {
* error_string = " Cannot allocate tmp_ctx " ;
return ENOMEM ;
}
* found_previous = true ;
code = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
switch ( code ) {
case 0 :
break ;
# ifdef HEIM_ERR_OPNOTSUPP
case HEIM_ERR_OPNOTSUPP :
# endif
case ENOENT :
case KRB5_KT_END :
/* no point enumerating if there isn't anything here */
code = 0 ;
goto done ;
default :
* error_string = talloc_asprintf ( mem_ctx ,
" failed to open keytab for read of old entries: %s \n " ,
2024-03-14 15:14:55 +13:00
smb_get_krb5_error_message ( context , code , tmp_ctx ) ) ;
2015-04-17 15:53:41 +02:00
goto done ;
}
do {
2015-07-17 09:03:25 +02:00
krb5_kvno old_kvno = kvno - 1 ;
2015-04-17 15:53:41 +02:00
krb5_keytab_entry entry ;
bool matched = false ;
uint32_t i ;
code = krb5_kt_next_entry ( context , keytab , & entry , & cursor ) ;
if ( code ) {
break ;
}
for ( i = 0 ; i < num_principals ; i + + ) {
krb5_boolean ok ;
ok = smb_krb5_kt_compare ( context ,
& entry ,
principals [ i ] ,
0 ,
0 ) ;
if ( ok ) {
matched = true ;
break ;
}
}
if ( ! matched ) {
/*
* Free the entry , it wasn ' t the one we were looking
* for anyway
*/
krb5_kt_free_entry ( context , & entry ) ;
/* Make sure we do not double free */
ZERO_STRUCT ( entry ) ;
continue ;
}
2015-07-17 09:03:25 +02:00
/*
* Delete it , if it is not kvno - 1.
*
* Some keytab files store the kvno only in 8 bits . Limit the
* compare to 8 bits , so that we don ' t miss old keys and delete
* them .
*/
if ( ( entry . vno & 0xff ) ! = ( old_kvno & 0xff ) ) {
2015-04-17 15:53:41 +02:00
krb5_error_code rc ;
/* Release the enumeration. We are going to
* have to start this from the top again ,
* because deletes during enumeration may not
* always be consistent .
*
* Also , the enumeration locks a FILE : keytab
*/
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
code = krb5_kt_remove_entry ( context , keytab , & entry ) ;
krb5_kt_free_entry ( context , & entry ) ;
/* Make sure we do not double free */
ZERO_STRUCT ( entry ) ;
/* Deleted: Restart from the top */
rc = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( rc ! = 0 ) {
krb5_kt_free_entry ( context , & entry ) ;
/* Make sure we do not double free */
ZERO_STRUCT ( entry ) ;
DEBUG ( 1 , ( " failed to restart enumeration of keytab: %s \n " ,
smb_get_krb5_error_message ( context ,
code ,
tmp_ctx ) ) ) ;
talloc_free ( tmp_ctx ) ;
return rc ;
}
if ( code ! = 0 ) {
break ;
}
} else {
* found_previous = true ;
}
/* Free the entry, we don't need it any more */
krb5_kt_free_entry ( context , & entry ) ;
/* Make sure we do not double free */
ZERO_STRUCT ( entry ) ;
2018-05-01 11:10:50 +12:00
} while ( code = = 0 ) ;
2015-04-17 15:53:41 +02:00
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
switch ( code ) {
case 0 :
break ;
case ENOENT :
case KRB5_KT_END :
break ;
default :
* error_string = talloc_asprintf ( mem_ctx ,
" failed in deleting old entries for principal: %s \n " ,
smb_get_krb5_error_message ( context ,
code ,
2024-03-14 15:14:55 +13:00
tmp_ctx ) ) ;
2024-03-14 16:55:19 +13:00
goto done ;
2015-04-17 15:53:41 +02:00
}
code = 0 ;
done :
talloc_free ( tmp_ctx ) ;
return code ;
}
2024-03-06 17:43:47 +13:00
/*
* Walk the keytab , looking for entries of this principal name ,
* with KVNO and key equal
*
* These entries do not need to be replaced , so we want to tell the caller not to add them again
*
* Inspired by the code in Samba3 for ' use kerberos keytab ' .
*/
krb5_error_code smb_krb5_is_exact_entry_in_keytab ( TALLOC_CTX * mem_ctx ,
krb5_context context ,
krb5_keytab keytab ,
krb5_keytab_entry * to_match ,
bool * found ,
const char * * error_string )
{
TALLOC_CTX * tmp_ctx ;
krb5_error_code code ;
krb5_kt_cursor cursor ;
tmp_ctx = talloc_new ( mem_ctx ) ;
if ( tmp_ctx = = NULL ) {
* error_string = " Cannot allocate tmp_ctx " ;
return ENOMEM ;
}
* found = false ;
code = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
switch ( code ) {
case 0 :
break ;
# ifdef HEIM_ERR_OPNOTSUPP
case HEIM_ERR_OPNOTSUPP :
# endif
case ENOENT :
case KRB5_KT_END :
/* no point enumerating if there isn't anything here */
code = 0 ;
goto done ;
default :
* error_string = talloc_asprintf ( mem_ctx ,
" failed to open keytab for read of existing entries: %s \n " ,
2024-03-14 15:14:55 +13:00
smb_get_krb5_error_message ( context , code , tmp_ctx ) ) ;
2024-03-06 17:43:47 +13:00
goto done ;
}
do {
krb5_keytab_entry entry ;
bool matched = false ;
krb5_boolean ok ;
code = krb5_kt_next_entry ( context , keytab , & entry , & cursor ) ;
if ( code ) {
break ;
}
ok = smb_krb5_kt_compare ( context ,
& entry ,
to_match - > principal ,
to_match - > vno ,
KRB5_KEY_TYPE ( KRB5_KT_KEY ( to_match ) ) ) ;
if ( ok ) {
/* This is not a security check, constant time is not required */
if ( ( KRB5_KEY_LENGTH ( KRB5_KT_KEY ( & entry ) ) = = KRB5_KEY_LENGTH ( KRB5_KT_KEY ( to_match ) ) )
& & memcmp ( KRB5_KEY_DATA ( KRB5_KT_KEY ( & entry ) ) , KRB5_KEY_DATA ( KRB5_KT_KEY ( to_match ) ) ,
KRB5_KEY_LENGTH ( KRB5_KT_KEY ( & entry ) ) ) = = 0 ) {
matched = true ;
}
}
/* Free the entry, we don't need it any more */
krb5_kt_free_entry ( context , & entry ) ;
/* Make sure we do not double free */
ZERO_STRUCT ( entry ) ;
if ( matched ) {
* found = true ;
break ;
}
} while ( code = = 0 ) ;
krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
switch ( code ) {
case 0 :
break ;
case ENOENT :
case KRB5_KT_END :
break ;
default :
* error_string = talloc_asprintf ( mem_ctx ,
" failed in checking old entries for principal: %s \n " ,
smb_get_krb5_error_message ( context ,
code ,
2024-03-14 15:14:55 +13:00
tmp_ctx ) ) ;
2024-03-06 17:43:47 +13:00
goto done ;
}
code = 0 ;
done :
talloc_free ( tmp_ctx ) ;
return code ;
}