2001-11-24 17:16:41 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-11-24 17:16:41 +03:00
kerberos utility library
Copyright ( C ) Andrew Tridgell 2001
2001-12-20 06:54:52 +03:00
Copyright ( C ) Remus Koos 2001
2005-01-14 22:26:13 +03:00
Copyright ( C ) Nalin Dahyabhai < nalin @ redhat . com > 2004.
2004-10-30 02:38:10 +04:00
Copyright ( C ) Jeremy Allison 2004.
2006-07-11 22:45:22 +04:00
Copyright ( C ) Gerald Carter 2006.
2004-10-30 02:38:10 +04:00
2001-11-24 17:16:41 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# ifdef HAVE_KRB5
2004-10-30 02:38:10 +04:00
# define LIBADS_CCACHE_NAME "MEMORY:libads"
2002-07-15 14:35:28 +04:00
/*
we use a prompter to avoid a crash bug in the kerberos libs when
dealing with empty passwords
this prompter is just a string copy . . .
*/
static krb5_error_code
kerb_prompter ( krb5_context ctx , void * data ,
const char * name ,
const char * banner ,
int num_prompts ,
krb5_prompt prompts [ ] )
{
if ( num_prompts = = 0 ) return 0 ;
2004-10-30 02:38:10 +04:00
memset ( prompts [ 0 ] . reply - > data , ' \0 ' , prompts [ 0 ] . reply - > length ) ;
2002-07-15 14:35:28 +04:00
if ( prompts [ 0 ] . reply - > length > 0 ) {
2002-10-24 05:05:30 +04:00
if ( data ) {
2006-08-01 00:51:55 +04:00
strncpy ( prompts [ 0 ] . reply - > data , ( const char * ) data ,
prompts [ 0 ] . reply - > length - 1 ) ;
2002-10-24 05:05:30 +04:00
prompts [ 0 ] . reply - > length = strlen ( prompts [ 0 ] . reply - > data ) ;
} else {
prompts [ 0 ] . reply - > length = 0 ;
}
2002-07-15 14:35:28 +04:00
}
return 0 ;
}
2001-12-06 08:41:53 +03:00
/*
2004-10-30 02:38:10 +04:00
simulate a kinit , putting the tgt in the given cache location . If cache_name = = NULL
place in default cache location .
2001-12-06 08:41:53 +03:00
remus @ snapserver . com
*/
2006-03-20 22:05:44 +03:00
int kerberos_kinit_password_ext ( const char * principal ,
2004-10-30 02:38:10 +04:00
const char * password ,
int time_offset ,
time_t * expire_time ,
2006-02-04 01:19:41 +03:00
time_t * renew_till_time ,
const char * cache_name ,
BOOL request_pac ,
2006-04-25 16:24:25 +04:00
BOOL add_netbios_addr ,
2006-02-04 01:19:41 +03:00
time_t renewable_time )
2001-12-06 08:41:53 +03:00
{
2004-05-07 06:48:03 +04:00
krb5_context ctx = NULL ;
2001-12-06 08:41:53 +03:00
krb5_error_code code = 0 ;
2004-05-07 06:48:03 +04:00
krb5_ccache cc = NULL ;
2001-12-06 08:41:53 +03:00
krb5_principal me ;
krb5_creds my_creds ;
2006-02-04 01:19:41 +03:00
krb5_get_init_creds_opt opt ;
2006-04-25 16:24:25 +04:00
smb_krb5_addresses * addr = NULL ;
2001-12-13 14:30:13 +03:00
2005-11-07 17:16:50 +03:00
initialize_krb5_error_table ( ) ;
2001-12-06 08:41:53 +03:00
if ( ( code = krb5_init_context ( & ctx ) ) )
return code ;
2002-09-25 19:19:00 +04:00
if ( time_offset ! = 0 ) {
krb5_set_real_time ( ctx , time ( NULL ) + time_offset , 0 ) ;
}
2006-02-04 01:19:41 +03:00
DEBUG ( 10 , ( " kerberos_kinit_password: using %s as ccache \n " ,
cache_name ? cache_name : krb5_cc_default_name ( ctx ) ) ) ;
if ( ( code = krb5_cc_resolve ( ctx , cache_name ? cache_name : krb5_cc_default_name ( ctx ) , & cc ) ) ) {
2001-12-06 08:41:53 +03:00
krb5_free_context ( ctx ) ;
return code ;
}
2006-04-24 19:57:54 +04:00
if ( ( code = smb_krb5_parse_name ( ctx , principal , & me ) ) ) {
2001-12-06 08:41:53 +03:00
krb5_free_context ( ctx ) ;
return code ;
}
2006-02-04 01:19:41 +03:00
krb5_get_init_creds_opt_init ( & opt ) ;
krb5_get_init_creds_opt_set_renew_life ( & opt , renewable_time ) ;
krb5_get_init_creds_opt_set_forwardable ( & opt , 1 ) ;
2001-12-06 08:41:53 +03:00
2006-02-04 01:19:41 +03:00
if ( request_pac ) {
# ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
2006-04-25 16:24:25 +04:00
code = krb5_get_init_creds_opt_set_pac_request ( ctx , & opt , True ) ;
if ( code ) {
krb5_free_principal ( ctx , me ) ;
krb5_free_context ( ctx ) ;
return code ;
}
2006-02-04 01:19:41 +03:00
# endif
}
2006-04-25 16:24:25 +04:00
if ( add_netbios_addr ) {
code = smb_krb5_gen_netbios_krb5_address ( & addr ) ;
if ( code ) {
krb5_free_principal ( ctx , me ) ;
krb5_free_context ( ctx ) ;
return code ;
}
krb5_get_init_creds_opt_set_address_list ( & opt , addr - > addrs ) ;
}
2005-10-18 07:24:00 +04:00
if ( ( code = krb5_get_init_creds_password ( ctx , & my_creds , me , CONST_DISCARD ( char * , password ) ,
2006-03-17 16:57:00 +03:00
kerb_prompter , NULL , 0 , NULL , & opt ) ) )
{
2006-04-25 16:24:25 +04:00
smb_krb5_free_addresses ( ctx , addr ) ;
2001-12-06 08:41:53 +03:00
krb5_free_principal ( ctx , me ) ;
krb5_free_context ( ctx ) ;
return code ;
}
if ( ( code = krb5_cc_initialize ( ctx , cc , me ) ) ) {
2006-04-25 16:24:25 +04:00
smb_krb5_free_addresses ( ctx , addr ) ;
2001-12-06 08:41:53 +03:00
krb5_free_cred_contents ( ctx , & my_creds ) ;
krb5_free_principal ( ctx , me ) ;
krb5_free_context ( ctx ) ;
return code ;
}
if ( ( code = krb5_cc_store_cred ( ctx , cc , & my_creds ) ) ) {
krb5_cc_close ( ctx , cc ) ;
2006-04-25 16:24:25 +04:00
smb_krb5_free_addresses ( ctx , addr ) ;
2001-12-06 08:41:53 +03:00
krb5_free_cred_contents ( ctx , & my_creds ) ;
krb5_free_principal ( ctx , me ) ;
krb5_free_context ( ctx ) ;
return code ;
}
2006-02-04 01:19:41 +03:00
if ( expire_time ) {
2004-03-24 20:32:55 +03:00
* expire_time = ( time_t ) my_creds . times . endtime ;
2006-02-04 01:19:41 +03:00
}
if ( renew_till_time ) {
* renew_till_time = ( time_t ) my_creds . times . renew_till ;
}
2004-03-24 20:32:55 +03:00
2001-12-06 08:41:53 +03:00
krb5_cc_close ( ctx , cc ) ;
2006-04-25 16:24:25 +04:00
smb_krb5_free_addresses ( ctx , addr ) ;
2001-12-06 08:41:53 +03:00
krb5_free_cred_contents ( ctx , & my_creds ) ;
krb5_free_principal ( ctx , me ) ;
krb5_free_context ( ctx ) ;
return 0 ;
}
2001-12-05 12:46:53 +03:00
2001-12-06 08:41:53 +03:00
/* run kinit to setup our ccache */
int ads_kinit_password ( ADS_STRUCT * ads )
2001-12-05 12:46:53 +03:00
{
char * s ;
2001-12-06 08:41:53 +03:00
int ret ;
2005-11-10 22:50:09 +03:00
const char * account_name ;
fstring acct_name ;
if ( IS_DC ) {
/* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
account_name = lp_workgroup ( ) ;
} else {
/* always use the sAMAccountName for security = domain */
/* global_myname()$@REA.LM */
if ( lp_security ( ) = = SEC_DOMAIN ) {
fstr_sprintf ( acct_name , " %s$ " , global_myname ( ) ) ;
account_name = acct_name ;
}
else
/* This looks like host/global_myname()@REA.LM */
account_name = ads - > auth . user_name ;
}
2001-12-06 10:33:35 +03:00
2005-11-10 22:50:09 +03:00
if ( asprintf ( & s , " %s@%s " , account_name , ads - > auth . realm ) = = - 1 ) {
2002-10-01 17:10:57 +04:00
return KRB5_CC_NOMEM ;
}
if ( ! ads - > auth . password ) {
2006-06-16 01:59:25 +04:00
SAFE_FREE ( s ) ;
2002-10-01 17:10:57 +04:00
return KRB5_LIBOS_CANTREADPWD ;
}
2006-03-20 22:05:44 +03:00
ret = kerberos_kinit_password_ext ( s , ads - > auth . password , ads - > auth . time_offset ,
2006-04-25 16:24:25 +04:00
& ads - > auth . expire , NULL , NULL , False , False , ads - > auth . renewable ) ;
2001-12-11 08:15:52 +03:00
2001-12-06 08:41:53 +03:00
if ( ret ) {
2001-12-13 14:30:13 +03:00
DEBUG ( 0 , ( " kerberos_kinit_password %s failed: %s \n " ,
2001-12-08 14:18:56 +03:00
s , error_message ( ret ) ) ) ;
2001-12-06 08:41:53 +03:00
}
2006-06-16 01:59:25 +04:00
SAFE_FREE ( s ) ;
2001-12-06 08:41:53 +03:00
return ret ;
2001-12-05 12:46:53 +03:00
}
2004-03-24 20:32:55 +03:00
int ads_kdestroy ( const char * cc_name )
{
krb5_error_code code ;
2004-05-07 06:48:03 +04:00
krb5_context ctx = NULL ;
krb5_ccache cc = NULL ;
2004-03-24 20:32:55 +03:00
2005-11-07 17:16:50 +03:00
initialize_krb5_error_table ( ) ;
2004-03-24 20:32:55 +03:00
if ( ( code = krb5_init_context ( & ctx ) ) ) {
2004-08-21 00:18:28 +04:00
DEBUG ( 3 , ( " ads_kdestroy: kdb5_init_context failed: %s \n " ,
error_message ( code ) ) ) ;
2004-03-24 20:32:55 +03:00
return code ;
}
if ( ! cc_name ) {
if ( ( code = krb5_cc_default ( ctx , & cc ) ) ) {
krb5_free_context ( ctx ) ;
return code ;
}
} else {
if ( ( code = krb5_cc_resolve ( ctx , cc_name , & cc ) ) ) {
2004-08-21 00:18:28 +04:00
DEBUG ( 3 , ( " ads_kdestroy: krb5_cc_resolve failed: %s \n " ,
error_message ( code ) ) ) ;
2004-03-24 20:32:55 +03:00
krb5_free_context ( ctx ) ;
return code ;
}
}
if ( ( code = krb5_cc_destroy ( ctx , cc ) ) ) {
2004-08-21 00:18:28 +04:00
DEBUG ( 3 , ( " ads_kdestroy: krb5_cc_destroy failed: %s \n " ,
error_message ( code ) ) ) ;
2004-03-24 20:32:55 +03:00
}
krb5_free_context ( ctx ) ;
return code ;
}
2001-11-24 17:16:41 +03:00
2004-10-30 02:38:10 +04:00
/************************************************************************
Routine to fetch the salting principal for a service . Active
Directory may use a non - obvious principal name to generate the salt
when it determines the key to use for encrypting tickets for a service ,
and hopefully we detected that when we joined the domain .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * kerberos_secrets_fetch_salting_principal ( const char * service , int enctype )
{
char * key = NULL ;
char * ret = NULL ;
asprintf ( & key , " %s/%s/enctype=%d " , SECRETS_SALTING_PRINCIPAL , service , enctype ) ;
if ( ! key ) {
return NULL ;
}
ret = ( char * ) secrets_fetch ( key , NULL ) ;
SAFE_FREE ( key ) ;
return ret ;
}
/************************************************************************
2006-07-11 22:45:22 +04:00
Return the standard DES salt key
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * kerberos_standard_des_salt ( void )
{
fstring salt ;
fstr_sprintf ( salt , " host/%s.%s@ " , global_myname ( ) , lp_realm ( ) ) ;
strlower_m ( salt ) ;
fstrcat ( salt , lp_realm ( ) ) ;
return SMB_STRDUP ( salt ) ;
}
/************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * des_salt_key ( void )
{
char * key ;
asprintf ( & key , " %s/DES/%s " , SECRETS_SALTING_PRINCIPAL , lp_realm ( ) ) ;
return key ;
}
/************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL kerberos_secrets_store_des_salt ( const char * salt )
{
char * key ;
BOOL ret ;
if ( ( key = des_salt_key ( ) ) = = NULL ) {
DEBUG ( 0 , ( " kerberos_secrets_store_des_salt: failed to generate key! \n " ) ) ;
return False ;
}
if ( ! salt ) {
DEBUG ( 8 , ( " kerberos_secrets_store_des_salt: deleting salt \n " ) ) ;
secrets_delete ( key ) ;
2006-07-13 04:11:34 +04:00
return True ;
2006-07-11 22:45:22 +04:00
}
DEBUG ( 3 , ( " kerberos_secrets_store_des_salt: Storing salt \" %s \" \n " , salt ) ) ;
ret = secrets_store ( key , salt , strlen ( salt ) + 1 ) ;
SAFE_FREE ( key ) ;
return ret ;
}
/************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * kerberos_secrets_fetch_des_salt ( void )
{
char * salt , * key ;
if ( ( key = des_salt_key ( ) ) = = NULL ) {
DEBUG ( 0 , ( " kerberos_secrets_fetch_des_salt: failed to generate key! \n " ) ) ;
return False ;
}
2006-07-12 00:50:50 +04:00
salt = ( char * ) secrets_fetch ( key , NULL ) ;
2006-07-11 22:45:22 +04:00
SAFE_FREE ( key ) ;
return salt ;
}
/************************************************************************
Routine to get the salting principal for this service . This is
maintained for backwards compatibilty with releases prior to 3.0 .24 .
Since we store the salting principal string only at join , we may have
to look for the older tdb keys . Caller must free if return is not null .
2004-10-30 02:38:10 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
krb5_principal kerberos_fetch_salt_princ_for_host_princ ( krb5_context context ,
krb5_principal host_princ ,
int enctype )
{
char * unparsed_name = NULL , * salt_princ_s = NULL ;
krb5_principal ret_princ = NULL ;
2006-07-11 22:45:22 +04:00
/* lookup new key first */
2004-10-30 02:38:10 +04:00
2006-07-11 22:45:22 +04:00
if ( ( salt_princ_s = kerberos_secrets_fetch_des_salt ( ) ) = = NULL ) {
/* look under the old key. If this fails, just use the standard key */
2004-10-30 02:38:10 +04:00
2006-07-11 22:45:22 +04:00
if ( smb_krb5_unparse_name ( context , host_princ , & unparsed_name ) ! = 0 ) {
return ( krb5_principal ) NULL ;
}
if ( ( salt_princ_s = kerberos_secrets_fetch_salting_principal ( unparsed_name , enctype ) ) = = NULL ) {
/* fall back to host/machine.realm@REALM */
salt_princ_s = kerberos_standard_des_salt ( ) ;
}
2004-10-30 02:38:10 +04:00
}
2006-04-24 19:57:54 +04:00
if ( smb_krb5_parse_name ( context , salt_princ_s , & ret_princ ) ! = 0 ) {
2006-07-11 22:45:22 +04:00
ret_princ = NULL ;
2004-10-30 02:38:10 +04:00
}
2006-07-11 22:45:22 +04:00
2006-04-24 19:57:54 +04:00
SAFE_FREE ( unparsed_name ) ;
2004-10-30 02:38:10 +04:00
SAFE_FREE ( salt_princ_s ) ;
2006-07-11 22:45:22 +04:00
2004-10-30 02:38:10 +04:00
return ret_princ ;
}
/************************************************************************
Routine to set the salting principal for this service . Active
Directory may use a non - obvious principal name to generate the salt
when it determines the key to use for encrypting tickets for a service ,
and hopefully we detected that when we joined the domain .
Setting principal to NULL deletes this entry .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-05-02 21:49:43 +04:00
BOOL kerberos_secrets_store_salting_principal ( const char * service ,
2004-10-30 02:38:10 +04:00
int enctype ,
const char * principal )
{
char * key = NULL ;
BOOL ret = False ;
krb5_context context = NULL ;
krb5_principal princ = NULL ;
char * princ_s = NULL ;
char * unparsed_name = NULL ;
krb5_init_context ( & context ) ;
if ( ! context ) {
return False ;
}
if ( strchr_m ( service , ' @ ' ) ) {
asprintf ( & princ_s , " %s " , service ) ;
} else {
asprintf ( & princ_s , " %s@%s " , service , lp_realm ( ) ) ;
}
2006-04-24 19:57:54 +04:00
if ( smb_krb5_parse_name ( context , princ_s , & princ ) ! = 0 ) {
2004-10-30 02:38:10 +04:00
goto out ;
}
2006-04-24 19:57:54 +04:00
if ( smb_krb5_unparse_name ( context , princ , & unparsed_name ) ! = 0 ) {
2004-10-30 02:38:10 +04:00
goto out ;
}
asprintf ( & key , " %s/%s/enctype=%d " , SECRETS_SALTING_PRINCIPAL , unparsed_name , enctype ) ;
if ( ! key ) {
goto out ;
}
if ( ( principal ! = NULL ) & & ( strlen ( principal ) > 0 ) ) {
ret = secrets_store ( key , principal , strlen ( principal ) + 1 ) ;
} else {
ret = secrets_delete ( key ) ;
}
out :
SAFE_FREE ( key ) ;
SAFE_FREE ( princ_s ) ;
2006-04-24 19:57:54 +04:00
SAFE_FREE ( unparsed_name ) ;
2004-10-30 02:38:10 +04:00
if ( context ) {
krb5_free_context ( context ) ;
}
return ret ;
}
/************************************************************************
2006-07-11 22:45:22 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-03-20 22:05:44 +03:00
int kerberos_kinit_password ( const char * principal ,
const char * password ,
int time_offset ,
const char * cache_name )
{
return kerberos_kinit_password_ext ( principal ,
password ,
time_offset ,
0 ,
0 ,
cache_name ,
False ,
2006-04-25 16:24:25 +04:00
False ,
2006-03-20 22:05:44 +03:00
0 ) ;
}
2001-11-24 17:16:41 +03:00
# endif