2012-03-30 19:33:53 -04:00
/*
Unix SMB / CIFS implementation .
Kerberos utility functions
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2004 - 2005
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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "system/kerberos.h"
2015-04-17 15:54:03 +02:00
# include "auth/credentials/credentials.h"
2012-03-30 19:33:53 -04:00
# include "auth/kerberos/kerberos.h"
2015-04-17 15:54:03 +02:00
# include "auth/kerberos/kerberos_util.h"
2012-03-30 19:33:53 -04:00
# include "auth/kerberos/kerberos_srv_keytab.h"
2012-03-31 01:27:02 -04:00
2015-04-17 15:54:03 +02:00
static void keytab_principals_free ( krb5_context context ,
uint32_t num_principals ,
krb5_principal * set )
2012-03-31 01:27:02 -04:00
{
2015-04-17 15:54:03 +02:00
uint32_t i ;
2012-03-30 19:33:53 -04:00
2015-04-17 15:54:03 +02:00
for ( i = 0 ; i < num_principals ; i + + ) {
krb5_free_principal ( context , set [ i ] ) ;
2012-03-31 01:27:02 -04:00
}
2012-03-30 19:33:53 -04:00
}
static krb5_error_code keytab_add_keys ( TALLOC_CTX * parent_ctx ,
2015-04-17 15:54:03 +02:00
uint32_t num_principals ,
2012-03-31 01:27:02 -04:00
krb5_principal * principals ,
2012-03-30 19:33:53 -04:00
krb5_principal salt_princ ,
int kvno ,
const char * password_s ,
2012-03-31 01:27:02 -04:00
krb5_context context ,
2012-03-30 19:33:53 -04:00
krb5_enctype * enctypes ,
krb5_keytab keytab ,
const char * * error_string )
{
unsigned int i , p ;
krb5_error_code ret ;
krb5_data password ;
2012-03-31 01:27:02 -04:00
char * unparsed ;
2012-03-30 19:33:53 -04:00
2012-04-26 17:56:38 -04:00
password . data = discard_const_p ( char , password_s ) ;
2012-03-30 19:33:53 -04:00
password . length = strlen ( password_s ) ;
for ( i = 0 ; enctypes [ i ] ; i + + ) {
krb5_keytab_entry entry ;
ZERO_STRUCT ( entry ) ;
2014-04-25 14:14:20 +02:00
ret = smb_krb5_create_key_from_string ( context ,
2015-03-26 11:21:06 +01:00
salt_princ ,
2014-04-25 14:14:20 +02:00
NULL ,
& password ,
enctypes [ i ] ,
KRB5_KT_KEY ( & entry ) ) ;
2012-03-30 19:33:53 -04:00
if ( ret ! = 0 ) {
return ret ;
}
entry . vno = kvno ;
2015-04-17 15:54:03 +02:00
for ( p = 0 ; p < num_principals ; p + + ) {
2012-03-31 01:27:02 -04:00
unparsed = NULL ;
entry . principal = principals [ p ] ;
ret = krb5_kt_add_entry ( context , keytab , & entry ) ;
2012-03-30 19:33:53 -04:00
if ( ret ! = 0 ) {
char * k5_error_string =
2012-03-31 01:27:02 -04:00
smb_get_krb5_error_message ( context ,
ret , NULL ) ;
krb5_unparse_name ( context ,
principals [ p ] , & unparsed ) ;
2012-03-30 19:33:53 -04:00
* error_string = talloc_asprintf ( parent_ctx ,
" Failed to add enctype %d entry for "
" %s(kvno %d) to keytab: %s \n " ,
2012-03-31 01:27:02 -04:00
( int ) enctypes [ i ] , unparsed ,
2012-03-30 19:33:53 -04:00
kvno , k5_error_string ) ;
2012-03-31 01:27:02 -04:00
free ( unparsed ) ;
2012-03-30 19:33:53 -04:00
talloc_free ( k5_error_string ) ;
2012-03-31 01:27:02 -04:00
krb5_free_keyblock_contents ( context ,
2012-04-26 18:11:09 -04:00
KRB5_KT_KEY ( & entry ) ) ;
2012-03-30 19:33:53 -04:00
return ret ;
}
2012-03-31 01:27:02 -04:00
DEBUG ( 5 , ( " Added key (kvno %d) to keytab (enctype %d) \n " ,
kvno , ( int ) enctypes [ i ] ) ) ;
2012-03-30 19:33:53 -04:00
}
2012-04-26 18:11:09 -04:00
krb5_free_keyblock_contents ( context , KRB5_KT_KEY ( & entry ) ) ;
2012-03-30 19:33:53 -04:00
}
return 0 ;
}
static krb5_error_code create_keytab ( TALLOC_CTX * parent_ctx ,
2012-03-31 01:27:02 -04:00
const char * samAccountName ,
const char * realm ,
const char * saltPrincipal ,
int kvno ,
const char * new_secret ,
const char * old_secret ,
uint32_t supp_enctypes ,
2015-04-17 15:54:03 +02:00
uint32_t num_principals ,
2012-03-31 01:27:02 -04:00
krb5_principal * principals ,
krb5_context context ,
2012-03-30 19:33:53 -04:00
krb5_keytab keytab ,
bool add_old ,
const char * * error_string )
{
krb5_error_code ret ;
2012-03-31 01:27:02 -04:00
krb5_principal salt_princ = NULL ;
2012-03-30 19:33:53 -04:00
krb5_enctype * enctypes ;
2012-03-31 01:27:02 -04:00
TALLOC_CTX * mem_ctx ;
if ( ! new_secret ) {
/* There is no password here, so nothing to do */
return 0 ;
}
mem_ctx = talloc_new ( parent_ctx ) ;
2012-03-30 19:33:53 -04:00
if ( ! mem_ctx ) {
2014-06-12 10:39:02 +02:00
* error_string = talloc_strdup ( parent_ctx ,
" unable to allocate tmp_ctx for create_keytab " ) ;
2012-03-30 19:33:53 -04:00
return ENOMEM ;
}
/* The salt used to generate these entries may be different however,
* fetch that */
2015-04-23 19:18:32 +02:00
ret = krb5_parse_name ( context , saltPrincipal , & salt_princ ) ;
2012-03-30 19:33:53 -04:00
if ( ret ) {
2015-04-23 19:18:32 +02:00
* error_string = smb_get_krb5_error_message ( context ,
ret ,
parent_ctx ) ;
2012-03-30 19:33:53 -04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2012-03-31 01:27:02 -04:00
ret = ms_suptypes_to_ietf_enctypes ( mem_ctx , supp_enctypes , & enctypes ) ;
2012-03-30 19:33:53 -04:00
if ( ret ) {
* error_string = talloc_asprintf ( parent_ctx ,
" create_keytab: generating list of "
" encryption types failed (%s) \n " ,
2012-03-31 01:27:02 -04:00
smb_get_krb5_error_message ( context ,
ret , mem_ctx ) ) ;
goto done ;
2012-03-30 19:33:53 -04:00
}
2015-04-17 15:54:03 +02:00
ret = keytab_add_keys ( mem_ctx ,
num_principals ,
principals ,
2012-03-31 01:27:02 -04:00
salt_princ , kvno , new_secret ,
context , enctypes , keytab , error_string ) ;
2012-03-30 19:33:53 -04:00
if ( ret ) {
2014-06-12 10:39:02 +02:00
talloc_steal ( parent_ctx , * error_string ) ;
2012-03-31 01:27:02 -04:00
goto done ;
2012-03-30 19:33:53 -04:00
}
2012-03-31 01:27:02 -04:00
if ( old_secret & & add_old & & kvno ! = 0 ) {
2015-04-17 15:54:03 +02:00
ret = keytab_add_keys ( mem_ctx ,
num_principals ,
principals ,
2012-03-30 19:33:53 -04:00
salt_princ , kvno - 1 , old_secret ,
2012-03-31 01:27:02 -04:00
context , enctypes , keytab , error_string ) ;
2014-06-12 10:39:02 +02:00
if ( ret ) {
talloc_steal ( parent_ctx , * error_string ) ;
}
2012-03-30 19:33:53 -04:00
}
2012-03-31 01:27:02 -04:00
done :
krb5_free_principal ( context , salt_princ ) ;
2012-03-30 19:33:53 -04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
krb5_error_code smb_krb5_update_keytab ( TALLOC_CTX * parent_ctx ,
2012-04-01 19:08:15 -04:00
krb5_context context ,
2012-03-31 01:27:02 -04:00
const char * keytab_name ,
const char * samAccountName ,
const char * realm ,
const char * * SPNs ,
int num_SPNs ,
const char * saltPrincipal ,
const char * new_secret ,
const char * old_secret ,
int kvno ,
uint32_t supp_enctypes ,
bool delete_all_kvno ,
2012-03-31 03:23:19 -04:00
krb5_keytab * _keytab ,
2012-03-31 01:27:02 -04:00
const char * * error_string )
2012-03-30 19:33:53 -04:00
{
2012-03-31 03:23:19 -04:00
krb5_keytab keytab ;
2012-03-30 19:33:53 -04:00
krb5_error_code ret ;
2015-04-17 15:54:03 +02:00
bool found_previous = false ;
2012-03-31 03:23:19 -04:00
TALLOC_CTX * tmp_ctx ;
2012-03-31 01:27:02 -04:00
krb5_principal * principals = NULL ;
2015-04-17 15:54:03 +02:00
uint32_t num_principals = 0 ;
char * upper_realm ;
2012-03-30 19:33:53 -04:00
2012-03-31 03:23:19 -04:00
if ( keytab_name = = NULL ) {
2012-03-30 19:33:53 -04:00
return ENOENT ;
}
2015-04-23 19:18:32 +02:00
if ( saltPrincipal = = NULL ) {
* error_string = " No saltPrincipal provided " ;
return EINVAL ;
}
2012-04-01 19:08:15 -04:00
ret = krb5_kt_resolve ( context , keytab_name , & keytab ) ;
2012-03-31 03:23:19 -04:00
if ( ret ) {
2012-04-01 19:08:15 -04:00
* error_string = smb_get_krb5_error_message ( context ,
ret , parent_ctx ) ;
2012-03-31 03:23:19 -04:00
return ret ;
2012-03-30 19:33:53 -04:00
}
DEBUG ( 5 , ( " Opened keytab %s \n " , keytab_name ) ) ;
2012-03-31 03:23:19 -04:00
tmp_ctx = talloc_new ( parent_ctx ) ;
if ( ! tmp_ctx ) {
return ENOMEM ;
}
2015-04-17 15:54:03 +02:00
upper_realm = strupper_talloc ( tmp_ctx , realm ) ;
if ( upper_realm = = NULL ) {
* error_string = " Cannot allocate memory to upper case realm " ;
talloc_free ( tmp_ctx ) ;
return ENOMEM ;
}
2012-03-30 19:33:53 -04:00
2015-04-17 15:54:03 +02:00
ret = smb_krb5_create_principals_array ( tmp_ctx ,
context ,
samAccountName ,
upper_realm ,
num_SPNs ,
SPNs ,
& num_principals ,
& principals ,
error_string ) ;
2012-03-30 19:33:53 -04:00
if ( ret ! = 0 ) {
* error_string = talloc_asprintf ( parent_ctx ,
" Failed to load principals from ldb message: %s \n " ,
* error_string ) ;
2012-03-31 01:27:02 -04:00
goto done ;
2012-03-30 19:33:53 -04:00
}
2015-04-17 15:54:03 +02:00
ret = smb_krb5_remove_obsolete_keytab_entries ( tmp_ctx ,
context ,
keytab ,
num_principals ,
principals ,
kvno ,
& found_previous ,
error_string ) ;
2012-03-30 19:33:53 -04:00
if ( ret ! = 0 ) {
* error_string = talloc_asprintf ( parent_ctx ,
" Failed to remove old principals from keytab: %s \n " ,
* error_string ) ;
2012-03-31 01:27:02 -04:00
goto done ;
2012-03-30 19:33:53 -04: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 */
2012-03-31 03:23:19 -04:00
ret = create_keytab ( tmp_ctx ,
2015-04-17 15:54:03 +02:00
samAccountName , upper_realm , saltPrincipal ,
2012-03-31 01:27:02 -04:00
kvno , new_secret , old_secret ,
2015-04-17 15:54:03 +02:00
supp_enctypes ,
num_principals ,
principals ,
2012-04-01 19:08:15 -04:00
context , keytab ,
2012-03-30 19:33:53 -04:00
found_previous ? false : true ,
error_string ) ;
2012-03-31 03:23:19 -04:00
if ( ret ) {
talloc_steal ( parent_ctx , * error_string ) ;
}
}
if ( ret = = 0 & & _keytab ! = NULL ) {
/* caller wants the keytab handle back */
* _keytab = keytab ;
2012-03-30 19:33:53 -04:00
}
2012-03-31 01:27:02 -04:00
done :
2015-04-17 15:54:03 +02:00
keytab_principals_free ( context , num_principals , principals ) ;
2012-03-31 03:23:19 -04:00
if ( ret ! = 0 | | _keytab = = NULL ) {
2012-04-01 19:08:15 -04:00
krb5_kt_close ( context , keytab ) ;
2012-03-31 03:23:19 -04:00
}
talloc_free ( tmp_ctx ) ;
2012-03-30 19:33:53 -04:00
return ret ;
}
krb5_error_code smb_krb5_create_memory_keytab ( TALLOC_CTX * parent_ctx ,
2012-04-01 19:08:15 -04:00
krb5_context context ,
2012-03-31 05:19:59 -04:00
const char * new_secret ,
const char * samAccountName ,
const char * realm ,
2015-04-23 19:18:32 +02:00
const char * salt_principal ,
2012-03-31 05:19:59 -04:00
int kvno ,
2012-03-31 03:23:19 -04:00
krb5_keytab * keytab ,
const char * * keytab_name )
2012-03-30 19:33:53 -04:00
{
krb5_error_code ret ;
TALLOC_CTX * mem_ctx = talloc_new ( parent_ctx ) ;
const char * rand_string ;
const char * error_string ;
if ( ! mem_ctx ) {
return ENOMEM ;
}
rand_string = generate_random_str ( mem_ctx , 16 ) ;
if ( ! rand_string ) {
talloc_free ( mem_ctx ) ;
return ENOMEM ;
}
2012-03-31 03:23:19 -04:00
* keytab_name = talloc_asprintf ( mem_ctx , " MEMORY:%s " , rand_string ) ;
if ( * keytab_name = = NULL ) {
2012-03-30 19:33:53 -04:00
talloc_free ( mem_ctx ) ;
return ENOMEM ;
}
2012-04-01 19:08:15 -04:00
ret = smb_krb5_update_keytab ( mem_ctx , context ,
2012-03-31 03:23:19 -04:00
* keytab_name , samAccountName , realm ,
2015-04-23 19:18:32 +02:00
NULL , 0 , salt_principal , new_secret , NULL ,
2012-03-31 01:27:02 -04:00
kvno , ENC_ALL_TYPES ,
2012-03-31 03:23:19 -04:00
false , keytab , & error_string ) ;
2012-03-30 19:33:53 -04:00
if ( ret = = 0 ) {
2012-03-31 03:23:19 -04:00
talloc_steal ( parent_ctx , * keytab_name ) ;
2012-03-30 19:33:53 -04:00
} else {
DEBUG ( 0 , ( " Failed to create in-memory keytab: %s \n " ,
error_string ) ) ;
2012-03-31 03:23:19 -04:00
* keytab_name = NULL ;
2012-03-30 19:33:53 -04:00
}
talloc_free ( mem_ctx ) ;
return ret ;
}