]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/random-seed/random-seed.c
tree-wide: remove Lennart's copyright lines
[thirdparty/systemd.git] / src / random-seed / random-seed.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
6e200d55 2
6e200d55 3#include <errno.h>
07630cea 4#include <fcntl.h>
6e200d55
LP
5#include <string.h>
6#include <sys/stat.h>
07630cea 7#include <unistd.h>
6e200d55 8
b5efdb8a 9#include "alloc-util.h"
3ffd4af2 10#include "fd-util.h"
c004493c 11#include "io-util.h"
6e200d55 12#include "log.h"
49e942b2 13#include "mkdir.h"
07630cea
LP
14#include "string-util.h"
15#include "util.h"
6e200d55 16
26192dfc
LP
17#define POOL_SIZE_MIN 512
18
6e200d55 19int main(int argc, char *argv[]) {
ce179470
LP
20 _cleanup_close_ int seed_fd = -1, random_fd = -1;
21 _cleanup_free_ void* buf = NULL;
26192dfc 22 size_t buf_size = 0;
ce179470 23 ssize_t k;
8edc2d22 24 int r, open_rw_error;
26192dfc 25 FILE *f;
1509fb87 26 bool refresh_seed_file = true;
6e200d55
LP
27
28 if (argc != 2) {
29 log_error("This program requires one argument.");
22f4096c 30 return EXIT_FAILURE;
6e200d55
LP
31 }
32
4cfa2c99 33 log_set_target(LOG_TARGET_AUTO);
6e200d55 34 log_parse_environment();
2396fb04 35 log_open();
6e200d55 36
4c12626c
LP
37 umask(0022);
38
26192dfc 39 /* Read pool size, if possible */
ce179470
LP
40 f = fopen("/proc/sys/kernel/random/poolsize", "re");
41 if (f) {
ece174c5 42 if (fscanf(f, "%zu", &buf_size) > 0)
7c2ec009
TG
43 /* poolsize is in bits on 2.6, but we want bytes */
44 buf_size /= 8;
7c2ec009 45
26192dfc
LP
46 fclose(f);
47 }
48
49 if (buf_size <= POOL_SIZE_MIN)
50 buf_size = POOL_SIZE_MIN;
51
ce179470
LP
52 buf = malloc(buf_size);
53 if (!buf) {
54 r = log_oom();
26192dfc
LP
55 goto finish;
56 }
57
ce179470
LP
58 r = mkdir_parents_label(RANDOM_SEED, 0755);
59 if (r < 0) {
da927ba9 60 log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
b56e5747
GSB
61 goto finish;
62 }
63
6e200d55
LP
64 /* When we load the seed we read it and write it to the device
65 * and then immediately update the saved seed with new data,
66 * to make sure the next boot gets seeded differently. */
67
68 if (streq(argv[1], "load")) {
69
ce179470 70 seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
8edc2d22 71 open_rw_error = -errno;
ce179470 72 if (seed_fd < 0) {
8edc2d22
ZJS
73 refresh_seed_file = false;
74
ce179470
LP
75 seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
76 if (seed_fd < 0) {
8edc2d22
ZJS
77 bool missing = errno == ENOENT;
78
79 log_full_errno(missing ? LOG_DEBUG : LOG_ERR,
80 open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m");
81 r = log_full_errno(missing ? LOG_DEBUG : LOG_ERR,
82 errno, "Failed to open " RANDOM_SEED " for reading: %m");
83 if (missing)
84 r = 0;
85
6e200d55
LP
86 goto finish;
87 }
88 }
89
ce179470
LP
90 random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
91 if (random_fd < 0) {
92 random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600);
93 if (random_fd < 0) {
1509fb87 94 r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
6e200d55
LP
95 goto finish;
96 }
97 }
98
ce179470 99 k = loop_read(seed_fd, buf, buf_size, false);
1509fb87
LP
100 if (k < 0)
101 r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
8edc2d22
ZJS
102 else if (k == 0) {
103 r = 0;
1509fb87 104 log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding.");
8edc2d22 105 } else {
1509fb87 106 (void) lseek(seed_fd, 0, SEEK_SET);
6e200d55 107
553acb7b
ZJS
108 r = loop_write(random_fd, buf, (size_t) k, false);
109 if (r < 0)
110 log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
6e200d55
LP
111 }
112
113 } else if (streq(argv[1], "save")) {
114
ce179470
LP
115 seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
116 if (seed_fd < 0) {
1509fb87 117 r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
6e200d55
LP
118 goto finish;
119 }
120
ce179470
LP
121 random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
122 if (random_fd < 0) {
1509fb87 123 r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
6e200d55
LP
124 goto finish;
125 }
ce179470 126
6e200d55 127 } else {
1509fb87 128 log_error("Unknown verb '%s'.", argv[1]);
ce179470 129 r = -EINVAL;
6e200d55
LP
130 goto finish;
131 }
132
1509fb87
LP
133 if (refresh_seed_file) {
134
352e2098
CG
135 /* This is just a safety measure. Given that we are root and
136 * most likely created the file ourselves the mode and owner
137 * should be correct anyway. */
1509fb87
LP
138 (void) fchmod(seed_fd, 0600);
139 (void) fchown(seed_fd, 0, 0);
6e200d55 140
352e2098 141 k = loop_read(random_fd, buf, buf_size, false);
1509fb87
LP
142 if (k < 0) {
143 r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m");
144 goto finish;
352e2098 145 }
1509fb87
LP
146 if (k == 0) {
147 log_error("Got EOF while reading from /dev/urandom.");
148 r = -EIO;
149 goto finish;
150 }
151
152 r = loop_write(seed_fd, buf, (size_t) k, false);
153 if (r < 0)
154 log_error_errno(r, "Failed to write new random seed file: %m");
6e200d55
LP
155 }
156
6e200d55 157finish:
ce179470 158 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6e200d55 159}