diff options
Diffstat (limited to 'plugins/MirOTR/Libgcrypt/random/rndlinux.c')
-rw-r--r-- | plugins/MirOTR/Libgcrypt/random/rndlinux.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/plugins/MirOTR/Libgcrypt/random/rndlinux.c b/plugins/MirOTR/Libgcrypt/random/rndlinux.c new file mode 100644 index 0000000000..574ef6dcc0 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/random/rndlinux.c @@ -0,0 +1,167 @@ +/* rndlinux.c - raw random number for OSes with /dev/random + * Copyright (C) 1998, 2001, 2002, 2003, 2007 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_GETTIMEOFDAY +# include <sys/times.h> +#endif +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include "types.h" +#include "g10lib.h" +#include "rand-internal.h" + +static int open_device ( const char *name ); + + +static int +set_cloexec_flag (int fd) +{ + int oldflags; + + oldflags= fcntl (fd, F_GETFD, 0); + if (oldflags < 0) + return oldflags; + oldflags |= FD_CLOEXEC; + return fcntl (fd, F_SETFD, oldflags); +} + + + +/* + * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists)). + */ +static int +open_device ( const char *name ) +{ + int fd; + + fd = open ( name, O_RDONLY ); + if ( fd == -1 ) + log_fatal ("can't open %s: %s\n", name, strerror(errno) ); + + if (set_cloexec_flag (fd)) + log_error ("error setting FD_CLOEXEC on fd %d: %s\n", + fd, strerror (errno)); + + /* We used to do the following check, however it turned out that this + is not portable since more OSes provide a random device which is + sometimes implemented as another device type. + + struct stat sb; + + if( fstat( fd, &sb ) ) + log_fatal("stat() off %s failed: %s\n", name, strerror(errno) ); + if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) ) + log_fatal("invalid random device!\n" ); + */ + return fd; +} + + +int +_gcry_rndlinux_gather_random (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level ) +{ + static int fd_urandom = -1; + static int fd_random = -1; + int fd; + int n; + int warn=0; + byte buffer[768]; + size_t n_hw; + + /* First read from a hardware source. However let it account only + for up to 50% of the requested bytes. */ + n_hw = _gcry_rndhw_poll_slow (add, origin); + if (n_hw > length/2) + n_hw = length/2; + if (length > 1) + length -= n_hw; + + /* Open the requested device. */ + if (level >= 2) + { + if( fd_random == -1 ) + fd_random = open_device ( NAME_OF_DEV_RANDOM ); + fd = fd_random; + } + else + { + if( fd_urandom == -1 ) + fd_urandom = open_device ( NAME_OF_DEV_URANDOM ); + fd = fd_urandom; + } + + /* And enter the read loop. */ + while (length) + { + fd_set rfds; + struct timeval tv; + int rc; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = 3; + tv.tv_usec = 0; + if( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) + { + if( !warn ) + { + _gcry_random_progress ("need_entropy", 'X', 0, (int)length); + warn = 1; + } + continue; + } + else if( rc == -1 ) + { + log_error ("select() error: %s\n", strerror(errno)); + continue; + } + + do + { + int nbytes = length < sizeof(buffer)? length : sizeof(buffer); + n = read(fd, buffer, nbytes ); + if( n >= 0 && n > nbytes ) + { + log_error("bogus read from random device (n=%d)\n", n ); + n = nbytes; + } + } + while( n == -1 && errno == EINTR ); + if( n == -1 ) + log_fatal("read error on random device: %s\n", strerror(errno)); + (*add)( buffer, n, origin ); + length -= n; + } + memset(buffer, 0, sizeof(buffer) ); + + return 0; /* success */ +} |