/*
* Unix SMB / Netbios implementation . Version 1.9 . SMB parameters and setup
* Copyright ( C ) Andrew Tridgell 1992 - 1998 Modified by Jeremy Allison 1995.
*
* 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"
extern int DEBUGLEVEL ;
static int gotalarm ;
int pw_file_lock_depth = 0 ;
/***************************************************************
Signal function to tell us we timed out .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void gotalarm_sig ( void )
{
gotalarm = 1 ;
}
/***************************************************************
Lock or unlock a fd for a known lock type . Abandon after waitsecs
seconds .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL do_file_lock ( int fd , int waitsecs , int type )
{
struct flock lock ;
int ret ;
gotalarm = 0 ;
CatchSignal ( SIGALRM , SIGNAL_CAST gotalarm_sig ) ;
lock . l_type = type ;
lock . l_whence = SEEK_SET ;
lock . l_start = 0 ;
lock . l_len = 1 ;
lock . l_pid = 0 ;
alarm ( 5 ) ;
ret = fcntl ( fd , F_SETLKW , & lock ) ;
alarm ( 0 ) ;
CatchSignal ( SIGALRM , SIGNAL_CAST SIG_DFL ) ;
if ( gotalarm ) {
DEBUG ( 0 , ( " do_file_lock: failed to %s file. \n " ,
type = = F_UNLCK ? " unlock " : " lock " ) ) ;
return False ;
}
return ( ret = = 0 ) ;
}
/***************************************************************
Lock an fd . Abandon after waitsecs seconds .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL pw_file_lock ( int fd , int type , int secs , int * plock_depth )
{
if ( fd < 0 )
return False ;
( * plock_depth ) + + ;
if ( pw_file_lock_depth = = 0 ) {
if ( ! do_file_lock ( fd , secs , type ) ) {
DEBUG ( 10 , ( " pw_file_lock: locking file failed, error = %s. \n " ,
strerror ( errno ) ) ) ;
return False ;
}
}
return True ;
}
/***************************************************************
Unlock an fd . Abandon after waitsecs seconds .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL pw_file_unlock ( int fd , int * plock_depth )
{
BOOL ret = True ;
if ( * plock_depth = = 1 )
ret = do_file_lock ( fd , 5 , F_UNLCK ) ;
( * plock_depth ) - - ;
if ( ! ret )
DEBUG ( 10 , ( " pw_file_unlock: unlocking file failed, error = %s. \n " ,
strerror ( errno ) ) ) ;
return ret ;
}
static int mach_passwd_lock_depth ;
static FILE * mach_passwd_fp ;
/************************************************************************
Routine to get the name for a trust account file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void get_trust_account_file_name ( char * domain , char * name , char * mac_file )
{
unsigned int mac_file_len ;
char * p ;
pstrcpy ( mac_file , lp_smb_passwd_file ( ) ) ;
p = strrchr ( mac_file , ' / ' ) ;
if ( p ! = NULL )
* + + p = ' \0 ' ;
mac_file_len = strlen ( mac_file ) ;
if ( ( int ) ( sizeof ( pstring ) - mac_file_len - strlen ( domain ) - strlen ( name ) - 6 ) < 0 )
{
DEBUG ( 0 , ( " trust_password_lock: path %s too long to add trust details. \n " ,
mac_file ) ) ;
return ;
}
pstrcat ( mac_file , domain ) ;
pstrcat ( mac_file , " . " ) ;
pstrcat ( mac_file , name ) ;
pstrcat ( mac_file , " .mac " ) ;
}
/************************************************************************
Routine to lock the trust account password file for a domain .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL trust_password_lock ( char * domain , char * name , BOOL update )
{
pstring mac_file ;
if ( mach_passwd_lock_depth = = 0 ) {
get_trust_account_file_name ( domain , name , mac_file ) ;
if ( ( mach_passwd_fp = fopen ( mac_file , " r+b " ) ) = = NULL ) {
if ( errno = = ENOENT & & update ) {
mach_passwd_fp = fopen ( mac_file , " w+b " ) ;
}
if ( mach_passwd_fp = = NULL ) {
DEBUG ( 0 , ( " trust_password_lock: cannot open file %s - Error was %s. \n " ,
mac_file , strerror ( errno ) ) ) ;
return False ;
}
}
chmod ( mac_file , 0600 ) ;
if ( ! pw_file_lock ( fileno ( mach_passwd_fp ) , ( update ? F_WRLCK : F_RDLCK ) ,
60 , & mach_passwd_lock_depth ) )
{
DEBUG ( 0 , ( " trust_password_lock: cannot lock file %s \n " , mac_file ) ) ;
fclose ( mach_passwd_fp ) ;
return False ;
}
}
return True ;
}
/************************************************************************
Routine to unlock the trust account password file for a domain .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL trust_password_unlock ( void )
{
BOOL ret = pw_file_unlock ( fileno ( mach_passwd_fp ) , & mach_passwd_lock_depth ) ;
if ( mach_passwd_lock_depth = = 0 )
fclose ( mach_passwd_fp ) ;
return ret ;
}
/************************************************************************
Routine to delete the trust account password file for a domain .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL trust_password_delete ( char * domain , char * name )
{
pstring mac_file ;
get_trust_account_file_name ( domain , name , mac_file ) ;
return ( unlink ( mac_file ) = = 0 ) ;
}
/************************************************************************
Routine to get the trust account password for a domain .
The user of this function must have locked the trust password file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL get_trust_account_password ( unsigned char * ret_pwd , time_t * pass_last_set_time )
{
char linebuf [ 256 ] ;
char * p ;
int i ;
linebuf [ 0 ] = ' \0 ' ;
* pass_last_set_time = ( time_t ) 0 ;
memset ( ret_pwd , ' \0 ' , 16 ) ;
if ( fseek ( mach_passwd_fp , 0L , SEEK_SET ) = = - 1 ) {
DEBUG ( 0 , ( " get_trust_account_password: Failed to seek to start of file. Error was %s. \n " ,
strerror ( errno ) ) ) ;
return False ;
}
fgets ( linebuf , sizeof ( linebuf ) , mach_passwd_fp ) ;
if ( ferror ( mach_passwd_fp ) ) {
DEBUG ( 0 , ( " get_trust_account_password: Failed to read password. Error was %s. \n " ,
strerror ( errno ) ) ) ;
return False ;
}
if ( linebuf [ strlen ( linebuf ) - 1 ] = = ' \n ' )
linebuf [ strlen ( linebuf ) - 1 ] = ' \0 ' ;
/*
* The length of the line read
* must be 45 bytes ( < - - - XXXX 32 bytes - - > : TLC - 12345678
*/
if ( strlen ( linebuf ) ! = 45 ) {
DEBUG ( 0 , ( " get_trust_account_password: Malformed trust password file (wrong length \
- was % d , should be 45 ) . \ n " , strlen(linebuf)));
# ifdef DEBUG_PASSWORD
DEBUG ( 100 , ( " get_trust_account_password: line = |%s| \n " , linebuf ) ) ;
# endif
return False ;
}
/*
* Get the hex password .
*/
if ( ! pdb_gethexpwd ( ( char * ) linebuf , ( char * ) ret_pwd ) | | linebuf [ 32 ] ! = ' : ' | |
strncmp ( & linebuf [ 33 ] , " TLC- " , 4 ) ) {
DEBUG ( 0 , ( " get_trust_account_password: Malformed trust password file (incorrect format). \n " ) ) ;
# ifdef DEBUG_PASSWORD
DEBUG ( 100 , ( " get_trust_account_password: line = |%s| \n " , linebuf ) ) ;
# endif
return False ;
}
/*
* Get the last changed time .
*/
p = & linebuf [ 37 ] ;
for ( i = 0 ; i < 8 ; i + + ) {
if ( p [ i ] = = ' \0 ' | | ! isxdigit ( p [ i ] ) ) {
DEBUG ( 0 , ( " get_trust_account_password: Malformed trust password file (no timestamp). \n " ) ) ;
# ifdef DEBUG_PASSWORD
DEBUG ( 100 , ( " get_trust_account_password: line = |%s| \n " , linebuf ) ) ;
# endif
return False ;
}
}
/*
* p points at 8 characters of hex digits -
* read into a time_t as the seconds since
* 1970 that the password was last changed .
*/
* pass_last_set_time = ( time_t ) strtol ( p , NULL , 16 ) ;
return True ;
}
/************************************************************************
Routine to get the trust account password for a domain .
The user of this function must have locked the trust password file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL set_trust_account_password ( unsigned char * md4_new_pwd )
{
char linebuf [ 64 ] ;
int i ;
if ( fseek ( mach_passwd_fp , 0L , SEEK_SET ) = = - 1 ) {
DEBUG ( 0 , ( " set_trust_account_password: Failed to seek to start of file. Error was %s. \n " ,
strerror ( errno ) ) ) ;
return False ;
}
for ( i = 0 ; i < 16 ; i + + )
slprintf ( & linebuf [ ( i * 2 ) ] , sizeof ( linebuf ) - ( i * 2 ) - 1 , " %02X " , md4_new_pwd [ i ] ) ;
slprintf ( & linebuf [ 32 ] , 32 , " :TLC-%08X \n " , ( unsigned ) time ( NULL ) ) ;
if ( fwrite ( linebuf , 1 , 46 , mach_passwd_fp ) ! = 46 ) {
DEBUG ( 0 , ( " set_trust_account_password: Failed to write file. Warning - the trust \
account is now invalid . Please recreate . Error was % s . \ n " , strerror(errno) ));
return False ;
}
fflush ( mach_passwd_fp ) ;
return True ;
}