X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/2b87da3b1fb7c5ca907cb65aa048fada4ad29803..e339aa537da1f01f56f5d61857e9baabbb0988ad:/entropy.c diff --git a/entropy.c b/entropy.c index 82bb574d..44440d97 100644 --- a/entropy.c +++ b/entropy.c @@ -26,6 +26,7 @@ #include #include +#include /* SunOS 4.4.4 needs this */ #ifdef HAVE_FLOATINGPOINT_H @@ -33,6 +34,7 @@ #endif /* HAVE_FLOATINGPOINT_H */ #include "ssh.h" +#include "misc.h" #include "xmalloc.h" #include "atomicio.h" #include "pathnames.h" @@ -62,67 +64,126 @@ RCSID("$Id$"); # define RUSAGE_CHILDREN 0 #endif -#if defined(EGD_SOCKET) || defined(RANDOM_POOL) +#if defined(_POSIX_SAVED_IDS) && !defined(BROKEN_SAVED_UIDS) +# define SAVED_IDS_WORK_WITH_SETEUID +#endif -#ifdef EGD_SOCKET -/* Collect entropy from EGD */ -int get_random_bytes(unsigned char *buf, int len) +void +check_openssl_version(void) +{ + if (SSLeay() != OPENSSL_VERSION_NUMBER) + fatal("OpenSSL version mismatch. Built against %lx, you " + "have %lx", OPENSSL_VERSION_NUMBER, SSLeay()); +} + +#if defined(PRNGD_SOCKET) || defined(PRNGD_PORT) +# define USE_PRNGD +#endif + +#if defined(USE_PRNGD) || defined(RANDOM_POOL) + +#ifdef USE_PRNGD +/* Collect entropy from PRNGD/EGD */ +int +get_random_bytes(unsigned char *buf, int len) { int fd; char msg[2]; +#ifdef PRNGD_PORT + struct sockaddr_in addr; +#else struct sockaddr_un addr; - int addr_len; +#endif + int addr_len, rval, errors; + mysig_t old_sigpipe; + memset(&addr, '\0', sizeof(addr)); + +#ifdef PRNGD_PORT + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_port = htons(PRNGD_PORT); + addr_len = sizeof(struct sockaddr_in); +#else /* use IP socket PRNGD_SOCKET instead */ /* Sanity checks */ - if (sizeof(EGD_SOCKET) > sizeof(addr.sun_path)) + if (sizeof(PRNGD_SOCKET) > sizeof(addr.sun_path)) fatal("Random pool path is too long"); if (len > 255) - fatal("Too many bytes to read from EGD"); + fatal("Too many bytes to read from PRNGD"); - memset(&addr, '\0', sizeof(addr)); addr.sun_family = AF_UNIX; - strlcpy(addr.sun_path, EGD_SOCKET, sizeof(addr.sun_path)); - addr_len = offsetof(struct sockaddr_un, sun_path) + sizeof(EGD_SOCKET); + strlcpy(addr.sun_path, PRNGD_SOCKET, sizeof(addr.sun_path)); + addr_len = offsetof(struct sockaddr_un, sun_path) + + sizeof(PRNGD_SOCKET); +#endif - fd = socket(AF_UNIX, SOCK_STREAM, 0); + old_sigpipe = mysignal(SIGPIPE, SIG_IGN); + + errors = rval = 0; +reopen: +#ifdef PRNGD_PORT + fd = socket(addr.sin_family, SOCK_STREAM, 0); + if (fd == -1) { + error("Couldn't create AF_INET socket: %s", strerror(errno)); + goto done; + } +#else + fd = socket(addr.sun_family, SOCK_STREAM, 0); if (fd == -1) { error("Couldn't create AF_UNIX socket: %s", strerror(errno)); - return(0); + goto done; } +#endif if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) { - error("Couldn't connect to EGD socket \"%s\": %s", - addr.sun_path, strerror(errno)); - close(fd); - return(0); +#ifdef PRNGD_PORT + error("Couldn't connect to PRNGD port %d: %s", + PRNGD_PORT, strerror(errno)); +#else + error("Couldn't connect to PRNGD socket \"%s\": %s", + addr.sun_path, strerror(errno)); +#endif + goto done; } - /* Send blocking read request to EGD */ + /* Send blocking read request to PRNGD */ msg[0] = 0x02; msg[1] = len; if (atomicio(write, fd, msg, sizeof(msg)) != sizeof(msg)) { - error("Couldn't write to EGD socket \"%s\": %s", - EGD_SOCKET, strerror(errno)); - close(fd); - return(0); + if (errno == EPIPE && errors < 10) { + close(fd); + errors++; + goto reopen; + } + error("Couldn't write to PRNGD socket: %s", + strerror(errno)); + goto done; } if (atomicio(read, fd, buf, len) != len) { - error("Couldn't read from EGD socket \"%s\": %s", - EGD_SOCKET, strerror(errno)); - close(fd); - return(0); + if (errno == EPIPE && errors < 10) { + close(fd); + errors++; + goto reopen; + } + error("Couldn't read from PRNGD socket: %s", + strerror(errno)); + goto done; } - close(fd); - - return(1); + rval = 1; +done: + mysignal(SIGPIPE, old_sigpipe); + if (fd != -1) + close(fd); + return(rval); } -#else /* !EGD_SOCKET */ +#else /* !USE_PRNGD */ #ifdef RANDOM_POOL /* Collect entropy from /dev/urandom or pipe */ -int get_random_bytes(unsigned char *buf, int len) +int +get_random_bytes(unsigned char *buf, int len) { int random_pool; @@ -145,16 +206,16 @@ int get_random_bytes(unsigned char *buf, int len) return(1); } #endif /* RANDOM_POOL */ -#endif /* EGD_SOCKET */ +#endif /* USE_PRNGD */ /* * Seed OpenSSL's random number pool from Kernel random number generator - * or EGD + * or PRNGD/EGD */ void seed_rng(void) { - char buf[32]; + unsigned char buf[32]; debug("Seeding random number generator"); @@ -168,10 +229,13 @@ seed_rng(void) memset(buf, '\0', sizeof(buf)); } -/* No-op */ -void init_rng(void) {} +void +init_rng(void) +{ + check_openssl_version(); +} -#else /* defined(EGD_SOCKET) || defined(RANDOM_POOL) */ +#else /* defined(USE_PRNGD) || defined(RANDOM_POOL) */ /* * FIXME: proper entropy estimations. All current values are guesses @@ -343,8 +407,7 @@ stir_rusage(int who, double entropy_estimate) } -static -int +static int _get_timeval_msec_difference(struct timeval *t1, struct timeval *t2) { int secdiff, usecdiff; @@ -773,31 +836,36 @@ prng_seed_cleanup(void *junk) void seed_rng(void) { - void *old_sigchld_handler; + mysig_t old_sigchld_handler; if (!prng_initialised) fatal("RNG not initialised"); /* Make sure some other sigchld handler doesn't reap our entropy */ /* commands */ - old_sigchld_handler = signal(SIGCHLD, SIG_DFL); + old_sigchld_handler = mysignal(SIGCHLD, SIG_DFL); - debug("Seeded RNG with %i bytes from programs", (int)stir_from_programs()); - debug("Seeded RNG with %i bytes from system calls", (int)stir_from_system()); + debug("Seeded RNG with %i bytes from programs", + (int)stir_from_programs()); + debug("Seeded RNG with %i bytes from system calls", + (int)stir_from_system()); if (!RAND_status()) fatal("Not enough entropy in RNG"); - signal(SIGCHLD, old_sigchld_handler); + mysignal(SIGCHLD, old_sigchld_handler); if (!RAND_status()) fatal("Couldn't initialise builtin random number generator -- exiting."); } -void init_rng(void) +void +init_rng(void) { int original_euid; + check_openssl_version(); + original_uid = getuid(); original_euid = geteuid(); @@ -809,13 +877,34 @@ void init_rng(void) prng_seed_saved = 0; /* Give up privs while reading seed file */ +#ifdef SAVED_IDS_WORK_WITH_SETEUID if ((original_uid != original_euid) && (seteuid(original_uid) == -1)) fatal("Couldn't give up privileges"); +#else /* SAVED_IDS_WORK_WITH_SETEUID */ + /* + * Propagate the privileged uid to all of our uids. + * Set the effective uid to the given (unprivileged) uid. + */ + if (original_uid != original_euid && (setuid(original_euid) == -1 || + seteuid(original_uid) == -1)) + fatal("Couldn't give up privileges"); +#endif /* SAVED_IDS_WORK_WITH_SETEUID */ prng_read_seedfile(); +#ifdef SAVED_IDS_WORK_WITH_SETEUID if ((original_uid != original_euid) && (seteuid(original_euid) == -1)) fatal("Couldn't restore privileges"); +#else /* SAVED_IDS_WORK_WITH_SETEUID */ + /* + * We are unable to restore the real uid to its unprivileged value. + * Propagate the real uid (usually more privileged) to effective uid + * as well. + */ + if (original_uid != original_euid && (seteuid(original_euid) == -1 || + setuid(original_uid) == -1)) + fatal("Couldn't restore privileges"); +#endif /* SAVED_IDS_WORK_WITH_SETEUID */ fatal_add_cleanup(prng_seed_cleanup, NULL); atexit(prng_write_seedfile); @@ -823,4 +912,4 @@ void init_rng(void) prng_initialised = 1; } -#endif /* defined(EGD_SOCKET) || defined(RANDOM_POOL) */ +#endif /* defined(USE_PRNGD) || defined(RANDOM_POOL) */