]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/random-seed/random-seed.c
util-lib: split our string related calls from util.[ch] into its own file string...
[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
LP
27
28#include "log.h"
49e942b2 29#include "mkdir.h"
07630cea
LP
30#include "string-util.h"
31#include "util.h"
6e200d55 32
26192dfc
LP
33#define POOL_SIZE_MIN 512
34
6e200d55 35int main(int argc, char *argv[]) {
ce179470
LP
36 _cleanup_close_ int seed_fd = -1, random_fd = -1;
37 _cleanup_free_ void* buf = NULL;
26192dfc 38 size_t buf_size = 0;
ce179470
LP
39 ssize_t k;
40 int r;
26192dfc 41 FILE *f;
1509fb87 42 bool refresh_seed_file = true;
6e200d55
LP
43
44 if (argc != 2) {
45 log_error("This program requires one argument.");
22f4096c 46 return EXIT_FAILURE;
6e200d55
LP
47 }
48
4cfa2c99 49 log_set_target(LOG_TARGET_AUTO);
6e200d55 50 log_parse_environment();
2396fb04 51 log_open();
6e200d55 52
4c12626c
LP
53 umask(0022);
54
26192dfc 55 /* Read pool size, if possible */
ce179470
LP
56 f = fopen("/proc/sys/kernel/random/poolsize", "re");
57 if (f) {
ece174c5 58 if (fscanf(f, "%zu", &buf_size) > 0)
7c2ec009
TG
59 /* poolsize is in bits on 2.6, but we want bytes */
60 buf_size /= 8;
7c2ec009 61
26192dfc
LP
62 fclose(f);
63 }
64
65 if (buf_size <= POOL_SIZE_MIN)
66 buf_size = POOL_SIZE_MIN;
67
ce179470
LP
68 buf = malloc(buf_size);
69 if (!buf) {
70 r = log_oom();
26192dfc
LP
71 goto finish;
72 }
73
ce179470
LP
74 r = mkdir_parents_label(RANDOM_SEED, 0755);
75 if (r < 0) {
da927ba9 76 log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
b56e5747
GSB
77 goto finish;
78 }
79
6e200d55
LP
80 /* When we load the seed we read it and write it to the device
81 * and then immediately update the saved seed with new data,
82 * to make sure the next boot gets seeded differently. */
83
84 if (streq(argv[1], "load")) {
85
ce179470
LP
86 seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
87 if (seed_fd < 0) {
88 seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
89 if (seed_fd < 0) {
1509fb87 90 r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
6e200d55
LP
91 goto finish;
92 }
1509fb87
LP
93
94 refresh_seed_file = false;
6e200d55
LP
95 }
96
ce179470
LP
97 random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
98 if (random_fd < 0) {
99 random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600);
100 if (random_fd < 0) {
1509fb87 101 r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
6e200d55
LP
102 goto finish;
103 }
104 }
105
ce179470 106 k = loop_read(seed_fd, buf, buf_size, false);
1509fb87
LP
107 if (k < 0)
108 r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
109 else if (k == 0)
110 log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding.");
111 else {
112 (void) lseek(seed_fd, 0, SEEK_SET);
6e200d55 113
553acb7b
ZJS
114 r = loop_write(random_fd, buf, (size_t) k, false);
115 if (r < 0)
116 log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
6e200d55
LP
117 }
118
119 } else if (streq(argv[1], "save")) {
120
ce179470
LP
121 seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
122 if (seed_fd < 0) {
1509fb87 123 r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
6e200d55
LP
124 goto finish;
125 }
126
ce179470
LP
127 random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
128 if (random_fd < 0) {
1509fb87 129 r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
6e200d55
LP
130 goto finish;
131 }
ce179470 132
6e200d55 133 } else {
1509fb87 134 log_error("Unknown verb '%s'.", argv[1]);
ce179470 135 r = -EINVAL;
6e200d55
LP
136 goto finish;
137 }
138
1509fb87
LP
139 if (refresh_seed_file) {
140
352e2098
CG
141 /* This is just a safety measure. Given that we are root and
142 * most likely created the file ourselves the mode and owner
143 * should be correct anyway. */
1509fb87
LP
144 (void) fchmod(seed_fd, 0600);
145 (void) fchown(seed_fd, 0, 0);
6e200d55 146
352e2098 147 k = loop_read(random_fd, buf, buf_size, false);
1509fb87
LP
148 if (k < 0) {
149 r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m");
150 goto finish;
352e2098 151 }
1509fb87
LP
152 if (k == 0) {
153 log_error("Got EOF while reading from /dev/urandom.");
154 r = -EIO;
155 goto finish;
156 }
157
158 r = loop_write(seed_fd, buf, (size_t) k, false);
159 if (r < 0)
160 log_error_errno(r, "Failed to write new random seed file: %m");
6e200d55
LP
161 }
162
6e200d55 163finish:
ce179470 164 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6e200d55 165}