]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/random-seed/random-seed.c
util-lib: split out fd-related operations into fd-util.[ch]
[thirdparty/systemd.git] / src / random-seed / random-seed.c
CommitLineData
6e200d55
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
6e200d55
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
6e200d55 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
6e200d55
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
6e200d55 22#include <errno.h>
07630cea 23#include <fcntl.h>
6e200d55
LP
24#include <string.h>
25#include <sys/stat.h>
07630cea 26#include <unistd.h>
6e200d55 27
3ffd4af2 28#include "fd-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
LP
40 ssize_t k;
41 int r;
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
LP
87 seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
88 if (seed_fd < 0) {
89 seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
90 if (seed_fd < 0) {
1509fb87 91 r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
6e200d55
LP
92 goto finish;
93 }
1509fb87
LP
94
95 refresh_seed_file = false;
6e200d55
LP
96 }
97
ce179470
LP
98 random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
99 if (random_fd < 0) {
100 random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600);
101 if (random_fd < 0) {
1509fb87 102 r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
6e200d55
LP
103 goto finish;
104 }
105 }
106
ce179470 107 k = loop_read(seed_fd, buf, buf_size, false);
1509fb87
LP
108 if (k < 0)
109 r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
110 else if (k == 0)
111 log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding.");
112 else {
113 (void) lseek(seed_fd, 0, SEEK_SET);
6e200d55 114
553acb7b
ZJS
115 r = loop_write(random_fd, buf, (size_t) k, false);
116 if (r < 0)
117 log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
6e200d55
LP
118 }
119
120 } else if (streq(argv[1], "save")) {
121
ce179470
LP
122 seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
123 if (seed_fd < 0) {
1509fb87 124 r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
6e200d55
LP
125 goto finish;
126 }
127
ce179470
LP
128 random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
129 if (random_fd < 0) {
1509fb87 130 r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
6e200d55
LP
131 goto finish;
132 }
ce179470 133
6e200d55 134 } else {
1509fb87 135 log_error("Unknown verb '%s'.", argv[1]);
ce179470 136 r = -EINVAL;
6e200d55
LP
137 goto finish;
138 }
139
1509fb87
LP
140 if (refresh_seed_file) {
141
352e2098
CG
142 /* This is just a safety measure. Given that we are root and
143 * most likely created the file ourselves the mode and owner
144 * should be correct anyway. */
1509fb87
LP
145 (void) fchmod(seed_fd, 0600);
146 (void) fchown(seed_fd, 0, 0);
6e200d55 147
352e2098 148 k = loop_read(random_fd, buf, buf_size, false);
1509fb87
LP
149 if (k < 0) {
150 r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m");
151 goto finish;
352e2098 152 }
1509fb87
LP
153 if (k == 0) {
154 log_error("Got EOF while reading from /dev/urandom.");
155 r = -EIO;
156 goto finish;
157 }
158
159 r = loop_write(seed_fd, buf, (size_t) k, false);
160 if (r < 0)
161 log_error_errno(r, "Failed to write new random seed file: %m");
6e200d55
LP
162 }
163
6e200d55 164finish:
ce179470 165 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6e200d55 166}