1998-04-20 22:43:54 +00:00
/*
2002-01-30 06:08:46 +00:00
Unix SMB / CIFS implementation .
1998-04-20 22:43:54 +00:00
Functions to create reasonable random numbers for crypto use .
2001-05-24 18:24:54 +00:00
Copyright ( C ) Jeremy Allison 2001
1998-04-20 22:43:54 +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
2007-07-09 19:25:36 +00:00
the Free Software Foundation ; either version 3 of the License , or
1998-04-20 22:43:54 +00: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 00:52:41 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-04-20 22:43:54 +00:00
*/
# include "includes.h"
2005-09-30 17:13:37 +00:00
static unsigned char smb_arc4_state [ 258 ] ;
2001-05-24 18:24:54 +00:00
static uint32 counter ;
2004-07-14 04:36:01 +00:00
2007-10-18 17:40:25 -07:00
static bool done_reseed = False ;
2004-07-14 04:36:01 +00:00
static void ( * reseed_callback ) ( int * newseed ) ;
2001-05-24 18:24:54 +00:00
/****************************************************************
Copy any user given reseed data .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-07-14 04:36:01 +00:00
void set_rand_reseed_callback ( void ( * fn ) ( int * ) )
2001-05-24 18:24:54 +00:00
{
2004-07-14 04:36:01 +00:00
reseed_callback = fn ;
set_need_random_reseed ( ) ;
}
2001-05-24 18:24:54 +00:00
2004-07-14 04:36:01 +00:00
void set_need_random_reseed ( void )
{
done_reseed = False ;
}
static void get_rand_reseed_data ( int * reseed_data )
{
if ( reseed_callback ) {
reseed_callback ( reseed_data ) ;
} else {
* reseed_data = 0 ;
}
2001-05-24 18:24:54 +00:00
}
1998-04-21 07:17:35 +00:00
/****************************************************************
2001-05-24 18:24:54 +00:00
Get a 16 byte hash from the contents of a file .
Note that the hash is not initialised .
1998-04-21 07:17:35 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-24 18:24:54 +00:00
2003-01-03 08:28:12 +00:00
static void do_filehash ( const char * fname , unsigned char * the_hash )
1998-04-21 07:17:35 +00:00
{
unsigned char buf [ 1011 ] ; /* deliberate weird size */
unsigned char tmp_md4 [ 16 ] ;
int fd , n ;
1998-11-17 20:50:07 +00:00
fd = sys_open ( fname , O_RDONLY , 0 ) ;
2001-05-24 18:24:54 +00:00
if ( fd = = - 1 )
return ;
1998-04-21 07:17:35 +00:00
while ( ( n = read ( fd , ( char * ) buf , sizeof ( buf ) ) ) > 0 ) {
mdfour ( tmp_md4 , buf , n ) ;
for ( n = 0 ; n < 16 ; n + + )
2001-05-29 07:34:51 +00:00
the_hash [ n ] ^ = tmp_md4 [ n ] ;
1998-04-21 07:17:35 +00:00
}
close ( fd ) ;
}
1998-04-20 22:43:54 +00:00
/**************************************************************
Try and get a good random number seed . Try a number of
2001-05-24 18:24:54 +00:00
different factors . Firstly , try / dev / urandom - use if exists .
1998-04-21 07:17:35 +00:00
1999-04-28 02:00:38 +00:00
We use / dev / urandom as a read of / dev / random can block if
the entropy pool dries up . This leads clients to timeout
or be very slow on connect .
2001-05-24 18:24:54 +00:00
If we can ' t use / dev / urandom then seed the stream random generator
above . . .
1998-04-20 22:43:54 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-18 17:40:25 -07:00
static int do_reseed ( bool use_fd , int fd )
1998-04-20 22:43:54 +00:00
{
2001-05-24 18:24:54 +00:00
unsigned char seed_inbuf [ 40 ] ;
uint32 v1 , v2 ; struct timeval tval ; pid_t mypid ;
struct passwd * pw ;
2004-07-14 04:36:01 +00:00
int reseed_data = 0 ;
2001-05-24 18:24:54 +00:00
if ( use_fd ) {
if ( fd ! = - 1 )
return fd ;
fd = sys_open ( " /dev/urandom " , O_RDONLY , 0 ) ;
if ( fd > = 0 )
return fd ;
}
/* Add in some secret file contents */
do_filehash ( " /etc/shadow " , & seed_inbuf [ 0 ] ) ;
do_filehash ( lp_smb_passwd_file ( ) , & seed_inbuf [ 16 ] ) ;
/*
* Add in the root encrypted password .
* On any system where security is taken
* seriously this will be secret .
*/
2006-02-03 22:19:41 +00:00
pw = getpwnam_alloc ( NULL , " root " ) ;
2001-05-24 18:24:54 +00:00
if ( pw & & pw - > pw_passwd ) {
size_t i ;
unsigned char md4_tmp [ 16 ] ;
mdfour ( md4_tmp , ( unsigned char * ) pw - > pw_passwd , strlen ( pw - > pw_passwd ) ) ;
for ( i = 0 ; i < 16 ; i + + )
seed_inbuf [ 8 + i ] ^ = md4_tmp [ i ] ;
2006-02-20 17:59:58 +00:00
TALLOC_FREE ( pw ) ;
2001-05-24 18:24:54 +00:00
}
/*
* Add the counter , time of day , and pid .
*/
GetTimeOfDay ( & tval ) ;
mypid = sys_getpid ( ) ;
v1 = ( counter + + ) + mypid + tval . tv_sec ;
v2 = ( counter + + ) * mypid + tval . tv_usec ;
SIVAL ( seed_inbuf , 32 , v1 ^ IVAL ( seed_inbuf , 32 ) ) ;
SIVAL ( seed_inbuf , 36 , v2 ^ IVAL ( seed_inbuf , 36 ) ) ;
/*
* Add any user - given reseed data .
*/
2004-07-14 04:36:01 +00:00
get_rand_reseed_data ( & reseed_data ) ;
2001-05-24 18:24:54 +00:00
if ( reseed_data ) {
size_t i ;
for ( i = 0 ; i < sizeof ( seed_inbuf ) ; i + + )
2004-07-14 04:36:01 +00:00
seed_inbuf [ i ] ^ = ( ( char * ) ( & reseed_data ) ) [ i % sizeof ( reseed_data ) ] ;
2001-05-24 18:24:54 +00:00
}
2005-09-30 17:13:37 +00:00
smb_arc4_init ( smb_arc4_state , seed_inbuf , sizeof ( seed_inbuf ) ) ;
2001-05-24 18:24:54 +00:00
return - 1 ;
1998-04-20 22:43:54 +00:00
}
/*******************************************************************
Interface to the ( hopefully ) good crypto random number generator .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-07-14 04:36:01 +00:00
void generate_random_buffer ( unsigned char * out , int len )
1998-04-20 22:43:54 +00:00
{
2001-05-24 18:24:54 +00:00
static int urand_fd = - 1 ;
unsigned char md4_buf [ 64 ] ;
unsigned char tmp_buf [ 16 ] ;
unsigned char * p ;
2004-07-14 04:36:01 +00:00
if ( ! done_reseed ) {
2001-05-24 18:24:54 +00:00
urand_fd = do_reseed ( True , urand_fd ) ;
done_reseed = True ;
}
if ( urand_fd ! = - 1 & & len > 0 ) {
if ( read ( urand_fd , out , len ) = = len )
return ; /* len bytes of random data read from urandom. */
/* Read of urand error, drop back to non urand method. */
close ( urand_fd ) ;
urand_fd = - 1 ;
do_reseed ( False , - 1 ) ;
done_reseed = True ;
}
/*
* Generate random numbers in chunks of 64 bytes ,
* then md4 them & copy to the output buffer .
* This way the raw state of the stream is never externally
* seen .
*/
p = out ;
while ( len > 0 ) {
int copy_len = len > 16 ? 16 : len ;
2005-09-30 17:13:37 +00:00
smb_arc4_crypt ( smb_arc4_state , md4_buf , sizeof ( md4_buf ) ) ;
2001-05-24 18:24:54 +00:00
mdfour ( tmp_buf , md4_buf , sizeof ( md4_buf ) ) ;
memcpy ( p , tmp_buf , copy_len ) ;
p + = copy_len ;
len - = copy_len ;
}
1998-04-20 22:43:54 +00:00
}
2001-04-12 07:00:08 +00:00
/*******************************************************************
Use the random number generator to generate a random string .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-04-12 07:20:15 +00:00
static char c_list [ ] = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#., " ;
2001-04-12 07:00:08 +00:00
char * generate_random_str ( size_t len )
{
static unsigned char retstr [ 256 ] ;
size_t i ;
memset ( retstr , ' \0 ' , sizeof ( retstr ) ) ;
if ( len > sizeof ( retstr ) - 1 )
len = sizeof ( retstr ) - 1 ;
2004-07-14 04:36:01 +00:00
generate_random_buffer ( retstr , len ) ;
2001-04-12 07:00:08 +00:00
for ( i = 0 ; i < len ; i + + )
2002-08-17 17:00:51 +00:00
retstr [ i ] = c_list [ retstr [ i ] % ( sizeof ( c_list ) - 1 ) ] ;
2001-04-12 07:00:08 +00:00
retstr [ i ] = ' \0 ' ;
2001-04-13 19:12:06 +00:00
return ( char * ) retstr ;
2001-04-12 07:00:08 +00:00
}