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