/* * rngd_linux.c -- Entropy sink for the Linux Kernel (/dev/random) * * Copyright (C) 2001 Philipp Rumpf * * This program 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. * * This program 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, Suite 500, Boston, MA 02110-1335 USA */ #define _GNU_SOURCE #ifndef HAVE_CONFIG_H #error Invalid or missing autoconf build environment #endif #include "rng-tools-config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rngd.h" #include "fips.h" #include "exits.h" #include "rngd_linux.h" extern struct rng *rng_list; /* Kernel output device */ static int random_fd; /* * Get the default watermark */ int default_watermark(void) { char psbuf[64], *p; unsigned long ps; FILE *f; size_t l; unsigned int wm = 2048; /* Default guess */ f = fopen("/proc/sys/kernel/random/poolsize", "r"); if (!f) goto err; l = fread(psbuf, 1, sizeof psbuf, f); if (ferror(f) || !feof(f) || l == 0) goto err; if (psbuf[l-1] != '\n') goto err; psbuf[l-1] = '\0'; ps = strtoul(psbuf, &p, 0); if (*p) goto err; wm = ps*3/4; err: if (f) fclose(f); return wm; } /* * Initialize the interface to the Linux Kernel * entropy pool (through /dev/random) * * randomdev is the path to the random device */ void init_kernel_rng(const char* randomdev) { FILE *f; int err; random_fd = open(randomdev, O_RDWR); if (random_fd == -1) { message(LOG_DAEMON|LOG_ERR, "can't open %s: %s", randomdev, strerror(errno)); exit(EXIT_USAGE); } f = fopen("/proc/sys/kernel/random/write_wakeup_threshold", "w"); if (!f) { err = 1; } else { fprintf(f, "%u\n", arguments->fill_watermark); /* Note | not || here... we always want to close the file */ err = ferror(f) | fclose(f); } if (err) { message(LOG_DAEMON|LOG_WARNING, "unable to adjust write_wakeup_threshold: %s", strerror(errno)); } } void random_add_entropy(void *buf, size_t size) { struct { int ent_count; int size; unsigned char data[size]; } entropy; entropy.ent_count = size * 8; entropy.size = size; memcpy(entropy.data, buf, size); if (ioctl(random_fd, RNDADDENTROPY, &entropy) != 0) { message(LOG_DAEMON|LOG_ERR, "RNDADDENTROPY failed: %s\n", strerror(errno)); exit(1); } } void random_sleep(void) { struct pollfd pfd = { fd: random_fd, events: POLLOUT, }; poll(&pfd, 1, -1); } void src_list_add(struct rng *ent_src) { if (rng_list) { struct rng *iter; iter = rng_list; while (iter->next) { iter = iter->next; } iter->next = ent_src; } else { rng_list = ent_src; } }