diff options
Diffstat (limited to 'libotr/libgcrypt-1.8.7/src/getrandom.c')
-rw-r--r-- | libotr/libgcrypt-1.8.7/src/getrandom.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/libotr/libgcrypt-1.8.7/src/getrandom.c b/libotr/libgcrypt-1.8.7/src/getrandom.c new file mode 100644 index 0000000..f9bb5c0 --- /dev/null +++ b/libotr/libgcrypt-1.8.7/src/getrandom.c @@ -0,0 +1,326 @@ +/* getrandom.c - Libgcrypt Random Number client + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * Getrandom 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. + * + * Getrandom 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <config.h> +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdarg.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <errno.h> + +#define PGM "getrandom" +#define MYVERSION_LINE PGM " (Libgcrypt) " VERSION +#define BUGREPORT_LINE "\nReport bugs to <bug-libgcrypt@gnupg.org>.\n" + + +static void +logit (const char *format, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, format) ; + fputs (PGM ": ", stderr); + vfprintf (stderr, format, arg_ptr); + putc ('\n', stderr); + va_end (arg_ptr); +} + + +/* Send LENGTH bytes of BUFFER to file descriptor FD. Returns 0 on + success or another value on write error. */ +static int +writen (int fd, const void *buffer, size_t length) +{ + while (length) + { + ssize_t n; + + do + n = write (fd, buffer, length); + while (n < 0 && errno == EINTR); + if (n < 0) + { + logit ("write error: %s", strerror (errno)); + return -1; /* write error */ + } + length -= n; + buffer = (const char *)buffer + n; + } + return 0; /* Okay */ +} + + + + +static void +print_version (int with_help) +{ + fputs (MYVERSION_LINE "\n" + "Copyright (C) 2006 Free Software Foundation, Inc.\n" + "License GPLv2+: GNU GPL version 2 or later " + "<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n", + stdout); + + if (with_help) + fputs ("\n" + "Usage: " PGM " [OPTIONS] NBYTES\n" + "Connect to libgcrypt's random number daemon and " + "return random numbers" + "\n" + " --nonce Return weak random suitable for a nonce\n" + " --very-strong Return very strong random\n" + " --ping Send a ping\n" + " --socket NAME Name of sockket to connect to\n" + " --hex Return result as a hex dump\n" + " --verbose Show what we are doing\n" + " --version Print version of the program and exit\n" + " --help Display this help and exit\n" + BUGREPORT_LINE, stdout ); + + exit (0); +} + +static int +print_usage (void) +{ + fputs ("usage: " PGM " [OPTIONS] NBYTES\n", stderr); + fputs (" (use --help to display options)\n", stderr); + exit (1); +} + + +int +main (int argc, char **argv) +{ + struct sockaddr_un *srvr_addr; + socklen_t addrlen; + int fd; + int rc; + unsigned char buffer[300]; + int nleft, nread; + const char *socketname = "/var/run/libgcrypt/S.gcryptrnd"; + int do_ping = 0; + int get_nonce = 0; + int get_very_strong = 0; + int req_nbytes, nbytes, n; + int verbose = 0; + int fail = 0; + int do_hex = 0; + + if (argc) + { + argc--; argv++; + } + while (argc && **argv == '-' && (*argv)[1] == '-') + { + if (!(*argv)[2]) + { + argc--; argv++; + break; + } + else if (!strcmp (*argv, "--version")) + print_version (0); + else if (!strcmp (*argv, "--help")) + print_version (1); + else if (!strcmp (*argv, "--socket") && argc > 1 ) + { + argc--; argv++; + socketname = *argv; + argc--; argv++; + } + else if (!strcmp (*argv, "--nonce")) + { + argc--; argv++; + get_nonce = 1; + } + else if (!strcmp (*argv, "--very-strong")) + { + argc--; argv++; + get_very_strong = 1; + } + else if (!strcmp (*argv, "--ping")) + { + argc--; argv++; + do_ping = 1; + } + else if (!strcmp (*argv, "--hex")) + { + argc--; argv++; + do_hex = 1; + } + else if (!strcmp (*argv, "--verbose")) + { + argc--; argv++; + verbose = 1; + } + else + print_usage (); + } + + + if (!argc && do_ping) + ; /* This is allowed. */ + else if (argc != 1) + print_usage (); + req_nbytes = argc? atoi (*argv) : 0; + + if (req_nbytes < 0) + print_usage (); + + /* Create a socket. */ + fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) + { + logit ("can't create socket: %s", strerror (errno)); + exit (1); + } + srvr_addr = malloc (sizeof *srvr_addr); + if (!srvr_addr) + { + logit ("malloc failed: %s", strerror (errno)); + exit (1); + } + memset (srvr_addr, 0, sizeof *srvr_addr); + srvr_addr->sun_family = AF_UNIX; + if (strlen (socketname) + 1 >= sizeof (srvr_addr->sun_path)) + { + logit ("socket name `%s' too long", socketname); + exit (1); + } + strcpy (srvr_addr->sun_path, socketname); + addrlen = (offsetof (struct sockaddr_un, sun_path) + + strlen (srvr_addr->sun_path) + 1); + rc = connect (fd, (struct sockaddr*) srvr_addr, addrlen); + if (rc == -1) + { + logit ("error connecting socket `%s': %s", + srvr_addr->sun_path, strerror (errno)); + close (fd); + exit (1); + } + + do + { + nbytes = req_nbytes > 255? 255 : req_nbytes; + req_nbytes -= nbytes; + + buffer[0] = 3; + if (do_ping) + buffer[1] = 0; + else if (get_nonce) + buffer[1] = 10; + else if (get_very_strong) + buffer[1] = 12; + else + buffer[1] = 11; + buffer[2] = nbytes; + if (writen (fd, buffer, 3)) + fail = 1; + else + { + for (nleft=2, nread=0; nleft > 0; ) + { + do + n = read (fd, buffer+nread, nleft); + while (n < 0 && errno == EINTR); + if (n < 0) + { + logit ("read error: %s", strerror (errno)); + exit (1); + } + nleft -= n; + nread += n; + if (nread && buffer[0]) + { + logit ("server returned error code %d", buffer[0]); + exit (1); + } + } + if (verbose) + logit ("received response with %d bytes of data", buffer[1]); + if (buffer[1] < nbytes) + { + logit ("warning: server returned less bytes than requested"); + fail = 1; + } + else if (buffer[1] > nbytes && !do_ping) + { + logit ("warning: server returned more bytes than requested"); + fail = 1; + } + nbytes = buffer[1]; + if (nbytes > sizeof buffer) + { + logit ("buffer too short to receive data"); + exit (1); + } + + for (nleft=nbytes, nread=0; nleft > 0; ) + { + do + n = read (fd, buffer+nread, nleft); + while (n < 0 && errno == EINTR); + if (n < 0) + { + logit ("read error: %s", strerror (errno)); + exit (1); + } + nleft -= n; + nread += n; + } + + if (do_hex) + { + for (n=0; n < nbytes; n++) + { + if (!n) + ; + else if (!(n % 16)) + putchar ('\n'); + else + putchar (' '); + printf ("%02X", buffer[n]); + } + if (nbytes) + putchar ('\n'); + } + else + { + if (fwrite (buffer, nbytes, 1, stdout) != 1) + { + logit ("error writing to stdout: %s", strerror (errno)); + fail = 1; + } + } + } + } + while (!fail && req_nbytes); + + close (fd); + free (srvr_addr); + return fail? 1 : 0; +} |