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"
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"
# include <ldb.h>
2010-09-23 17:01:44 +10:00
# include "param/secrets.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 ;
2010-09-24 14:17:58 +10:00
const char * string_form ; /* Optional */
2005-06-22 02:12:26 +00:00
} ;
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 ;
}
2010-03-03 13:24:52 +11:00
static krb5_error_code parse_principal ( TALLOC_CTX * parent_ctx ,
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 ;
}
ret = krb5_parse_name ( smb_krb5_context - > krb5_context ,
princ_string , princ ) ;
if ( ret ) {
( * error_string ) = smb_get_krb5_error_message ( smb_krb5_context - > krb5_context , ret , parent_ctx ) ;
return ret ;
}
mem_ctx = talloc ( parent_ctx , struct principal_container ) ;
if ( ! mem_ctx ) {
( * error_string ) = error_message ( ENOMEM ) ;
return ENOMEM ;
}
/* This song-and-dance effectivly puts the principal
* into talloc , so we can ' t loose it . */
mem_ctx - > smb_krb5_context = talloc_reference ( mem_ctx , smb_krb5_context ) ;
mem_ctx - > principal = * princ ;
talloc_set_destructor ( mem_ctx , free_principal ) ;
return 0 ;
}
2010-09-24 14:17:58 +10:00
static krb5_error_code principals_from_msg ( TALLOC_CTX * parent_ctx ,
struct ldb_message * msg ,
struct smb_krb5_context * smb_krb5_context ,
struct principal_container * * * principals_out ,
const char * * error_string )
2005-06-22 02:12:26 +00:00
{
2010-09-24 14:17:58 +10:00
unsigned int i ;
2005-06-22 02:12:26 +00:00
krb5_error_code ret ;
2010-09-23 17:01:44 +10:00
char * upper_realm ;
const char * realm = ldb_msg_find_attr_as_string ( msg , " realm " , NULL ) ;
const char * samAccountName = ldb_msg_find_attr_as_string ( msg , " samAccountName " , NULL ) ;
2010-09-24 14:17:58 +10:00
struct ldb_message_element * spn_el = ldb_msg_find_element ( msg , " servicePrincipalName " ) ;
2010-09-23 17:01:44 +10:00
TALLOC_CTX * tmp_ctx ;
2010-09-24 14:17:58 +10:00
struct principal_container * * principals ;
tmp_ctx = talloc_new ( parent_ctx ) ;
2010-09-23 17:01:44 +10:00
if ( ! tmp_ctx ) {
* error_string = " Cannot allocate tmp_ctx " ;
return ENOMEM ;
}
if ( ! realm ) {
* error_string = " Cannot have a kerberos secret in secrets.ldb without a realm " ;
return EINVAL ;
}
upper_realm = strupper_talloc ( tmp_ctx , realm ) ;
if ( ! upper_realm ) {
2010-09-24 14:17:58 +10:00
talloc_free ( tmp_ctx ) ;
2010-09-23 17:01:44 +10:00
* error_string = " Cannot allocate full upper case realm " ;
return ENOMEM ;
}
2010-09-24 14:17:58 +10:00
principals = talloc_array ( tmp_ctx , struct principal_container * , spn_el ? ( spn_el - > num_values + 2 ) : 2 ) ;
spn_el = ldb_msg_find_element ( msg , " servicePrincipalName " ) ;
for ( i = 0 ; spn_el & & i < spn_el - > num_values ; i + + ) {
principals [ i ] = talloc ( principals , struct principal_container ) ;
if ( ! principals [ i ] ) {
talloc_free ( tmp_ctx ) ;
* error_string = " Cannot allocate mem_ctx " ;
return ENOMEM ;
}
principals [ i ] - > smb_krb5_context = talloc_reference ( principals [ i ] , smb_krb5_context ) ;
principals [ i ] - > string_form = talloc_asprintf ( principals [ i ] , " %*.*s@%s " ,
( int ) spn_el - > values [ i ] . length ,
( int ) spn_el - > values [ i ] . length ,
( const char * ) spn_el - > values [ i ] . data , upper_realm ) ;
if ( ! principals [ i ] - > string_form ) {
talloc_free ( tmp_ctx ) ;
* error_string = " Cannot allocate full samAccountName " ;
return ENOMEM ;
}
ret = krb5_parse_name ( smb_krb5_context - > krb5_context ,
principals [ i ] - > string_form , & principals [ i ] - > principal ) ;
2010-09-23 17:01:44 +10:00
2010-09-24 14:17:58 +10:00
if ( ret ) {
talloc_free ( tmp_ctx ) ;
( * error_string ) = smb_get_krb5_error_message ( smb_krb5_context - > krb5_context , ret , parent_ctx ) ;
return ret ;
}
/* This song-and-dance effectivly puts the principal
* into talloc , so we can ' t loose it . */
talloc_set_destructor ( principals [ i ] , free_principal ) ;
}
2010-09-23 17:01:44 +10:00
if ( samAccountName ) {
2010-09-24 14:17:58 +10:00
principals [ i ] = talloc ( principals , struct principal_container ) ;
if ( ! principals [ i ] ) {
talloc_free ( tmp_ctx ) ;
* error_string = " Cannot allocate mem_ctx " ;
return ENOMEM ;
}
principals [ i ] - > smb_krb5_context = talloc_reference ( principals [ i ] , smb_krb5_context ) ;
principals [ i ] - > string_form = talloc_asprintf ( parent_ctx , " %s@%s " , samAccountName , upper_realm ) ;
if ( ! principals [ i ] - > string_form ) {
talloc_free ( tmp_ctx ) ;
2010-09-23 17:01:44 +10:00
* error_string = " Cannot allocate full samAccountName " ;
return ENOMEM ;
}
2010-09-24 14:17:58 +10:00
ret = krb5_make_principal ( smb_krb5_context - > krb5_context , & principals [ i ] - > principal , upper_realm , samAccountName ,
2010-09-23 17:01:44 +10:00
NULL ) ;
2010-09-24 14:17:58 +10:00
if ( ret ) {
talloc_free ( tmp_ctx ) ;
( * error_string ) = smb_get_krb5_error_message ( smb_krb5_context - > krb5_context , ret , parent_ctx ) ;
return ret ;
2010-09-23 17:01:44 +10:00
}
/* This song-and-dance effectivly puts the principal
* into talloc , so we can ' t loose it . */
2010-09-24 14:17:58 +10:00
talloc_set_destructor ( principals [ i ] , free_principal ) ;
i + + ;
2010-09-23 17:01:44 +10:00
}
2010-09-24 14:17:58 +10:00
principals [ i ] = NULL ;
* principals_out = talloc_steal ( parent_ctx , principals ) ;
2010-09-23 17:01:44 +10:00
talloc_free ( tmp_ctx ) ;
return ret ;
}
static krb5_error_code salt_principal_from_msg ( TALLOC_CTX * parent_ctx ,
struct ldb_message * msg ,
struct smb_krb5_context * smb_krb5_context ,
krb5_principal * salt_princ ,
const char * * error_string )
{
const char * salt_principal = ldb_msg_find_attr_as_string ( msg , " saltPrincipal " , NULL ) ;
const char * samAccountName = ldb_msg_find_attr_as_string ( msg , " samAccountName " , NULL ) ;
const char * realm = ldb_msg_find_attr_as_string ( msg , " realm " , NULL ) ;
if ( salt_principal ) {
return parse_principal ( parent_ctx , salt_principal , smb_krb5_context , salt_princ , error_string ) ;
} else if ( samAccountName ) {
krb5_error_code ret ;
char * machine_username ;
char * salt_body ;
char * lower_realm ;
char * upper_realm ;
TALLOC_CTX * tmp_ctx ;
struct principal_container * mem_ctx = talloc ( parent_ctx , struct principal_container ) ;
if ( ! mem_ctx ) {
* error_string = " Cannot allocate mem_ctx " ;
return ENOMEM ;
}
tmp_ctx = talloc_new ( mem_ctx ) ;
if ( ! tmp_ctx ) {
talloc_free ( mem_ctx ) ;
* error_string = " Cannot allocate tmp_ctx " ;
return ENOMEM ;
}
if ( ! realm ) {
* error_string = " Cannot have a kerberos secret in secrets.ldb without a realm " ;
return EINVAL ;
}
2005-10-20 10:28:16 +00:00
2010-09-23 17:01:44 +10:00
machine_username = talloc_strdup ( tmp_ctx , samAccountName ) ;
2005-10-20 10:28:16 +00:00
if ( ! machine_username ) {
talloc_free ( mem_ctx ) ;
2010-09-23 17:01:44 +10:00
* error_string = " Cannot duplicate samAccountName " ;
2005-10-20 10:28:16 +00:00
return ENOMEM ;
}
if ( machine_username [ strlen ( machine_username ) - 1 ] = = ' $ ' ) {
machine_username [ strlen ( machine_username ) - 1 ] = ' \0 ' ;
}
2010-09-23 17:01:44 +10:00
lower_realm = strlower_talloc ( tmp_ctx , realm ) ;
2005-10-20 10:28:16 +00:00
if ( ! lower_realm ) {
talloc_free ( mem_ctx ) ;
2010-09-23 17:01:44 +10:00
* error_string = " Cannot allocate to lower case realm " ;
return ENOMEM ;
}
upper_realm = strupper_talloc ( tmp_ctx , realm ) ;
if ( ! upper_realm ) {
talloc_free ( mem_ctx ) ;
* error_string = " Cannot allocate to upper case realm " ;
2005-10-20 10:28:16 +00:00
return ENOMEM ;
}
2010-09-23 17:01:44 +10:00
salt_body = talloc_asprintf ( tmp_ctx , " %s.%s " , machine_username ,
2005-10-20 10:28:16 +00:00
lower_realm ) ;
2010-09-23 17:01:44 +10:00
talloc_free ( lower_realm ) ;
talloc_free ( machine_username ) ;
2005-10-20 10:28:16 +00:00
if ( ! salt_body ) {
talloc_free ( mem_ctx ) ;
2010-09-23 17:01:44 +10:00
* error_string = " Cannot form salt principal body " ;
return ENOMEM ;
2005-10-20 10:28:16 +00:00
}
ret = krb5_make_principal ( smb_krb5_context - > krb5_context , salt_princ ,
2010-09-23 17:01:44 +10:00
upper_realm ,
2005-10-20 10:28:16 +00:00
" host " , salt_body , NULL ) ;
2010-03-03 13:24:52 +11:00
if ( ret = = 0 ) {
/* This song-and-dance effectivly puts the principal
* into talloc , so we can ' t loose it . */
mem_ctx - > smb_krb5_context = talloc_reference ( mem_ctx , smb_krb5_context ) ;
mem_ctx - > principal = * salt_princ ;
talloc_set_destructor ( mem_ctx , free_principal ) ;
2010-09-23 17:01:44 +10:00
} else {
( * error_string ) = smb_get_krb5_error_message ( smb_krb5_context - > krb5_context , ret , parent_ctx ) ;
2010-03-03 13:24:52 +11:00
}
2010-09-24 14:17:58 +10:00
talloc_free ( tmp_ctx ) ;
2010-09-23 17:01:44 +10:00
return ret ;
} else {
2010-09-24 14:17:58 +10:00
( * error_string ) = " Cannot determine salt principal, no saltPrincipal or samAccountName specified " ;
return EINVAL ;
}
2005-06-22 02:12:26 +00:00
}
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 ) . */
2010-09-23 17:01:44 +10:00
krb5_error_code principal_from_credentials ( TALLOC_CTX * parent_ctx ,
2008-03-17 15:22:52 +11:00
struct cli_credentials * credentials ,
struct smb_krb5_context * smb_krb5_context ,
2010-02-25 16:16:33 +11:00
krb5_principal * princ ,
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-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 ) ;
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 ;
}
2010-05-01 10:33:08 +10:00
princ_string = cli_credentials_get_principal_and_obtained ( credentials , mem_ctx , obtained ) ;
2005-09-05 10:53:14 +00:00
if ( ! princ_string ) {
2010-03-03 13:24:52 +11:00
( * error_string ) = error_message ( ENOMEM ) ;
return ENOMEM ;
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
2010-03-03 13:24:52 +11:00
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 )
{
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
}
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 ,
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 ;
2010-03-03 13:24:52 +11:00
const char * password , * 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 ;
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 ;
}
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 ;
}
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 ;
}
/* get the defaults */
krb5_get_init_creds_opt_set_default_flags ( smb_krb5_context - > krb5_context , NULL , NULL , krb_options ) ;
/* 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 ;
}
2006-11-06 11:18:32 +00:00
tries = 2 ;
while ( tries - - ) {
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 ) ;
return ret ;
}
2006-11-06 11:18:32 +00:00
if ( password ) {
ret = kerberos_kinit_password_cc ( smb_krb5_context - > krb5_context , ccache ,
2010-03-03 13:24:52 +11:00
princ , password ,
impersonate_principal , target_service ,
2010-09-16 14:13:29 +10:00
krb_options ,
2010-03-03 13:24:52 +11:00
NULL , & kdc_time ) ;
} 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 " ;
return EINVAL ;
2006-11-06 11:18:32 +00:00
} 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 ) ;
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 ) ;
2010-10-11 16:53:08 +11:00
smb_krb5_context_remove_event_ctx ( smb_krb5_context , previous_ev , event_ctx ) ;
2006-11-06 11:18:32 +00:00
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 ,
2010-03-03 13:24:52 +11:00
princ , & keyblock ,
2010-09-16 14:13:29 +10:00
target_service , krb_options ,
2010-03-03 13:24:52 +11:00
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
2010-10-11 16:53:08 +11:00
smb_krb5_context_remove_event_ctx ( smb_krb5_context , previous_ev , event_ctx ) ;
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 ) ;
}
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 ,
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 ;
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 ,
2010-10-02 07:12:48 +10:00
struct principal_container * * principals ,
2005-12-01 05:09:28 +00:00
krb5_principal salt_princ ,
int kvno ,
const char * password_s ,
struct smb_krb5_context * smb_krb5_context ,
2010-09-23 17:01:44 +10:00
krb5_enctype * enctypes ,
2010-09-24 14:17:58 +10:00
krb5_keytab keytab ,
const char * * error_string )
2005-06-22 02:12:26 +00:00
{
2010-10-02 07:12:48 +10:00
unsigned int i , p ;
2005-06-22 02:12:26 +00:00
krb5_error_code ret ;
2005-12-01 05:09:28 +00:00
krb5_data password ;
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 ) ;
2010-09-23 17:01:44 +10:00
for ( i = 0 ; enctypes [ i ] ; i + + ) {
2005-12-01 05:09:28 +00:00
krb5_keytab_entry entry ;
2010-10-01 13:07:42 -07:00
ZERO_STRUCT ( entry ) ;
2011-04-14 15:40:28 +10:00
ret = create_kerberos_key_from_string_direct ( 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
return ret ;
}
2010-10-02 07:12:48 +10:00
entry . vno = kvno ;
for ( p = 0 ; principals [ p ] ; p + + ) {
entry . principal = principals [ p ] - > principal ;
ret = krb5_kt_add_entry ( smb_krb5_context - > krb5_context , keytab , & entry ) ;
if ( ret ! = 0 ) {
char * k5_error_string = smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , NULL ) ;
* error_string = talloc_asprintf ( parent_ctx , " Failed to add enctype %d entry for %s(kvno %d) to keytab: %s \n " ,
( int ) enctypes [ i ] ,
principals [ p ] - > string_form ,
kvno ,
k5_error_string ) ;
talloc_free ( k5_error_string ) ;
krb5_free_keyblock_contents ( smb_krb5_context - > krb5_context , & entry . keyblock ) ;
return ret ;
}
2005-12-01 05:09:28 +00:00
2010-10-02 07:12:48 +10:00
DEBUG ( 5 , ( " Added %s(kvno %d) to keytab (enctype %d) \n " ,
principals [ p ] - > string_form , kvno ,
( int ) enctypes [ i ] ) ) ;
}
2005-12-01 05:09:28 +00:00
krb5_free_keyblock_contents ( smb_krb5_context - > krb5_context , & entry . keyblock ) ;
}
return 0 ;
}
2008-09-09 17:37:33 +02:00
static krb5_error_code create_keytab ( TALLOC_CTX * parent_ctx ,
2010-09-23 17:01:44 +10:00
struct ldb_message * msg ,
2010-09-24 14:17:58 +10:00
struct principal_container * * principals ,
2010-09-23 17:01:44 +10:00
struct smb_krb5_context * smb_krb5_context ,
krb5_keytab keytab ,
2010-09-24 14:17:58 +10:00
bool add_old ,
const char * * error_string )
2005-12-01 05:09:28 +00:00
{
krb5_error_code ret ;
const char * password_s ;
const char * old_secret ;
int kvno ;
2010-09-23 17:01:44 +10:00
uint32_t enctype_bitmap ;
2005-12-01 05:09:28 +00:00
krb5_principal salt_princ ;
2010-09-23 17:01:44 +10:00
krb5_enctype * enctypes ;
2005-12-01 05:09:28 +00:00
TALLOC_CTX * mem_ctx = talloc_new ( parent_ctx ) ;
if ( ! mem_ctx ) {
2010-09-24 14:17:58 +10:00
* error_string = " unable to allocate tmp_ctx for create_keytab " ;
2005-12-01 05:09:28 +00:00
return ENOMEM ;
}
/* The salt used to generate these entries may be different however, fetch that */
2010-09-23 17:01:44 +10:00
ret = salt_principal_from_msg ( mem_ctx , msg ,
smb_krb5_context ,
2010-09-24 14:17:58 +10:00
& salt_princ , error_string ) ;
2005-09-05 10:53:14 +00:00
if ( ret ) {
talloc_free ( mem_ctx ) ;
2005-10-20 03:47:55 +00:00
return ret ;
2005-06-22 02:12:26 +00:00
}
2010-09-24 14:17:58 +10:00
kvno = ldb_msg_find_attr_as_int ( msg , " msDS-KeyVersionNumber " , 0 ) ;
2005-12-01 05:09:28 +00:00
/* Finally, do the dance to get the password to put in the entry */
2010-09-23 17:01:44 +10:00
password_s = ldb_msg_find_attr_as_string ( msg , " secret " , NULL ) ;
2010-09-26 12:34:58 +10:00
if ( ! password_s ) {
/* There is no password here, so nothing to do */
talloc_free ( mem_ctx ) ;
return 0 ;
}
2010-09-24 14:17:58 +10:00
if ( add_old & & kvno ! = 0 ) {
old_secret = ldb_msg_find_attr_as_string ( msg , " priorSecret " , NULL ) ;
} else {
old_secret = NULL ;
}
2005-06-29 03:01:35 +00:00
2010-09-23 17:01:44 +10:00
enctype_bitmap = ( uint32_t ) ldb_msg_find_attr_as_int ( msg , " msDS-SupportedEncryptionTypes " , ENC_ALL_TYPES ) ;
ret = kerberos_enctype_bitmap_to_enctypes ( mem_ctx , enctype_bitmap , & enctypes ) ;
if ( ret ) {
2010-09-24 14:17:58 +10:00
* error_string = talloc_asprintf ( parent_ctx , " create_keytab: generating list of encryption types failed (%s) \n " ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ;
2005-12-01 05:09:28 +00:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2005-06-29 03:01:35 +00:00
2010-10-02 07:12:48 +10:00
ret = keytab_add_keys ( mem_ctx , principals ,
salt_princ ,
kvno , password_s , smb_krb5_context ,
enctypes , keytab , error_string ) ;
if ( ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
if ( old_secret ) {
ret = keytab_add_keys ( mem_ctx , principals ,
2010-09-24 14:17:58 +10:00
salt_princ ,
2010-10-02 07:12:48 +10:00
kvno - 1 , old_secret , smb_krb5_context ,
2010-09-24 14:17:58 +10:00
enctypes , keytab , error_string ) ;
if ( ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
2005-12-01 05:09:28 +00:00
}
talloc_free ( mem_ctx ) ;
2010-09-24 14:17:58 +10:00
return ret ;
2005-12-01 05:09:28 +00: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 ' .
*
*/
static krb5_error_code remove_old_entries ( TALLOC_CTX * parent_ctx ,
2010-09-23 17:01:44 +10:00
struct ldb_message * msg ,
2010-09-24 14:17:58 +10:00
struct principal_container * * principals ,
2010-09-23 17:01:44 +10:00
bool delete_all_kvno ,
2005-12-01 05:09:28 +00:00
struct smb_krb5_context * smb_krb5_context ,
2010-09-24 14:17:58 +10:00
krb5_keytab keytab , bool * found_previous ,
const char * * error_string )
2005-12-01 05:09:28 +00:00
{
krb5_error_code ret , ret2 ;
krb5_kt_cursor cursor ;
int kvno ;
TALLOC_CTX * mem_ctx = talloc_new ( parent_ctx ) ;
2010-02-25 16:16:33 +11:00
2005-12-01 05:09:28 +00:00
if ( ! mem_ctx ) {
return ENOMEM ;
}
2007-10-06 22:16:19 +00:00
* found_previous = false ;
2005-06-22 02:12:26 +00:00
2010-09-23 17:01:44 +10:00
kvno = ldb_msg_find_attr_as_int ( msg , " msDS-KeyVersionNumber " , 0 ) ;
2005-10-20 03:47:55 +00:00
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 :
2010-09-24 14:17:58 +10:00
* error_string = talloc_asprintf ( parent_ctx , " failed to open keytab for read of old entries: %s \n " ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ;
2005-12-01 05:09:28 +00:00
talloc_free ( mem_ctx ) ;
return ret ;
}
while ( ! ret ) {
2010-09-24 14:17:58 +10:00
unsigned int i ;
bool matched = false ;
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
}
2010-09-24 14:17:58 +10:00
for ( i = 0 ; principals [ i ] ; i + + ) {
/* if it matches our principal */
if ( krb5_kt_compare ( smb_krb5_context - > krb5_context , & entry , principals [ i ] - > principal , 0 , 0 ) ) {
matched = true ;
break ;
}
}
if ( ! matched ) {
2005-12-01 05:09:28 +00:00
/* 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 :
2010-09-24 14:17:58 +10:00
* error_string = talloc_asprintf ( parent_ctx , " failed in deleting old entries for principal: %s \n " ,
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context ,
ret , mem_ctx ) ) ;
2005-12-01 05:09:28 +00:00
}
talloc_free ( mem_ctx ) ;
return ret ;
}
2005-10-20 03:47:55 +00:00
2010-09-24 14:17:58 +10:00
krb5_error_code smb_krb5_update_keytab ( TALLOC_CTX * parent_ctx ,
struct smb_krb5_context * smb_krb5_context ,
2010-09-23 17:01:44 +10:00
struct ldb_context * ldb ,
struct ldb_message * msg ,
2010-09-24 14:17:58 +10:00
bool delete_all_kvno ,
const char * * error_string )
2005-12-01 05:09:28 +00:00
{
krb5_error_code ret ;
2007-10-06 22:16:19 +00:00
bool found_previous ;
2010-09-23 17:01:44 +10:00
TALLOC_CTX * mem_ctx = talloc_new ( NULL ) ;
struct keytab_container * keytab_container ;
2010-09-24 14:17:58 +10:00
struct principal_container * * principals ;
2010-09-23 17:01:44 +10:00
const char * keytab_name ;
2005-12-01 05:09:28 +00:00
if ( ! mem_ctx ) {
return ENOMEM ;
}
2007-04-28 16:38:06 +00:00
2010-09-23 17:01:44 +10:00
keytab_name = keytab_name_from_msg ( mem_ctx , ldb , msg ) ;
if ( ! keytab_name ) {
return ENOENT ;
}
ret = smb_krb5_open_keytab ( mem_ctx , smb_krb5_context , keytab_name , & keytab_container ) ;
if ( ret ! = 0 ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
DEBUG ( 5 , ( " Opened keytab %s \n " , keytab_name ) ) ;
2010-09-24 14:17:58 +10:00
/* Get the principal we will store the new keytab entries under */
ret = principals_from_msg ( mem_ctx , msg , smb_krb5_context , & principals , error_string ) ;
2005-12-01 05:09:28 +00:00
if ( ret ! = 0 ) {
2010-09-24 14:17:58 +10:00
* error_string = talloc_asprintf ( parent_ctx , " Failed to load principals from ldb message: %s \n " , * error_string ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
ret = remove_old_entries ( mem_ctx , msg , principals , delete_all_kvno ,
smb_krb5_context , keytab_container - > keytab , & found_previous , error_string ) ;
if ( ret ! = 0 ) {
* error_string = talloc_asprintf ( parent_ctx , " Failed to remove old principals from keytab: %s \n " , * error_string ) ;
2005-12-01 05:09:28 +00:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2010-09-23 17:01:44 +10:00
if ( ! delete_all_kvno ) {
/* 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 */
2010-09-24 14:17:58 +10:00
ret = create_keytab ( mem_ctx , msg , principals ,
smb_krb5_context ,
2010-09-23 17:01:44 +10:00
keytab_container - > keytab ,
2010-09-24 14:17:58 +10:00
found_previous ? false : true , error_string ) ;
2010-09-23 17:01:44 +10:00
}
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 ,
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 ;
2010-09-23 17:01:44 +10:00
struct ldb_message * msg ;
2010-09-24 14:17:58 +10:00
const char * error_string ;
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 ;
}
2010-09-23 17:01:44 +10:00
msg = ldb_msg_new ( mem_ctx ) ;
if ( ! msg ) {
talloc_free ( mem_ctx ) ;
return ENOMEM ;
}
ldb_msg_add_string ( msg , " krb5Keytab " , keytab_name ) ;
ldb_msg_add_string ( msg , " secret " , cli_credentials_get_password ( machine_account ) ) ;
ldb_msg_add_string ( msg , " samAccountName " , cli_credentials_get_username ( machine_account ) ) ;
ldb_msg_add_string ( msg , " realm " , cli_credentials_get_realm ( machine_account ) ) ;
ldb_msg_add_fmt ( msg , " msDS-KeyVersionNumber " , " %d " , ( int ) cli_credentials_get_kvno ( machine_account ) ) ;
2010-09-24 14:17:58 +10:00
ret = smb_krb5_update_keytab ( mem_ctx , smb_krb5_context , NULL , msg , false , & error_string ) ;
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 {
2010-09-24 14:17:58 +10:00
DEBUG ( 0 , ( " Failed to create in-memory keytab: %s \n " , error_string ) ) ;
2005-12-04 12:17:02 +00:00
* keytab_container = NULL ;
}
2005-12-01 05:09:28 +00:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2010-06-28 23:19:16 +10:00
/* Translate between the IETF encryption type values and the Microsoft msDS-SupportedEncryptionTypes values */
uint32_t kerberos_enctype_to_bitmap ( krb5_enctype enc_type_enum )
{
switch ( enc_type_enum ) {
case ENCTYPE_DES_CBC_CRC :
return ENC_CRC32 ;
case ENCTYPE_DES_CBC_MD5 :
return ENC_RSA_MD5 ;
case ENCTYPE_ARCFOUR_HMAC_MD5 :
return ENC_RC4_HMAC_MD5 ;
case ENCTYPE_AES128_CTS_HMAC_SHA1_96 :
return ENC_HMAC_SHA1_96_AES128 ;
case ENCTYPE_AES256_CTS_HMAC_SHA1_96 :
return ENC_HMAC_SHA1_96_AES256 ;
default :
return 0 ;
}
}
/* Translate between the Microsoft msDS-SupportedEncryptionTypes values and the IETF encryption type values */
krb5_enctype kerberos_enctype_bitmap_to_enctype ( uint32_t enctype_bitmap )
{
switch ( enctype_bitmap ) {
case ENC_CRC32 :
return ENCTYPE_DES_CBC_CRC ;
case ENC_RSA_MD5 :
return ENCTYPE_DES_CBC_MD5 ;
case ENC_RC4_HMAC_MD5 :
return ENCTYPE_ARCFOUR_HMAC_MD5 ;
case ENC_HMAC_SHA1_96_AES128 :
return ENCTYPE_AES128_CTS_HMAC_SHA1_96 ;
case ENC_HMAC_SHA1_96_AES256 :
return ENCTYPE_AES256_CTS_HMAC_SHA1_96 ;
default :
return 0 ;
}
}
/* Return an array of krb5_enctype values */
krb5_error_code kerberos_enctype_bitmap_to_enctypes ( TALLOC_CTX * mem_ctx , uint32_t enctype_bitmap , krb5_enctype * * enctypes )
{
unsigned int i , j = 0 ;
2010-09-23 17:01:44 +10:00
* enctypes = talloc_zero_array ( mem_ctx , krb5_enctype , ( 8 * sizeof ( enctype_bitmap ) ) + 1 ) ;
2010-06-28 23:19:16 +10:00
if ( ! * enctypes ) {
return ENOMEM ;
}
for ( i = 0 ; i < ( 8 * sizeof ( enctype_bitmap ) ) ; i + + ) {
2010-09-23 19:41:20 +10:00
uint32_t bit_value = ( 1 < < i ) & enctype_bitmap ;
if ( bit_value & enctype_bitmap ) {
( * enctypes ) [ j ] = kerberos_enctype_bitmap_to_enctype ( bit_value ) ;
2010-06-28 23:19:16 +10:00
if ( ! ( * enctypes ) [ j ] ) {
2010-09-23 17:01:44 +10:00
continue ;
2010-06-28 23:19:16 +10:00
}
j + + ;
}
}
2010-09-23 17:01:44 +10:00
( * enctypes ) [ j ] = 0 ;
2010-06-28 23:19:16 +10:00
return 0 ;
}