2010-08-14 23:23:26 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd 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 .
systemd 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 systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
# include <string.h>
# include <sys/stat.h>
# include "log.h"
# include "util.h"
2012-04-10 23:54:31 +04:00
# include "mkdir.h"
2010-08-14 23:23:26 +04:00
2010-08-18 21:38:45 +04:00
# define POOL_SIZE_MIN 512
2010-08-14 23:23:26 +04:00
int main ( int argc , char * argv [ ] ) {
int seed_fd = - 1 , random_fd = - 1 ;
2010-08-31 23:05:54 +04:00
int ret = EXIT_FAILURE ;
2010-08-18 21:38:45 +04:00
void * buf ;
size_t buf_size = 0 ;
2010-08-14 23:23:26 +04:00
ssize_t r ;
2010-08-18 21:38:45 +04:00
FILE * f ;
2010-08-14 23:23:26 +04:00
if ( argc ! = 2 ) {
log_error ( " This program requires one argument. " ) ;
2010-08-31 23:05:54 +04:00
return EXIT_FAILURE ;
2010-08-14 23:23:26 +04:00
}
2012-01-12 08:09:06 +04:00
log_set_target ( LOG_TARGET_AUTO ) ;
2010-08-14 23:23:26 +04:00
log_parse_environment ( ) ;
2010-08-17 00:39:02 +04:00
log_open ( ) ;
2010-08-14 23:23:26 +04:00
2011-08-01 22:52:18 +04:00
umask ( 0022 ) ;
2010-08-18 21:38:45 +04:00
/* Read pool size, if possible */
if ( ( f = fopen ( " /proc/sys/kernel/random/poolsize " , " re " ) ) ) {
2011-10-22 20:47:08 +04:00
if ( fscanf ( f , " %zu " , & buf_size ) > 0 ) {
/* poolsize is in bits on 2.6, but we want bytes */
buf_size / = 8 ;
}
2010-08-18 21:38:45 +04:00
fclose ( f ) ;
}
if ( buf_size < = POOL_SIZE_MIN )
buf_size = POOL_SIZE_MIN ;
if ( ! ( buf = malloc ( buf_size ) ) ) {
log_error ( " Failed to allocate buffer. " ) ;
goto finish ;
}
2010-09-20 17:04:10 +04:00
if ( mkdir_parents ( RANDOM_SEED , 0755 ) < 0 ) {
log_error ( " Failed to create directories parents of %s: %m " , RANDOM_SEED ) ;
goto finish ;
}
2010-08-14 23:23:26 +04:00
/* When we load the seed we read it and write it to the device
* and then immediately update the saved seed with new data ,
* to make sure the next boot gets seeded differently . */
if ( streq ( argv [ 1 ] , " load " ) ) {
if ( ( seed_fd = open ( RANDOM_SEED , O_RDWR | O_CLOEXEC | O_NOCTTY | O_CREAT , 0600 ) ) < 0 ) {
if ( ( seed_fd = open ( RANDOM_SEED , O_RDONLY | O_CLOEXEC | O_NOCTTY ) ) < 0 ) {
log_error ( " Failed to open random seed: %m " ) ;
goto finish ;
}
}
if ( ( random_fd = open ( " /dev/urandom " , O_RDWR | O_CLOEXEC | O_NOCTTY , 0600 ) ) < 0 ) {
if ( ( random_fd = open ( " /dev/urandom " , O_WRONLY | O_CLOEXEC | O_NOCTTY , 0600 ) ) < 0 ) {
log_error ( " Failed to open /dev/urandom: %m " ) ;
goto finish ;
}
}
2011-03-31 06:40:02 +04:00
if ( ( r = loop_read ( seed_fd , buf , buf_size , false ) ) < = 0 ) {
if ( r ! = 0 )
log_error ( " Failed to read seed file: %m " ) ;
} else {
2010-08-14 23:23:26 +04:00
lseek ( seed_fd , 0 , SEEK_SET ) ;
2010-08-18 21:38:45 +04:00
if ( ( r = loop_write ( random_fd , buf , ( size_t ) r , false ) ) < = 0 )
2010-08-14 23:23:26 +04:00
log_error ( " Failed to write seed to /dev/random: %s " , r < 0 ? strerror ( errno ) : " short write " ) ;
}
} else if ( streq ( argv [ 1 ] , " save " ) ) {
if ( ( seed_fd = open ( RANDOM_SEED , O_WRONLY | O_CLOEXEC | O_NOCTTY | O_CREAT , 0600 ) ) < 0 ) {
log_error ( " Failed to open random seed: %m " ) ;
goto finish ;
}
if ( ( random_fd = open ( " /dev/urandom " , O_RDONLY | O_CLOEXEC | O_NOCTTY ) ) < 0 ) {
log_error ( " Failed to open /dev/urandom: %m " ) ;
goto finish ;
}
} else {
log_error ( " Unknown verb %s. " , argv [ 1 ] ) ;
goto finish ;
}
/* This is just a safety measure. Given that we are root and
* most likely created the file ourselves the mode and owner
* should be correct anyway . */
fchmod ( seed_fd , 0600 ) ;
fchown ( seed_fd , 0 , 0 ) ;
2010-08-18 21:38:45 +04:00
if ( ( r = loop_read ( random_fd , buf , buf_size , false ) ) < = 0 )
2010-08-14 23:23:26 +04:00
log_error ( " Failed to read new seed from /dev/urandom: %s " , r < 0 ? strerror ( errno ) : " EOF " ) ;
else {
2010-08-18 21:38:45 +04:00
if ( ( r = loop_write ( seed_fd , buf , ( size_t ) r , false ) ) < = 0 )
2010-08-14 23:23:26 +04:00
log_error ( " Failed to write new random seed file: %s " , r < 0 ? strerror ( errno ) : " short write " ) ;
}
2010-08-31 23:05:54 +04:00
ret = EXIT_SUCCESS ;
2010-08-14 23:23:26 +04:00
finish :
if ( random_fd > = 0 )
close_nointr_nofail ( random_fd ) ;
if ( seed_fd > = 0 )
close_nointr_nofail ( seed_fd ) ;
2010-08-18 21:38:45 +04:00
free ( buf ) ;
2010-08-14 23:23:26 +04:00
return ret ;
}