]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/random-seed/random-seed.c
util-lib: split out IO related calls to io-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"
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
LP
41 ssize_t k;
42 int r;
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
LP
88 seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
89 if (seed_fd < 0) {
90 seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
91 if (seed_fd < 0) {
1509fb87 92 r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
6e200d55
LP
93 goto finish;
94 }
1509fb87
LP
95
96 refresh_seed_file = false;
6e200d55
LP
97 }
98
ce179470
LP
99 random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
100 if (random_fd < 0) {
101 random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600);
102 if (random_fd < 0) {
1509fb87 103 r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
6e200d55
LP
104 goto finish;
105 }
106 }
107
ce179470 108 k = loop_read(seed_fd, buf, buf_size, false);
1509fb87
LP
109 if (k < 0)
110 r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
111 else if (k == 0)
112 log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding.");
113 else {
114 (void) lseek(seed_fd, 0, SEEK_SET);
6e200d55 115
553acb7b
ZJS
116 r = loop_write(random_fd, buf, (size_t) k, false);
117 if (r < 0)
118 log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
6e200d55
LP
119 }
120
121 } else if (streq(argv[1], "save")) {
122
ce179470
LP
123 seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
124 if (seed_fd < 0) {
1509fb87 125 r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
6e200d55
LP
126 goto finish;
127 }
128
ce179470
LP
129 random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
130 if (random_fd < 0) {
1509fb87 131 r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
6e200d55
LP
132 goto finish;
133 }
ce179470 134
6e200d55 135 } else {
1509fb87 136 log_error("Unknown verb '%s'.", argv[1]);
ce179470 137 r = -EINVAL;
6e200d55
LP
138 goto finish;
139 }
140
1509fb87
LP
141 if (refresh_seed_file) {
142
352e2098
CG
143 /* This is just a safety measure. Given that we are root and
144 * most likely created the file ourselves the mode and owner
145 * should be correct anyway. */
1509fb87
LP
146 (void) fchmod(seed_fd, 0600);
147 (void) fchown(seed_fd, 0, 0);
6e200d55 148
352e2098 149 k = loop_read(random_fd, buf, buf_size, false);
1509fb87
LP
150 if (k < 0) {
151 r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m");
152 goto finish;
352e2098 153 }
1509fb87
LP
154 if (k == 0) {
155 log_error("Got EOF while reading from /dev/urandom.");
156 r = -EIO;
157 goto finish;
158 }
159
160 r = loop_write(seed_fd, buf, (size_t) k, false);
161 if (r < 0)
162 log_error_errno(r, "Failed to write new random seed file: %m");
6e200d55
LP
163 }
164
6e200d55 165finish:
ce179470 166 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6e200d55 167}