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