2003-09-07 20:36:13 +04:00
/*
* Unix SMB / CIFS implementation .
* Generate AFS tickets
* Copyright ( C ) Volker Lendecke 2003
*
* 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-09 23:25:36 +04:00
* the Free Software Foundation ; either version 3 of the License , or
2003-09-07 20:36:13 +04: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 09:23:25 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2003-09-07 20:36:13 +04:00
*/
# include "includes.h"
# ifdef WITH_FAKE_KASERVER
2005-10-14 02:11:18 +04:00
# define NO_ASN1_TYPEDEFS 1
2003-09-07 20:36:13 +04:00
# include <afs/stds.h>
# include <afs/afs.h>
# include <afs/auth.h>
# include <afs/venus.h>
# include <asm/unistd.h>
# include <openssl/des.h>
struct ClearToken {
uint32 AuthHandle ;
char HandShakeKey [ 8 ] ;
uint32 ViceId ;
uint32 BeginTimestamp ;
uint32 EndTimestamp ;
} ;
2004-04-01 16:31:50 +04:00
static char * afs_encode_token ( const char * cell , const DATA_BLOB ticket ,
const struct ClearToken * ct )
{
char * base64_ticket ;
char * result ;
DATA_BLOB key = data_blob ( ct - > HandShakeKey , 8 ) ;
char * base64_key ;
base64_ticket = base64_encode_data_blob ( ticket ) ;
if ( base64_ticket = = NULL )
return NULL ;
base64_key = base64_encode_data_blob ( key ) ;
if ( base64_key = = NULL ) {
2007-10-28 21:15:08 +03:00
TALLOC_FREE ( base64_ticket ) ;
2004-04-01 16:31:50 +04:00
return NULL ;
}
asprintf ( & result , " %s \n %u \n %s \n %u \n %u \n %u \n %s \n " , cell ,
ct - > AuthHandle , base64_key , ct - > ViceId , ct - > BeginTimestamp ,
ct - > EndTimestamp , base64_ticket ) ;
DEBUG ( 10 , ( " Got ticket string: \n %s \n " , result ) ) ;
2007-10-28 21:15:08 +03:00
TALLOC_FREE ( base64_ticket ) ;
TALLOC_FREE ( base64_key ) ;
2004-04-01 16:31:50 +04:00
return result ;
}
/* Create a ClearToken and an encrypted ticket. ClearToken has not yet the
* ViceId set , this should be set by the caller . */
2003-09-23 18:52:21 +04:00
2007-10-19 04:40:25 +04:00
static bool afs_createtoken ( const char * username , const char * cell ,
2004-04-01 16:31:50 +04:00
DATA_BLOB * ticket , struct ClearToken * ct )
{
fstring clear_ticket ;
char * p = clear_ticket ;
uint32 len ;
uint32 now ;
struct afs_key key ;
des_key_schedule key_schedule ;
2003-09-07 20:36:13 +04:00
if ( ! secrets_init ( ) )
return False ;
2003-09-23 18:52:21 +04:00
if ( ! secrets_fetch_afs_key ( cell , & key ) ) {
2004-04-01 16:31:50 +04:00
DEBUG ( 1 , ( " Could not fetch AFS service key \n " ) ) ;
2003-09-07 20:36:13 +04:00
return False ;
}
2004-04-01 16:31:50 +04:00
ct - > AuthHandle = key . kvno ;
2003-09-07 20:36:13 +04:00
/* Build the ticket. This is going to be encrypted, so in our
way we fill in ct while we still have the unencrypted
form . */
2004-04-01 16:31:50 +04:00
p = clear_ticket ;
2003-09-07 20:36:13 +04:00
/* The byte-order */
* p = 1 ;
p + = 1 ;
/* "Alice", the client username */
2004-04-01 16:31:50 +04:00
strncpy ( p , username , sizeof ( clear_ticket ) - PTR_DIFF ( p , clear_ticket ) - 1 ) ;
2003-09-07 20:36:13 +04:00
p + = strlen ( p ) + 1 ;
2004-04-01 16:31:50 +04:00
strncpy ( p , " " , sizeof ( clear_ticket ) - PTR_DIFF ( p , clear_ticket ) - 1 ) ;
2003-09-07 20:36:13 +04:00
p + = strlen ( p ) + 1 ;
2004-04-01 16:31:50 +04:00
strncpy ( p , cell , sizeof ( clear_ticket ) - PTR_DIFF ( p , clear_ticket ) - 1 ) ;
2003-09-07 20:36:13 +04:00
p + = strlen ( p ) + 1 ;
/* Alice's network layer address. At least Openafs-1.2.10
ignores this , so we fill in a dummy value here . */
SIVAL ( p , 0 , 0 ) ;
p + = 4 ;
/* We need to create a session key */
2004-07-14 08:36:01 +04:00
generate_random_buffer ( p , 8 ) ;
2003-09-07 20:36:13 +04:00
/* Our client code needs the the key in the clear, it does not
know the server - key . . . */
2004-04-01 16:31:50 +04:00
memcpy ( ct - > HandShakeKey , p , 8 ) ;
2003-09-07 20:36:13 +04:00
p + = 8 ;
2004-12-17 12:35:54 +03:00
/* This is a kerberos 4 life time. The life time is expressed
* in units of 5 minute intervals up to 38400 seconds , after
* that a table is used up to lifetime 0xBF . Values between
* 0xC0 and 0xFF is undefined . 0xFF is defined to be the
* infinite time that never expire .
*
* So here we cheat and use the infinite time */
2003-09-07 20:36:13 +04:00
* p = 255 ;
p + = 1 ;
/* Ticket creation time */
now = time ( NULL ) ;
SIVAL ( p , 0 , now ) ;
2004-04-01 16:31:50 +04:00
ct - > BeginTimestamp = now ;
2003-09-07 20:36:13 +04:00
2004-12-17 14:42:10 +03:00
if ( lp_afs_token_lifetime ( ) = = 0 )
ct - > EndTimestamp = NEVERDATE ;
else
ct - > EndTimestamp = now + lp_afs_token_lifetime ( ) ;
2004-04-01 16:31:50 +04:00
if ( ( ( ct - > EndTimestamp - ct - > BeginTimestamp ) & 1 ) = = 1 ) {
ct - > BeginTimestamp + = 1 ; /* Lifetime must be even */
2003-09-07 20:36:13 +04:00
}
p + = 4 ;
/* And here comes Bob's name and instance, in this case the
AFS server . */
2004-04-01 16:31:50 +04:00
strncpy ( p , " afs " , sizeof ( clear_ticket ) - PTR_DIFF ( p , clear_ticket ) - 1 ) ;
2003-09-07 20:36:13 +04:00
p + = strlen ( p ) + 1 ;
2004-04-01 16:31:50 +04:00
strncpy ( p , " " , sizeof ( clear_ticket ) - PTR_DIFF ( p , clear_ticket ) - 1 ) ;
2003-09-07 20:36:13 +04:00
p + = strlen ( p ) + 1 ;
/* And zero-pad to a multiple of 8 bytes */
2004-04-01 16:31:50 +04:00
len = PTR_DIFF ( p , clear_ticket ) ;
2003-09-07 20:36:13 +04:00
if ( len & 7 ) {
uint32 extra_space = 8 - ( len & 7 ) ;
memset ( p , 0 , extra_space ) ;
p + = extra_space ;
}
2004-04-01 16:31:50 +04:00
len = PTR_DIFF ( p , clear_ticket ) ;
2003-09-07 20:36:13 +04:00
des_key_sched ( ( const_des_cblock * ) key . key , key_schedule ) ;
2004-04-01 16:31:50 +04:00
des_pcbc_encrypt ( clear_ticket , clear_ticket ,
2003-09-07 20:36:13 +04:00
len , key_schedule , ( C_Block * ) key . key , 1 ) ;
ZERO_STRUCT ( key ) ;
2004-04-01 16:31:50 +04:00
* ticket = data_blob ( clear_ticket , len ) ;
return True ;
}
char * afs_createtoken_str ( const char * username , const char * cell )
{
DATA_BLOB ticket ;
struct ClearToken ct ;
char * result ;
if ( ! afs_createtoken ( username , cell , & ticket , & ct ) )
return NULL ;
result = afs_encode_token ( cell , ticket , & ct ) ;
data_blob_free ( & ticket ) ;
return result ;
}
/*
This routine takes a radical approach completely bypassing the
Kerberos idea of security and using AFS simply as an intelligent
file backend . Samba has persuaded itself somehow that the user is
actually correctly identified and then we create a ticket that the
AFS server hopefully accepts using its KeyFile that the admin has
kindly stored to our secrets . tdb .
Thanks to the book " Network Security -- PRIVATE Communication in a
PUBLIC World " by Charlie Kaufman, Radia Perlman and Mike Speciner
Kerberos 4 tickets are not really hard to construct .
For the comments " Alice " is the User to be auth ' ed , and " Bob " is the
AFS server . */
2007-10-19 04:40:25 +04:00
bool afs_login ( connection_struct * conn )
2004-04-01 16:31:50 +04:00
{
2006-07-11 22:01:26 +04:00
extern userdom_struct current_user_info ;
2005-05-13 16:21:35 +04:00
extern struct current_user current_user ;
2004-04-01 16:31:50 +04:00
DATA_BLOB ticket ;
2007-11-16 01:19:52 +03:00
char * afs_username = NULL ;
char * cell = NULL ;
2007-10-19 04:40:25 +04:00
bool result ;
2007-11-16 01:19:52 +03:00
char * ticket_str = NULL ;
2005-05-13 16:21:35 +04:00
const DOM_SID * user_sid ;
2007-12-07 23:26:32 +03:00
TALLOC_CTX * ctx = talloc_tos ( ) ;
2004-04-01 16:31:50 +04:00
struct ClearToken ct ;
2007-12-07 23:26:32 +03:00
afs_username = talloc_strdup ( ctx ,
lp_afs_username_map ( ) ) ;
if ( ! afs_username ) {
return false ;
}
afs_username = talloc_sub_advanced ( ctx ,
SNUM ( conn ) , conn - > user ,
conn - > connectpath , conn - > gid ,
get_current_username ( ) ,
current_user_info . domain ,
afs_username ) ;
if ( ! afs_username ) {
return false ;
}
2004-04-01 16:31:50 +04:00
2005-05-13 16:21:35 +04:00
user_sid = & current_user . nt_user_token - > user_sids [ 0 ] ;
2007-11-16 01:19:52 +03:00
afs_username = talloc_string_sub ( talloc_tos ( ) ,
2007-12-07 23:26:32 +03:00
afs_username ,
2007-11-16 01:19:52 +03:00
" %s " ,
sid_string_static ( user_sid ) ) ;
if ( ! afs_username ) {
return false ;
}
2005-02-11 13:32:46 +03:00
2004-04-01 16:31:50 +04:00
/* The pts command always generates completely lower-case user
* names . */
strlower_m ( afs_username ) ;
cell = strchr ( afs_username , ' @ ' ) ;
if ( cell = = NULL ) {
DEBUG ( 1 , ( " AFS username doesn't contain a @, "
" could not find cell \n " ) ) ;
2007-11-16 01:19:52 +03:00
return false ;
2004-04-01 16:31:50 +04:00
}
* cell = ' \0 ' ;
cell + = 1 ;
2007-11-16 01:19:52 +03:00
DEBUG ( 10 , ( " Trying to log into AFS for user %s@%s \n " ,
2004-04-01 16:31:50 +04:00
afs_username , cell ) ) ;
if ( ! afs_createtoken ( afs_username , cell , & ticket , & ct ) )
return False ;
/* For which Unix-UID do we want to set the token? */
ct . ViceId = getuid ( ) ;
2004-05-02 16:13:16 +04:00
ticket_str = afs_encode_token ( cell , ticket , & ct ) ;
2004-04-01 16:31:50 +04:00
2004-05-02 16:13:16 +04:00
result = afs_settoken_str ( ticket_str ) ;
2004-04-01 16:31:50 +04:00
2004-05-02 16:13:16 +04:00
SAFE_FREE ( ticket_str ) ;
2004-04-01 16:31:50 +04:00
data_blob_free ( & ticket ) ;
return result ;
2003-09-07 20:36:13 +04:00
}
# else
2007-10-19 04:40:25 +04:00
bool afs_login ( connection_struct * conn )
2003-09-07 20:36:13 +04:00
{
return True ;
}
2004-04-01 16:31:50 +04:00
char * afs_createtoken_str ( const char * username , const char * cell )
{
return False ;
}
2003-09-07 20:36:13 +04:00
# endif /* WITH_FAKE_KASERVER */