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