diff --git a/ChangeLog b/ChangeLog index 275100bba..5a040ed9b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2006-02-09 Werner Koch + + * configure.ac: Check for fcntl and ftruncate. + 2006-01-22 David Shaw * configure.ac: Add define for EXEEXT so we can find keyserver diff --git a/cipher/ChangeLog b/cipher/ChangeLog index 23a0c1601..7fe30517f 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,9 @@ +2006-02-09 Werner Koch + + * random.c (lock_seed_file): New. + (read_seed_file, update_random_seed_file): Use it. + (random_disable_locking): New. + 2005-12-06 David Shaw * idea-stub.c (load_module): Not legal to return a void * as a diff --git a/cipher/random.c b/cipher/random.c index 1ae2e8065..52e421995 100644 --- a/cipher/random.c +++ b/cipher/random.c @@ -1,6 +1,6 @@ /* random.c - random number generator * Copyright (C) 1998, 1999, 2000, 2001, 2002, - * 2003 Free Software Foundation, Inc. + * 2003, 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -70,6 +70,14 @@ #endif +/* Check whether we can lock the seed file read write. */ +#if defined(HAVE_FCNTL) && defined(HAVE_FTRUNCATE) && !defined(HAVE_W32_SYSTEM) +#define LOCK_SEED_FILE 1 +#else +#define LOCK_SEED_FILE 0 +#endif + + #if SIZEOF_UNSIGNED_LONG == 8 #define ADD_VALUE 0xa5a5a5a5a5a5a5a5 #elif SIZEOF_UNSIGNED_LONG == 4 @@ -105,6 +113,7 @@ static int just_mixed; static int did_initial_extra_seeding; static char *seed_file_name; static int allow_seed_file_update; +static int no_seed_file_locking; static int secure_alloc; static int quick_test; @@ -272,6 +281,13 @@ random_is_faked() return faked_rng || quick_test; } +/* Disable locking of seed files. */ +void +random_disable_locking () +{ + no_seed_file_locking = 1; +} + /**************** * Return a pointer to a randomized buffer of level 0 and LENGTH bits * caller must free the buffer. @@ -359,6 +375,50 @@ set_random_seed_file( const char *name ) seed_file_name = xstrdup( name ); } + +/* Lock an open file identified by file descriptor FD and wait a + reasonable time to succeed. With FOR_WRITE set to true a Rite lock + will be taken. FNAME is used only for diagnostics. Returns 0 on + success or -1 on error. */ +#if LOCK_SEED_FILE +static int +lock_seed_file (int fd, const char *fname, int for_write) +{ + struct flock lck; + struct timeval tv; + int backoff=0; + + if (no_seed_file_locking) + return 0; + + /* We take a lock on the entire file. */ + memset (&lck, 0, sizeof lck); + lck.l_type = for_write? F_WRLCK : F_RDLCK; + lck.l_whence = SEEK_SET; + + while (fcntl (fd, F_SETLK, &lck) == -1) + { + if (errno != EAGAIN && errno != EACCES) + { + log_info (_("can't lock `%s': %s\n"), fname, strerror (errno)); + return -1; + } + + if (backoff > 2) /* Show the first message after ~2.25 seconds. */ + log_info( _("waiting for lock on `%s'...\n"), fname); + + tv.tv_sec = backoff; + tv.tv_usec = 250000; + select (0, NULL, NULL, NULL, &tv); + if (backoff < 10) + backoff++ ; + } + return 0; +} +#endif /*LOCK_SEED_FILE*/ + + + /**************** * Read in a seed form the random_seed file * and return true if this was successful @@ -388,6 +448,12 @@ read_seed_file(void) log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) ); return 0; } + if (lock_seed_file (fd, seed_file_name, 0)) + { + close (fd); + return 0; + } + if( fstat( fd, &sb ) ) { log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) ); close(fd); @@ -468,12 +534,31 @@ update_random_seed_file() fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR ); #else +# if LOCK_SEED_FILE + fd = open( seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR ); +# else fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR ); +# endif #endif if( fd == -1 ) { log_info(_("can't create `%s': %s\n"), seed_file_name, strerror(errno) ); return; } + + if (lock_seed_file (fd, seed_file_name, 1)) + { + close (fd); + return; + } +#if LOCK_SEED_FILE + if (ftruncate (fd, 0)) + { + log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno)); + close (fd); + return; + } +#endif /*LOCK_SEED_FILE*/ + do { i = write( fd, keypool, POOLSIZE ); } while( i == -1 && errno == EINTR ); diff --git a/cipher/random.h b/cipher/random.h index 9e8090ec7..0f26d999b 100644 --- a/cipher/random.h +++ b/cipher/random.h @@ -30,6 +30,7 @@ void set_random_seed_file(const char *); void update_random_seed_file(void); int quick_random_gen( int onoff ); int random_is_faked(void); +void random_disable_locking (void); void randomize_buffer( byte *buffer, size_t length, int level ); byte *get_random_bits( size_t nbits, int level, int secure ); void fast_random_poll( void ); diff --git a/configure.ac b/configure.ac index 08512bc0a..26791222d 100644 --- a/configure.ac +++ b/configure.ac @@ -858,6 +858,7 @@ AC_CHECK_FUNCS(strcasecmp strncasecmp ctermid times unsetenv getpwnam getpwuid) AC_CHECK_FUNCS(memmove gettimeofday getrusage setrlimit clock_gettime) AC_CHECK_FUNCS(atexit raise getpagesize strftime nl_langinfo setlocale) AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask rand pipe stat getaddrinfo) +AC_CHECK_FUNCS(fcntl ftruncate) AC_REPLACE_FUNCS(mkdtemp timegm isascii memrchr) AC_CHECK_TYPES([struct sigaction, sigset_t],,,[#include ]) diff --git a/g10/ChangeLog b/g10/ChangeLog index 7f5226344..aeee509e9 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,7 @@ +2006-02-09 Werner Koch + + * gpg.c (main) : Disable random locking. + 2006-02-06 Werner Koch * ccid-driver.c, ccid-driver.h: Updated from GnuPG 1.9. Changes: diff --git a/g10/gpg.c b/g10/gpg.c index 6f834bd4d..b2fb1a57f 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -2404,7 +2404,10 @@ main (int argc, char **argv ) case oEscapeFrom: opt.escape_from = 1; break; case oNoEscapeFrom: opt.escape_from = 0; break; case oLockOnce: opt.lock_once = 1; break; - case oLockNever: disable_dotlock(); break; + case oLockNever: + disable_dotlock (); + random_disable_locking (); + break; case oLockMultiple: #ifndef __riscos__ opt.lock_once = 0;