2002-06-25 02:29:09 +00:00
/*
Unix SMB / CIFS implementation .
kerberos utility library
Copyright ( C ) Andrew Tridgell 2001
Copyright ( C ) Remus Koos 2001
2003-03-17 22:46:12 +00:00
Copyright ( C ) Luke Howard 2003
2002-06-25 02:29:09 +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
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
/*
verify an incoming ticket and parse out the principal name and
authorization_data if available
*/
NTSTATUS ads_verify_ticket ( ADS_STRUCT * ads , const DATA_BLOB * ticket ,
2003-03-17 22:46:12 +00:00
char * * principal , DATA_BLOB * auth_data ,
DATA_BLOB * ap_rep ,
uint8 session_key [ 16 ] )
2002-06-25 02:29:09 +00:00
{
2003-07-12 00:27:22 +00:00
NTSTATUS sret = NT_STATUS_LOGON_FAILURE ;
krb5_context context = NULL ;
2002-06-25 02:29:09 +00:00
krb5_auth_context auth_context = NULL ;
krb5_keytab keytab = NULL ;
krb5_data packet ;
krb5_ticket * tkt = NULL ;
2003-07-12 00:27:22 +00:00
krb5_rcache rcache = NULL ;
2003-02-19 15:48:12 +00:00
int ret , i ;
2003-07-12 00:27:22 +00:00
krb5_keyblock * key = NULL ;
2002-06-25 02:29:09 +00:00
krb5_principal host_princ ;
2003-07-12 00:27:22 +00:00
char * host_princ_s = NULL ;
2002-06-25 02:29:09 +00:00
fstring myname ;
2003-07-12 00:27:22 +00:00
char * password_s = NULL ;
2002-06-25 02:29:09 +00:00
krb5_data password ;
2003-02-19 15:48:12 +00:00
krb5_enctype * enctypes = NULL ;
2003-07-12 00:27:22 +00:00
#if 0
krb5_address local_addr ;
krb5_address remote_addr ;
# endif
2003-02-19 15:48:12 +00:00
BOOL auth_ok = False ;
2002-06-25 02:29:09 +00:00
2003-07-12 00:27:22 +00:00
ZERO_STRUCT ( packet ) ;
ZERO_STRUCT ( password ) ;
ZERO_STRUCTP ( auth_data ) ;
ZERO_STRUCTP ( ap_rep ) ;
2002-06-25 02:29:09 +00:00
if ( ! secrets_init ( ) ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 1 , ( " ads_verify_ticket: secrets_init failed \n " ) ) ;
2002-06-25 02:29:09 +00:00
return NT_STATUS_LOGON_FAILURE ;
}
2003-04-21 14:09:03 +00:00
password_s = secrets_fetch_machine_password ( lp_workgroup ( ) , NULL , NULL ) ;
2002-06-25 02:29:09 +00:00
if ( ! password_s ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 1 , ( " ads_verify_ticket: failed to fetch machine password \n " ) ) ;
2002-06-25 02:29:09 +00:00
return NT_STATUS_LOGON_FAILURE ;
}
password . data = password_s ;
password . length = strlen ( password_s ) ;
ret = krb5_init_context ( & context ) ;
if ( ret ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 1 , ( " ads_verify_ticket: krb5_init_context failed (%s) \n " , error_message ( ret ) ) ) ;
2002-06-25 02:29:09 +00:00
return NT_STATUS_LOGON_FAILURE ;
}
2002-08-17 17:00:51 +00:00
ret = krb5_set_default_realm ( context , ads - > auth . realm ) ;
2002-06-25 02:29:09 +00:00
if ( ret ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 1 , ( " ads_verify_ticket: krb5_set_default_realm failed (%s) \n " , error_message ( ret ) ) ) ;
2003-07-12 00:27:22 +00:00
sret = NT_STATUS_LOGON_FAILURE ;
goto out ;
2002-06-25 02:29:09 +00:00
}
2003-07-12 00:27:22 +00:00
/* This whole process is far more complex than I would
2002-06-25 02:29:09 +00:00
like . We have to go through all this to allow us to store
the secret internally , instead of using / etc / krb5 . keytab */
2003-07-12 00:27:22 +00:00
2002-06-25 02:29:09 +00:00
ret = krb5_auth_con_init ( context , & auth_context ) ;
if ( ret ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 1 , ( " ads_verify_ticket: krb5_auth_con_init failed (%s) \n " , error_message ( ret ) ) ) ;
2003-07-12 00:27:22 +00:00
sret = NT_STATUS_LOGON_FAILURE ;
goto out ;
2002-06-25 02:29:09 +00:00
}
2002-11-12 23:20:50 +00:00
fstrcpy ( myname , global_myname ( ) ) ;
2003-07-03 19:11:31 +00:00
strlower_m ( myname ) ;
2002-06-25 02:29:09 +00:00
asprintf ( & host_princ_s , " HOST/%s@%s " , myname , lp_realm ( ) ) ;
ret = krb5_parse_name ( context , host_princ_s , & host_princ ) ;
if ( ret ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 1 , ( " ads_verify_ticket: krb5_parse_name(%s) failed (%s) \n " ,
host_princ_s , error_message ( ret ) ) ) ;
2003-07-12 00:27:22 +00:00
sret = NT_STATUS_LOGON_FAILURE ;
goto out ;
}
/*
2003-07-29 21:32:36 +00:00
* JRA . We must set the rcache here . This will prevent replay attacks .
2003-07-12 00:27:22 +00:00
*/
ret = krb5_get_server_rcache ( context , krb5_princ_component ( context , host_princ , 0 ) , & rcache ) ;
if ( ret ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 1 , ( " ads_verify_ticket: krb5_get_server_rcache failed (%s) \n " , error_message ( ret ) ) ) ;
2003-07-12 00:27:22 +00:00
sret = NT_STATUS_LOGON_FAILURE ;
goto out ;
}
ret = krb5_auth_con_setrcache ( context , auth_context , rcache ) ;
if ( ret ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 1 , ( " ads_verify_ticket: krb5_auth_con_setrcache failed (%s) \n " , error_message ( ret ) ) ) ;
2003-07-12 00:27:22 +00:00
sret = NT_STATUS_LOGON_FAILURE ;
goto out ;
2002-06-25 02:29:09 +00:00
}
2003-07-29 00:31:44 +00:00
/* CIFS doesn't use addresses in tickets. This would breat NAT. JRA */
2003-07-12 00:27:22 +00:00
2002-06-25 02:29:09 +00:00
if ( ! ( key = ( krb5_keyblock * ) malloc ( sizeof ( * key ) ) ) ) {
2003-07-12 00:27:22 +00:00
sret = NT_STATUS_NO_MEMORY ;
goto out ;
2002-06-25 02:29:09 +00:00
}
2003-02-19 15:48:12 +00:00
if ( ( ret = get_kerberos_allowed_etypes ( context , & enctypes ) ) ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 1 , ( " ads_verify_ticket: krb5_get_permitted_enctypes failed (%s) \n " ,
2003-02-19 15:48:12 +00:00
error_message ( ret ) ) ) ;
2003-07-12 00:27:22 +00:00
sret = NT_STATUS_LOGON_FAILURE ;
goto out ;
2002-06-25 02:29:09 +00:00
}
2003-07-29 21:32:36 +00:00
/* Lock a mutex surrounding the replay as there is no locking in the MIT krb5
* code surrounding the replay cache . . . */
if ( ! grab_server_mutex ( " replay cache mutex " ) ) {
DEBUG ( 1 , ( " ads_verify_ticket: unable to protect replay cache with mutex. \n " ) ) ;
sret = NT_STATUS_LOGON_FAILURE ;
goto out ;
}
/* We need to setup a auth context with each possible encoding type in turn. */
2003-02-19 15:48:12 +00:00
for ( i = 0 ; enctypes [ i ] ; i + + ) {
if ( create_kerberos_key_from_string ( context , host_princ , & password , key , enctypes [ i ] ) ) {
continue ;
}
2003-01-30 04:40:12 +00:00
2003-02-19 15:48:12 +00:00
krb5_auth_con_setuseruserkey ( context , auth_context , key ) ;
packet . length = ticket - > length ;
packet . data = ( krb5_pointer ) ticket - > data ;
2003-01-30 04:40:12 +00:00
2003-02-19 15:48:12 +00:00
if ( ! ( ret = krb5_rd_req ( context , & auth_context , & packet ,
NULL , keytab , NULL , & tkt ) ) ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 10 , ( " ads_verify_ticket: enc type [%u] decrypted message ! \n " ,
( unsigned int ) enctypes [ i ] ) ) ;
2003-02-19 15:48:12 +00:00
free_kerberos_etypes ( context , enctypes ) ;
auth_ok = True ;
break ;
}
2003-07-29 00:31:44 +00:00
2003-07-29 17:03:51 +00:00
DEBUG ( ( ret ! = KRB5_BAD_ENCTYPE ) ? 3 : 10 ,
2003-07-29 00:31:44 +00:00
( " ads_verify_ticket: enc type [%u] failed to decrypt with error %s \n " ,
( unsigned int ) enctypes [ i ] , error_message ( ret ) ) ) ;
2003-02-19 15:48:12 +00:00
}
2003-07-29 21:32:36 +00:00
release_server_mutex ( ) ;
2003-02-19 15:48:12 +00:00
if ( ! auth_ok ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 3 , ( " ads_verify_ticket: krb5_rd_req with auth failed (%s) \n " ,
2002-06-25 02:29:09 +00:00
error_message ( ret ) ) ) ;
2003-07-12 00:27:22 +00:00
sret = NT_STATUS_LOGON_FAILURE ;
goto out ;
2002-06-25 02:29:09 +00:00
}
2003-03-17 22:46:12 +00:00
ret = krb5_mk_rep ( context , auth_context , & packet ) ;
if ( ret ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 3 , ( " ads_verify_ticket: Failed to generate mutual authentication reply (%s) \n " ,
2003-03-17 22:46:12 +00:00
error_message ( ret ) ) ) ;
2003-07-12 00:27:22 +00:00
sret = NT_STATUS_LOGON_FAILURE ;
goto out ;
2003-03-17 22:46:12 +00:00
}
* ap_rep = data_blob ( packet . data , packet . length ) ;
free ( packet . data ) ;
2003-07-25 23:15:30 +00:00
get_krb5_smb_session_key ( context , auth_context , session_key , True ) ;
2003-06-06 10:22:48 +00:00
# ifdef DEBUG_PASSWORD
DEBUG ( 10 , ( " SMB session key (from ticket) follows: \n " ) ) ;
dump_data ( 10 , session_key , 16 ) ;
# endif
2003-03-17 22:46:12 +00:00
2003-02-19 15:48:12 +00:00
#if 0
file_save ( " /tmp/ticket.dat " , ticket - > data , ticket - > length ) ;
# endif
2003-01-30 18:03:34 +00:00
get_auth_data_from_tkt ( auth_data , tkt ) ;
2002-06-25 02:29:09 +00:00
2003-04-16 16:57:01 +00:00
{
TALLOC_CTX * ctx = talloc_init ( " pac data " ) ;
decode_pac_data ( auth_data , ctx ) ;
talloc_destroy ( ctx ) ;
}
2002-06-25 02:29:09 +00:00
#if 0
if ( tkt - > enc_part2 ) {
2003-03-17 22:46:12 +00:00
file_save ( " /tmp/authdata.dat " ,
2002-06-25 02:29:09 +00:00
tkt - > enc_part2 - > authorization_data [ 0 ] - > contents ,
tkt - > enc_part2 - > authorization_data [ 0 ] - > length ) ;
# endif
2003-02-19 15:48:12 +00:00
if ( ( ret = krb5_unparse_name ( context , get_principal_from_tkt ( tkt ) ,
principal ) ) ) {
2003-07-29 00:31:44 +00:00
DEBUG ( 3 , ( " ads_verify_ticket: krb5_unparse_name failed (%s) \n " ,
2002-06-25 02:29:09 +00:00
error_message ( ret ) ) ) ;
2003-07-12 00:27:22 +00:00
sret = NT_STATUS_LOGON_FAILURE ;
goto out ;
}
sret = NT_STATUS_OK ;
out :
if ( ! NT_STATUS_IS_OK ( sret ) )
2003-03-17 22:46:12 +00:00
data_blob_free ( auth_data ) ;
2003-07-12 00:27:22 +00:00
if ( ! NT_STATUS_IS_OK ( sret ) )
2003-03-17 22:46:12 +00:00
data_blob_free ( ap_rep ) ;
2003-07-12 00:27:22 +00:00
SAFE_FREE ( host_princ_s ) ;
SAFE_FREE ( password_s ) ;
if ( auth_context )
2003-03-17 22:46:12 +00:00
krb5_auth_con_free ( context , auth_context ) ;
2002-06-25 02:29:09 +00:00
2003-07-12 00:27:22 +00:00
if ( context )
krb5_free_context ( context ) ;
2003-03-17 22:46:12 +00:00
2003-07-12 00:27:22 +00:00
return sret ;
2002-06-25 02:29:09 +00:00
}
2003-03-17 22:46:12 +00:00
# endif /* HAVE_KRB5 */