summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in6
-rw-r--r--random-seed.c109
-rw-r--r--util.c30
-rw-r--r--util.h11
4 files changed, 95 insertions, 61 deletions
diff --git a/Makefile.in b/Makefile.in
index d3e3430..f52121e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -49,8 +49,8 @@ endif
test: $(TEST_FILE)
$(TEST_FILE): random-seed
- ./random-seed save $(TEST_FILE)
- ./random-seed load $(TEST_FILE) || [ $$? = 15 ]
+ $(TEST_WRAPPER) ./random-seed save $(TEST_FILE)
+ $(TEST_WRAPPER) ./random-seed load $(TEST_FILE) || [ $$? = 15 ]
clean:
$(RM) random-seed $(OBJ) $(DEP) $(TEST_FILE)
@@ -58,5 +58,5 @@ clean:
distclean: clean
$(RM) -r aclocal.m4 autom4te.cache config.h config.h.in 'config.h.in~' config.log config.status configure Makefile
-.PHONY: all install test clean
+.PHONY: all install test clean random-seed.test
.INTERMEDIATE: $(TEST_FILE)
diff --git a/random-seed.c b/random-seed.c
index 6ed971b..53ad8e3 100644
--- a/random-seed.c
+++ b/random-seed.c
@@ -213,7 +213,7 @@ static bool load(FILE *seed_file) {
}
}
- char *nul = memchr(line, '\0', line_length);
+ 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;
@@ -272,10 +272,11 @@ static bool load(FILE *seed_file) {
}
static bool get_rand_pool(unsigned char *buf) {
- size_t rand_bits_gotten = 0;
- while (rand_bits_gotten < RAND_POOL_SIZE) {
- long this_rand_bits_gotten = random_get(buf + rand_bits_gotten, RAND_POOL_SIZE - rand_bits_gotten, 0);
- if (this_rand_bits_gotten < 0) {
+ 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;
@@ -284,9 +285,10 @@ static bool get_rand_pool(unsigned char *buf) {
exit(1);
}
} else {
- rand_bits_gotten += (size_t)this_rand_bits_gotten;
+ rand_bytes_gotten += (size_t)this_rand_bytes_gotten;
}
- }
+ } while (rand_bytes_gotten < RAND_POOL_SIZE);
+
return true;
}
@@ -301,61 +303,64 @@ static bool save(const char *seed_path, unsigned char *random_buf) {
assert(seed_path);
bool rv = false;
- char *seed_path_tmp = NULL;
- char *seed_name_new = NULL;
- unsigned char my_random_buf[RAND_POOL_SIZE];
- if (!random_buf) {
- if (!get_rand_pool(my_random_buf))
+ 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;
- random_buf = my_random_buf;
}
unsigned char machine_id_digest[HASH_LEN];
- if (!get_machine_id_hash(random_buf, machine_id_digest)) {
+ 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_LEN*2+1];
- memset(machine_id_hash, 0, HASH_LEN*2);
- mem2hex(machine_id_hash, machine_id_digest, HASH_LEN);
- machine_id_hash[sizeof(machine_id_hash)-1] = '\0';
+ 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;
- seed_path_tmp = strdup(seed_path);
+ 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(mydirname(seed_path_tmp), O_RDONLY | O_DIRECTORY);
+ 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_buf, fs_id_digest, seed_dir_fd)) {
+ if (!get_fs_id_hash(random_ptr, fs_id_digest, seed_dir_fd)) {
fputs("cannot obtain machine id, aborting save\n", stderr);
- free(seed_path_tmp);
- return false;
+ 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';
- strcpy(seed_path_tmp, seed_path);
- char *seed_name = mybasename(seed_path_tmp);
- size_t seed_name_new_len = strlen(seed_name) + 6;
- seed_name_new = malloc(seed_name_new_len);
- if (!seed_name_new) {
- fputs("out of memory\n", stderr);
- free(seed_path_tmp);
- return false;
- }
- assert(seed_name_new_len < INT_MAX);
- if ((size_t)snprintf(seed_name_new, seed_name_new_len, ".%s.new", seed_name) >= seed_name_new_len)
- abort();
-
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");
@@ -367,7 +372,7 @@ static bool save(const char *seed_path, unsigned char *random_buf) {
goto err;
}
- if (fwrite(random_buf, 1, RAND_POOL_SIZE, seed_file) != RAND_POOL_SIZE
+ 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
@@ -468,17 +473,22 @@ noreturn static void run(const char *mode, const char *seed_path) {
if (refresh_seed) {
unsigned char random_buf[RAND_POOL_SIZE];
unsigned char *random_ptr = random_buf;
- if (random_get(random_buf, sizeof(random_buf), GRND_NONBLOCK) == -1) {
- if (errno != EAGAIN) {
- perror("getrandom");
- exit(1);
- }
- daemon(0, 1);
- close(0);
- close(1);
- random_ptr = NULL;
+ 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 (!save(seed_path, random_ptr))
+ 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);
@@ -505,7 +515,10 @@ noreturn static void run(const char *mode, const char *seed_path) {
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
- daemon(seed_path[0] != '/', 1);
+ if (daemon(seed_path[0] != '/', 1) == -1) {
+ perror("error daemonizing");
+ exit(1);
+ }
close(0);
close(1);
// don't close stderr because we log there
diff --git a/util.c b/util.c
index f0d1fda..a5eb220 100644
--- a/util.c
+++ b/util.c
@@ -68,7 +68,7 @@ void hash(const unsigned char salt[static SALT_LEN], unsigned char *out, const v
sha256_final(&ctx, out);
}
-void print_hash(const unsigned char digest[static HASH_LEN]) {
+static void print_hash(const unsigned char digest[static HASH_LEN]) {
#ifdef DEBUG
char hash[HASH_LEN*2+1];
mem2hex(hash, digest, HASH_LEN);
@@ -93,3 +93,31 @@ bool hash_match(const unsigned char digest[static HASH_LEN], const char *arg) {
#endif
return !memcmp(digest, theirdigest, HASH_LEN);
}
+
+ssize_t random_get(void *buf, size_t buflen, unsigned int flags) {
+ memset(buf, 0, buflen);
+
+ long rv = syscall(SYS_getrandom, buf, buflen, flags);
+ if (rv == -1) {
+ if (errno == ENOSYS) {
+ fputs("getrandom returned ENOSYS. random-seed requires Linux 3.17\n", stderr);
+ exit(1);
+ }
+ } else {
+ bool all_zero = true;
+ if (buflen > 32) {
+ for (size_t i = 0; i < buflen; i++) {
+ if (((unsigned char *)buf)[i] != 0) {
+ all_zero = false;
+ break;
+ }
+ }
+ }
+ if (all_zero) {
+ fputs("getrandom returned all zeros, probably broken\n", stderr);
+ exit(1);
+ }
+ }
+
+ return rv;
+}
diff --git a/util.h b/util.h
index 5c4a604..9cd2bd4 100644
--- a/util.h
+++ b/util.h
@@ -17,6 +17,7 @@
#define RAND_POOL_SIZE 512
/* SHA-256 */
#define HASH_LEN 32
+#define HASH_STR_LEN 65
/* The salt is the random data */
#define SALT_LEN RAND_POOL_SIZE
@@ -24,15 +25,7 @@ static inline bool streq(const char *s1, const char *s2) {
return !strcmp(s1, s2);
}
-static inline ssize_t random_get(void *buf, size_t buflen, unsigned int flags) {
- long rv = syscall(SYS_getrandom, buf, buflen, flags);
- if (rv == -1 && errno == ENOSYS) {
- fputs("getrandom returned ENOSYS. random-seed requires Linux 3.17", stderr);
- exit(1);
- }
- return rv;
-}
-
+ssize_t random_get(void *buf, size_t buflen, unsigned int flags);
size_t hex2mem(unsigned char *dest, size_t size, const char *src);
void mem2hex(char *dest, const void *src, size_t size);
void hash(const unsigned char salt[static SALT_LEN], unsigned char *out, const void *in, size_t size);