]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/random-seed/random-seed.c
Merge pull request #7388 from keszybz/doc-tweak
[thirdparty/systemd.git] / src / random-seed / random-seed.c
CommitLineData
6e200d55
LP
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
5430f7f2
LP
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
6e200d55
LP
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
5430f7f2 14 Lesser General Public License for more details.
6e200d55 15
5430f7f2 16 You should have received a copy of the GNU Lesser General Public License
6e200d55
LP
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
6e200d55 20#include <errno.h>
07630cea 21#include <fcntl.h>
6e200d55
LP
22#include <string.h>
23#include <sys/stat.h>
07630cea 24#include <unistd.h>
6e200d55 25
b5efdb8a 26#include "alloc-util.h"
3ffd4af2 27#include "fd-util.h"
c004493c 28#include "io-util.h"
6e200d55 29#include "log.h"
49e942b2 30#include "mkdir.h"
07630cea
LP
31#include "string-util.h"
32#include "util.h"
6e200d55 33
26192dfc
LP
34#define POOL_SIZE_MIN 512
35
6e200d55 36int main(int argc, char *argv[]) {
ce179470
LP
37 _cleanup_close_ int seed_fd = -1, random_fd = -1;
38 _cleanup_free_ void* buf = NULL;
26192dfc 39 size_t buf_size = 0;
ce179470 40 ssize_t k;
8edc2d22 41 int r, open_rw_error;
26192dfc 42 FILE *f;
1509fb87 43 bool refresh_seed_file = true;
6e200d55
LP
44
45 if (argc != 2) {
46 log_error("This program requires one argument.");
22f4096c 47 return EXIT_FAILURE;
6e200d55
LP
48 }
49
4cfa2c99 50 log_set_target(LOG_TARGET_AUTO);
6e200d55 51 log_parse_environment();
2396fb04 52 log_open();
6e200d55 53
4c12626c
LP
54 umask(0022);
55
26192dfc 56 /* Read pool size, if possible */
ce179470
LP
57 f = fopen("/proc/sys/kernel/random/poolsize", "re");
58 if (f) {
ece174c5 59 if (fscanf(f, "%zu", &buf_size) > 0)
7c2ec009
TG
60 /* poolsize is in bits on 2.6, but we want bytes */
61 buf_size /= 8;
7c2ec009 62
26192dfc
LP
63 fclose(f);
64 }
65
66 if (buf_size <= POOL_SIZE_MIN)
67 buf_size = POOL_SIZE_MIN;
68
ce179470
LP
69 buf = malloc(buf_size);
70 if (!buf) {
71 r = log_oom();
26192dfc
LP
72 goto finish;
73 }
74
ce179470
LP
75 r = mkdir_parents_label(RANDOM_SEED, 0755);
76 if (r < 0) {
da927ba9 77 log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
b56e5747
GSB
78 goto finish;
79 }
80
6e200d55
LP
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
ce179470 87 seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
8edc2d22 88 open_rw_error = -errno;
ce179470 89 if (seed_fd < 0) {
8edc2d22
ZJS
90 refresh_seed_file = false;
91
ce179470
LP
92 seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
93 if (seed_fd < 0) {
8edc2d22
ZJS
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
6e200d55
LP
103 goto finish;
104 }
105 }
106
ce179470
LP
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) {
1509fb87 111 r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
6e200d55
LP
112 goto finish;
113 }
114 }
115
ce179470 116 k = loop_read(seed_fd, buf, buf_size, false);
1509fb87
LP
117 if (k < 0)
118 r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
8edc2d22
ZJS
119 else if (k == 0) {
120 r = 0;
1509fb87 121 log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding.");
8edc2d22 122 } else {
1509fb87 123 (void) lseek(seed_fd, 0, SEEK_SET);
6e200d55 124
553acb7b
ZJS
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");
6e200d55
LP
128 }
129
130 } else if (streq(argv[1], "save")) {
131
ce179470
LP
132 seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
133 if (seed_fd < 0) {
1509fb87 134 r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
6e200d55
LP
135 goto finish;
136 }
137
ce179470
LP
138 random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
139 if (random_fd < 0) {
1509fb87 140 r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
6e200d55
LP
141 goto finish;
142 }
ce179470 143
6e200d55 144 } else {
1509fb87 145 log_error("Unknown verb '%s'.", argv[1]);
ce179470 146 r = -EINVAL;
6e200d55
LP
147 goto finish;
148 }
149
1509fb87
LP
150 if (refresh_seed_file) {
151
352e2098
CG
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. */
1509fb87
LP
155 (void) fchmod(seed_fd, 0600);
156 (void) fchown(seed_fd, 0, 0);
6e200d55 157
352e2098 158 k = loop_read(random_fd, buf, buf_size, false);
1509fb87
LP
159 if (k < 0) {
160 r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m");
161 goto finish;
352e2098 162 }
1509fb87
LP
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");
6e200d55
LP
172 }
173
6e200d55 174finish:
ce179470 175 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6e200d55 176}