From 94d6b7954dc5b7c98171095b56b15ed695923bb5 Mon Sep 17 00:00:00 2001 From: "Alex Xu (Hello71)" Date: Wed, 15 Aug 2018 11:26:39 -0400 Subject: Move source files to src --- random-seed.c | 575 ---------------------------------------------------------- 1 file changed, 575 deletions(-) delete mode 100644 random-seed.c (limited to 'random-seed.c') diff --git a/random-seed.c b/random-seed.c deleted file mode 100644 index 0b7c5c4..0000000 --- a/random-seed.c +++ /dev/null @@ -1,575 +0,0 @@ -/* Copyright 2018 Alex Xu (aka Hello71, alxu) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "musl-libgen-c.h" -#include "util.h" - -// musl forbids include/linux -#define RNDADDENTROPY _IOW( 'R', 0x03, int [2] ) - -/* 3 hours */ -#define DAEMONIZE_SLEEP_TIME (3*60*60) - -/* random pool is always the same size, so use a fixed size array */ -struct rand_pool_info_ { - int entropy_count; - int buf_size; - uint32_t buf[RAND_POOL_SIZE / sizeof(uint32_t)]; -}; - -static const char MAGIC[] = "RANDOM SEED FILE VERSION 1\n"; - -static sig_atomic_t sigint = 0; -static sig_atomic_t sigterm = 0; - -static bool noperms = false; - -static inline void usage() { - puts("usage: random-seed MODE FILE"); - puts("see random-seed(8) for more information."); -} - -static char *get_machine_id() { -#ifdef MACHINE_ID_PATH - FILE *machine_id_file = fopen(MACHINE_ID_PATH, "r"); -#else - const char *etc_machine_id = "/etc/machine-id"; - const char *var_lib_dbus_machine_id = "/var/lib/dbus/machine-id"; - FILE *machine_id_file = fopen(etc_machine_id, "r"); - if (!machine_id_file) { - if (errno != ENOENT) - fprintf(stderr, "error opening %s: %s, trying %s\n", - etc_machine_id, strerror(errno), var_lib_dbus_machine_id); - machine_id_file = fopen(var_lib_dbus_machine_id, "r"); - } -#endif - - if (!machine_id_file) { - perror("couldn't open any machine-id file, last error"); - return NULL; - } - - char *machine_id = NULL; - size_t machine_id_len = 0; - if (getdelim(&machine_id, &machine_id_len, '\0', machine_id_file) == -1) { - fputs("error reading machine id file\n", stderr); - free(machine_id); - return NULL; - } - - return machine_id; -} - -static bool get_machine_id_hash(const unsigned char salt[static SALT_LEN], unsigned char machine_id_digest[static HASH_LEN]) { - static char *c_machine_id; - if (!c_machine_id) - c_machine_id = get_machine_id(); - if (!c_machine_id) - return false; - - unsigned char c_machine_id_digest[HASH_LEN]; - hash(salt, c_machine_id_digest, c_machine_id, strlen(c_machine_id)); - memcpy(machine_id_digest, c_machine_id_digest, HASH_LEN); - return true; -} - -static inline bool get_fs_id_hash(const unsigned char salt[static SALT_LEN], unsigned char fsid_digest[static HASH_LEN], int seed_fd) { - struct statfs statfs_buf; - if (fstatfs(seed_fd, &statfs_buf) == -1) { - fprintf(stderr, "error statfs seed file: %s, " - "disabling entropy credit\n", strerror(errno)); - return false; - } - hash(salt, fsid_digest, &statfs_buf.f_fsid, sizeof(statfs_buf.f_fsid)); - return true; -} - -static bool run_seed_file_cmd(const char *cmd, const unsigned char *salt, FILE *seed_file) { - char *arg; - if (streq(cmd, "machine-id")) { - arg = strtok(NULL, " \t"); - if (!arg) { - fputs("error parsing seed file: expected argument " - "to 'machine-id'\n", stderr); - return false; - } - unsigned char machine_id_hash[HASH_LEN]; - if (!get_machine_id_hash(salt, machine_id_hash)) { - fputs("error getting machine id hash, disabling entropy credit\n", - stderr); - return false; - } - - if (!hash_match(machine_id_hash, arg)) { - fputs("machine-id does not match, disabling entropy credit\n", - stderr); - return false; - } - return true; - } - - if (streq(cmd, "fs-id")) { - arg = strtok(NULL, " \t"); - if (!arg) { - fputs("error parsing seed file: expected argument to 'fs-id'\n", stderr); - return false; - } - unsigned char fs_id_hash[HASH_LEN]; - if (!get_fs_id_hash(salt, fs_id_hash, fileno(seed_file))) { - fputs("error getting fs id hash, disabling entropy credit\n", stderr); - return false; - } - - if (!hash_match(fs_id_hash, arg)) { - fputs("fs id does not match, disabling entropy credit\n", stderr); - return false; - } - return true; - } - - fprintf(stderr, "error parsing seed file: unsupported command: %s\n", cmd); - return false; -} - -static bool load(FILE *seed_file) { - bool credit_entropy = true; - - struct rand_pool_info_ rpi = { - .entropy_count = RAND_POOL_SIZE * 8, - .buf_size = RAND_POOL_SIZE, - .buf = { 0 } - }; - - uint64_t linenum = 0; - char *line = NULL; - size_t n = 0; - bool done = false; - - if (fread(&rpi.buf, 1, RAND_POOL_SIZE, seed_file) != RAND_POOL_SIZE) { - if (feof(seed_file)) { - fputs("premature EOF on seed file\n", stderr); - } else if (ferror(seed_file)) { - fputs("error reading from seed file\n", stderr); - } - // else: we got signalled, so return to main loop to quit or whatever - return false; - } - - unsigned char *salt = (unsigned char *)rpi.buf; - - while (1) { - errno = 0; - ssize_t line_length = getline(&line, &n, seed_file); - if (line_length == -1) { - if (errno) { - perror("error reading from seed file"); - credit_entropy = false; - } - break; - } - - linenum++; - - if (linenum == 1) { - if (streq(line, MAGIC)) { - continue; - } else { - fputs("error parsing seed file: invalid magic\n", stderr); - credit_entropy = false; - break; - } - } - - char *nul = memchr(line, '\0', (size_t)line_length); - if (nul) { - fprintf(stderr, "error parsing seed file: encountered NUL byte in commands line %zu char %zu\n", linenum, nul - line + 1); - credit_entropy = false; - break; - } - - char *cmd = strtok(line, " \t\n"); - if (!cmd) - continue; - -#ifdef DEBUG - fprintf(stderr, "executing command: %s\n", cmd); -#endif - - if (streq(cmd, "done")) { - done = true; - continue; - } - - if (!run_seed_file_cmd(cmd, salt, seed_file)) { - credit_entropy = false; - break; - } - } - - if (!linenum) { - fputs("seed file has no commands, assuming legacy format. disabling entropy credit\n", stderr); - credit_entropy = false; - } - - if (credit_entropy && !done) { - fputs("missing done command, random seed file probably truncated. disabling entropy credit\n", stderr); - credit_entropy = false; - } - - int random_fd = open("/dev/random", O_RDWR, 0); - if (random_fd == -1) { - perror("error opening /dev/random"); - exit(1); - } - - if (credit_entropy) { - if (ioctl(random_fd, RNDADDENTROPY, &rpi) == -1) { - perror("ioctl(RNDADDENTROPY)"); - if (errno == EPERM) { - fputs("Continuing without crediting entropy.\n", stderr); - noperms = true; - } - credit_entropy = false; - } - } - - if (!credit_entropy) { - if (write(random_fd, &rpi.buf, RAND_POOL_SIZE) != RAND_POOL_SIZE) { - fputs("error writing entropy to /dev/random\n", stderr); - exit(1); - } - } - - return credit_entropy; -} - -static bool get_rand_pool(unsigned char *buf) { - size_t rand_bytes_gotten = 0; - - do { - long this_rand_bytes_gotten = random_get(buf + rand_bytes_gotten, RAND_POOL_SIZE - rand_bytes_gotten, 0); - if (this_rand_bytes_gotten == -1) { - switch (errno) { - case EAGAIN: continue; - case EINTR: return false; - default: - perror("getrandom"); - exit(1); - } - } else { - rand_bytes_gotten += (size_t)this_rand_bytes_gotten; - } - } while (rand_bytes_gotten < RAND_POOL_SIZE); - - return true; -} - -/** - * Save entropy to disk. - * - * \param seed_path the seed file path - * \param random_buf the random buffer. if NULL, get our own entropy. - * \return true means saved successfully, false means received EINTR - */ -static bool save(const char *seed_path, unsigned char *random_buf) { - assert(seed_path); - - bool rv = false; - - unsigned char *random_ptr; - if (random_buf) { - random_ptr = random_buf; - } else { - random_ptr = alloca(RAND_POOL_SIZE); - if (!get_rand_pool(random_ptr)) - return false; - } - - unsigned char machine_id_digest[HASH_LEN]; - if (!get_machine_id_hash(random_ptr, machine_id_digest)) { - fputs("cannot obtain machine id, aborting save\n", stderr); - return false; - } - char machine_id_hash[HASH_STR_LEN]; - mem2hex(machine_id_hash, machine_id_digest, HASH_STR_LEN); - machine_id_hash[HASH_STR_LEN-1] = '\0'; - - int seed_dir_fd = -1; - int seed_fd = -1; - FILE *seed_file = NULL; - - char *seed_path_tmp = strdup(seed_path); - const char *seed_dir, *seed_name; - char *seed_path_last_slash = strrchr(seed_path_tmp, '/'); - if (seed_path_last_slash) { - *seed_path_last_slash = '\0'; - seed_dir = seed_path_tmp; - seed_name = seed_path_last_slash + 1; - } else { - free(seed_path_tmp); - seed_path_tmp = NULL; - seed_dir = "."; - seed_name = seed_path; - } - char *seed_name_new = NULL; - - if (asprintf(&seed_name_new, ".%s.new", seed_name) == -1) { - fputs("out of memory\n", stderr); - goto out; - } - - seed_dir_fd = open(seed_dir, O_RDONLY | O_DIRECTORY); - if (seed_dir_fd == -1) { - perror("error opening seed directory"); - goto out; - } - - unsigned char fs_id_digest[HASH_LEN]; - if (!get_fs_id_hash(random_ptr, fs_id_digest, seed_dir_fd)) { - fputs("cannot obtain machine id, aborting save\n", stderr); - goto out; - } - char fs_id_hash[HASH_LEN*2+1]; - mem2hex(fs_id_hash, fs_id_digest, HASH_LEN); - fs_id_hash[sizeof(fs_id_hash)-1] = '\0'; - - seed_fd = openat(seed_dir_fd, seed_name_new, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (seed_fd == -1) { - perror("error opening new seed file"); - goto err; - } - seed_file = fdopen(seed_fd, "w"); - if (!seed_file) { - perror("error converting seed file fd to stream"); - goto err; - } - - if (fwrite(random_ptr, 1, RAND_POOL_SIZE, seed_file) != RAND_POOL_SIZE - || fputs(MAGIC, seed_file) == EOF - || fputs("machine-id ", seed_file) == EOF - || fputs(machine_id_hash, seed_file) == EOF - || fputs("\nfs-id ", seed_file) == EOF - || fputs(fs_id_hash, seed_file) == EOF - || fputs("\ndone\n", seed_file) == EOF) { - fputs("error writing new seed file\n", stderr); - goto err; - } - - if (fflush(seed_file) == EOF) { - perror("error flushing new seed file"); - goto err; - } - if (fsync(seed_fd) == -1) { - perror("error syncing new seed file"); - goto err; - } - if (renameat(seed_dir_fd, seed_name_new, seed_dir_fd, seed_name) == -1) { - perror("error installing new seed file"); - goto err; - } - if (fclose(seed_file) == EOF) { - perror("error closing new seed file"); - goto err; - } - if (fsync(seed_dir_fd) == -1) { - perror("error syncing seed directory"); - goto out; - } - - rv = true; - goto out; - -err: - if (seed_file) { - fclose(seed_file); - if (unlinkat(seed_dir_fd, seed_name_new, 0) == -1) { - perror("error removing temporary seed file"); - rv = false; - } - } - -out: - if (seed_dir_fd != -1) { - if (close(seed_dir_fd) == -1) { - perror("error closing seed directory"); - rv = false; - } - } - - free(seed_path_tmp); - free(seed_name_new); - - return rv; -} - -static void sighandler(int signum) { - switch (signum) { - case SIGHUP: - // do nothing; we just needed to interrupt sleep - break; - case SIGINT: - sigint = 1; - break; - case SIGTERM: - sigterm = 1; - break; - default: - abort(); - } -} - -noreturn static void run(const char *mode, const char *seed_path) { - FILE *seed_file; - int exit_status = 0; - - if (streq(mode, "load")) { - bool refresh_seed = true; - - if (streq(seed_path, "-")) { - fputs("warning: cannot refresh stdin seed\n", stderr); - seed_file = stdin; - refresh_seed = false; - } else { - seed_file = fopen(seed_path, "r"); - } - if (!seed_file) { - perror("error opening seed file"); - exit(1); - } - if (!load(seed_file)) { - if (noperms) - exit_status = 15; - else - exit_status = 1; - } - if (refresh_seed) { - unsigned char random_buf[RAND_POOL_SIZE]; - unsigned char *random_ptr = random_buf; - switch (random_get(random_buf, RAND_POOL_SIZE, GRND_NONBLOCK)) { - case RAND_POOL_SIZE: - goto save; - case -1: - if (errno != EAGAIN) { - perror("getrandom"); - exit(1); - } - } - if (daemon(0, 1) == -1) { - perror("error daemonizing, continuing without"); - } - close(0); - close(1); - random_ptr = NULL; -save: if (!save(seed_path, random_ptr)) - exit_status = 1; - } - exit(exit_status); - } else if (streq(mode, "save")) { - exit(!save(seed_path, NULL)); - } else if (streq(mode, "daemonize")) { - if (streq(seed_path, "-")) { - fputs("error: seed_path cannot be - for daemonize\n", stderr); - exit(2); - } - seed_file = fopen(seed_path, "r"); - if (!seed_file) { - perror("error opening seed file"); - exit(3); - } - if (!load(seed_file)) - fputs("warning: failed to load initial entropy\n", stderr); - - struct sigaction sa; - sa.sa_handler = sighandler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - - if (daemon(seed_path[0] != '/', 1) == -1) { - perror("error daemonizing"); - exit(1); - } - close(0); - close(1); - // don't close stderr because we log there - - while (true) { - if (sigint) - exit(exit_status); - if (!save(seed_path, NULL)) { - exit_status = 1; - fputs("an error occurred while saving, trying again later\n", stderr); - } - if (sigterm) - exit(exit_status); - sleep(DAEMONIZE_SLEEP_TIME); - } - } else if (streq(mode, "daemonise")) { - fputs("invalid mode (did you mean `daemonize'?)\n", stderr); - exit(2); - } else { - fputs("invalid mode, expected load, save, or daemonize\n", stderr); - exit(2); - } -} - -int main(int argc, char *argv[]) { - char *mode, *seed_path; - - switch (argc) { - case 2: - if (streq(argv[1], "-h") || streq(argv[1], "--help")) { - usage(); - exit(0); - } - if (streq(argv[1], "-V") || streq(argv[1], "--version")) { - printf("random-seed %s\n", PACKAGE_VERSION); - exit(0); - } - mode = argv[1]; - seed_path = DEFAULT_SEED_PATH; - break; - case 3: - mode = argv[1]; - seed_path = argv[2]; - break; - default: - fprintf(stderr, "error: invalid arguments\n"); - usage(); - exit(2); - } - - umask(0); - run(mode, seed_path); -} -- cgit v1.2.3-70-g09d2