X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/ba6e6b64033b1f9de49feccb5c9cd438354481f7..0f00dc4c8eb47e67bc0f148c2dd109f73a451e0a:/noise.c diff --git a/noise.c b/noise.c deleted file mode 100644 index e339317..0000000 --- a/noise.c +++ /dev/null @@ -1,461 +0,0 @@ -/* -*-c-*- - * - * $Id$ - * - * Acquisition of environmental noise (Unix-specific) - * - * (c) 1998 Straylight/Edgeware - */ - -/*----- Licensing notice --------------------------------------------------* - * - * This file is part of Catacomb. - * - * Catacomb is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * Catacomb 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 Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with Catacomb; if not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. - */ - -/*----- Header files ------------------------------------------------------*/ - -#include "config.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#ifdef HAVE_SETGROUPS -# include -#endif - -#include -#include - -#include "noise.h" -#include "paranoia.h" -#include "rand.h" - -/*----- Magical numbers ---------------------------------------------------*/ - -#define NOISE_KIDLIFE 100000 /* @noise_filter@ child lifetime */ -#define MILLION 1000000 /* One million */ - -/*----- Noise source definition -------------------------------------------*/ - -const rand_source noise_source = { noise_acquire, noise_timer }; - -/*----- Static variables --------------------------------------------------*/ - -/* --- Timer differences --- */ - -static unsigned long noise_last; /* Last time recorded */ -static unsigned long noise_diff; /* Last first order difference */ - -/* --- Setuid program handling --- */ - -static uid_t noise_uid = NOISE_NOSETUID; /* Uid to set to spawn processes */ -static gid_t noise_gid = NOISE_NOSETGID; /* Gid to set to spawn processes */ - -/*----- Main code ---------------------------------------------------------*/ - -/* --- @bitcount@ --- * - * - * Arguments: @unsigned long x@ = a word containing bits - * - * Returns: The number of bits set in the word. - */ - -static int bitcount(unsigned long x) -{ - char ctab[] = { 0, 1, 1, 2, 1, 2, 2, 3, - 1, 2, 2, 3, 2, 3, 3, 4 }; - int count = 0; - while (x) { - count += ctab[x & 0xfu]; - x >>= 4; - } - return (count); -} - -/* --- @timer@ --- * - * - * Arguments: @rand_pool *r@ = pointer to randomness pool - * @struct timeval *tv@ = pointer to time block - * - * Returns: Nonzero if some randomness was contributed. - * - * Use: Low-level timer contributor. - */ - -static int timer(rand_pool *r, struct timeval *tv) -{ - unsigned long x, d, dd; - int de, dde; - int ret; - - x = tv->tv_usec + MILLION * tv->tv_sec; - d = x ^ noise_last; - dd = d ^ noise_diff; - noise_diff = d; - de = bitcount(d); - dde = bitcount(dd); - rand_add(r, tv, sizeof(*tv), de <= dde ? de : dde); - ret = (de || dde); - BURN(tv); x = d = dd = de = dde = 0; - return (ret); -} - -/* --- @noise_timer@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * - * Returns: Nonzero if some randomness was contributed. - * - * Use: Contributes the current time to the randomness pool. - * A guess at the number of useful bits contributed is made, - * based on first and second order bit differences. This isn't - * ever-so reliable, but it's better than nothing. - */ - -int noise_timer(rand_pool *r) -{ - struct timeval tv; - gettimeofday(&tv, 0); - return (timer(r, &tv)); -} - -/* --- @noise_devrandom@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * - * Returns: Nonzero if some randomness was contributed. - * - * Use: Attempts to obtain some randomness from the system entropy - * pool. All bits from the device are assumed to be good. - */ - -int noise_devrandom(rand_pool *r) -{ - int fd; - octet buf[RAND_POOLSZ]; - ssize_t len; - int ret = 0; - - /* --- Be nice to other clients of the random device --- * - * - * Attempt to open the device nonblockingly. If that works, take up to - * one bufferful and then close again. If there's no data to be read, - * then that's tough and we go away again, on the grounds that the device - * needs to get some more entropy from somewhere. - */ - - if ((fd = open("/dev/urandom", O_RDONLY | O_NONBLOCK)) >= 0 || - (fd = open("/dev/arandom", O_RDONLY | O_NONBLOCK)) >= 0 || - (fd = open("/dev/random", O_RDONLY | O_NONBLOCK)) >= 0) { - if ((len = read(fd, buf, sizeof(buf))) > 0) { - rand_add(r, buf, len, len * 8); - BURN(buf); - ret = 1; - } - close(fd); - } - noise_timer(r); - return (ret); -} - -/* --- @noise_setid@ --- * - * - * Arguments: @uid_t uid@ = uid to set - * @gid_t gid@ = gid to set - * - * Returns: --- - * - * Use: Sets the user and group ids to be used by @noise_filter@ - * when running child processes. This is useful to avoid - * giving shell commands (even carefully written ones) undue - * privileges. This interface is Unix-specific - */ - -void noise_setid(uid_t uid, gid_t gid) -{ - noise_uid = uid; - noise_gid = gid; -} - -/* --- @noise_filter@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * @int good@ = number of good bits per 1024 bits - * @const char *c@ = shell command to run - * - * Returns: Nonzero if some randomness was contributed. - * - * Use: Attempts to execute a shell command, and dump it into the - * randomness pool. A very rough estimate of the number of - * good bits is made, based on the size of the command's output. - * This function calls @waitpid@, so be careful. Before execing - * the command, the process uid and gid are set to the values - * given to @noise_setid@, and an attempt is made to reset the - * list of supplementary groups. The environment passed to - * the command has been severly lobotimized. If the command - * fails to complete within a short time period, it is killed. - * Paranoid use of close-on-exec flags for file descriptors is - * recommended. - * - * This interface is Unix-specific. - */ - -int noise_filter(rand_pool *r, int good, const char *c) -{ - char buf[4096]; - pid_t kid; - int fd[2]; - struct timeval dead; - int ret = 0; - const char *env[] = { - "PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc", - 0 - }; - - /* --- Remember when this business started --- */ - - gettimeofday(&dead, 0); - timer(r, &dead); - - /* --- Create a pipe --- */ - - if (pipe(fd)) - return (ret); - - /* --- Fork a child off --- */ - - fflush(0); - kid = fork(); - if (kid < 0) { - close(fd[0]); - close(fd[1]); - return (ret); - } - - /* --- Handle the child end of the deal --- */ - - if (kid == 0) { - int f; - - /* --- Set the pipe as standard output, close standard input --- */ - - close(0); close(1); close(2); - - if (fd[1] != 1) { - if (dup2(fd[1], 1) < 0) _exit(127); - close(fd[1]); - } - - if ((f = open("/dev/null", O_RDONLY)) != 0 || - (f = open("/dev/null", O_WRONLY)) != 2) - _exit(127); - - /* --- Play games with uids --- */ - - if (noise_gid != NOISE_NOSETGID) { - setgid(noise_gid); - setegid(noise_gid); -#ifdef HAVE_SETGROUPS - setgroups(1, &noise_gid); -#endif - } - - if (noise_uid != NOISE_NOSETUID) { - setuid(noise_uid); - seteuid(noise_uid); - } - - /* --- Start the process up --- */ - - execle("/bin/sh", "-c", c, (char *)0, env); - _exit(127); - } - - /* --- Sort out my end of the deal --- */ - - close(fd[1]); - - /* --- Decide on the deadline --- */ - - TV_ADDL(&dead, &dead, 0, NOISE_KIDLIFE); - - /* --- Now read, and think --- */ - - for (;;) { - struct timeval now, diff; - fd_set rd; - - gettimeofday(&now, 0); - timer(r, &now); - if (TV_CMP(&now, >, &dead)) - break; - TV_SUB(&diff, &dead, &now); - - FD_ZERO(&rd); - FD_SET(fd[0], &rd); - - if (select(fd[0] + 1, &rd, 0, 0, &diff) < 0) - break; - if (FD_ISSET(fd[0], &rd)) { - ssize_t sz; - int goodbits; - - if ((sz = read(fd[0], buf, sizeof(buf))) <= 0) - break; - goodbits = (sz * good) / 128; - rand_add(r, buf, sz, goodbits); - ret = 1; - } - } - - /* --- We've finished with it: kill the child process --- * - * - * This is morally questionable. On the other hand, I don't want to be - * held up in the @waitpid@ call if I can possibly help it. Maybe a - * double-fork is worth doing here. - */ - - close(fd[0]); - BURN(buf); - noise_timer(r); - kill(kid, SIGKILL); - waitpid(kid, 0, 0); - return (ret); -} - -/* --- @noise_freewheel@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * - * Returns: Nonzero if some randomness was contributed. - * - * Use: Runs a free counter for a short while as a desparate attempt - * to get randomness from somewhere. This is actually quite - * effective. - */ - -#ifdef USE_FREEWHEEL - -static jmp_buf fwjmp; - -static void fwalarm(int sig) -{ - siglongjmp(fwjmp, 1); -} - -int noise_freewheel(rand_pool *r) -{ - void (*sigal)(int) = 0; - struct itimerval oitv, itv = { { 0, 0 }, { 0, 5000 } }; - int rc = 0; - volatile uint32 fwcount = 0; - - if (!sigsetjmp(fwjmp, 1)) { - if ((sigal = signal(SIGALRM, fwalarm)) == SIG_ERR) - return (0); - if (setitimer(ITIMER_REAL, &itv, &oitv)) - goto done; - for (;;) - fwcount++; - } else { - octet buf[4]; - STORE32(buf, fwcount); - rand_add(r, buf, sizeof(buf), 16); - rc = 1; - } - -done: - signal(SIGALRM, sigal); - if (oitv.it_value.tv_sec || oitv.it_value.tv_usec) - TV_SUB(&oitv.it_value, &oitv.it_value, &itv.it_value); - setitimer(ITIMER_REAL, &oitv, 0); - return (rc); -} - -#else - -int noise_freewheel(rand_pool *r) -{ - return (0); -} - -#endif - -/* --- @noise_enquire@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * - * Returns: Nonzero if some randomness was contributed. - * - * Use: Runs some shell commands to enquire about the prevailing - * environment. This can gather quite a lot of low-quality - * entropy. - */ - -int noise_enquire(rand_pool *r) -{ - struct tab { - const char *cmd; - unsigned rate; - } tab[] = { - { "ps alxww || ps -elf", 16 }, - { "netstat -n", 6 }, - { "ifconfig -a", 8 }, - { "df", 20 }, - { "w", 6 }, - { "ls -align /tmp/.", 10 }, - { 0, 0 } - }; - int i; - - for (i = 0; tab[i].cmd; i++) - noise_filter(r, tab[i].rate, tab[i].cmd); - return (1); -} - -/* --- @noise_acquire@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * - * Returns: --- - * - * Use: Acquires some randomness from somewhere. - */ - -void noise_acquire(rand_pool *r) -{ - unsigned i; - for (i = 0; i < 8; i++) - noise_freewheel(r); - if (!noise_devrandom(r)) { - noise_enquire(r); - for (i = 0; i < 8; i++) - noise_freewheel(r); - } -} - -/*----- That's all, folks -------------------------------------------------*/