]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cryptsetup/cryptsetup-generator.c
tmpfiles: write /run/nologin during early boot to disallow too early user logins
[thirdparty/systemd.git] / src / cryptsetup / cryptsetup-generator.c
CommitLineData
e23a0ce8
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
e23a0ce8
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.
e23a0ce8 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
e23a0ce8
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
25
26#include "log.h"
27#include "util.h"
28#include "unit-name.h"
49e942b2 29#include "mkdir.h"
66a78c2b
LP
30#include "virt.h"
31#include "strv.h"
e23a0ce8 32
66a78c2b
LP
33static const char *arg_dest = "/tmp";
34static bool arg_enabled = true;
35static bool arg_read_crypttab = true;
36static char **arg_proc_cmdline_disks = NULL;
e23a0ce8
LP
37
38static bool has_option(const char *haystack, const char *needle) {
39 const char *f = haystack;
40 size_t l;
41
f653f683
LP
42 assert(needle);
43
44 if (!haystack)
45 return false;
46
e23a0ce8
LP
47 l = strlen(needle);
48
49 while ((f = strstr(f, needle))) {
50
51 if (f > haystack && f[-1] != ',') {
52 f++;
53 continue;
54 }
55
aae5220d 56 if (f[l] != 0 && f[l] != ',') {
e23a0ce8
LP
57 f++;
58 continue;
59 }
60
61 return true;
62 }
63
64 return false;
65}
66
67static int create_disk(
68 const char *name,
69 const char *device,
70 const char *password,
71 const char *options) {
72
74715b82 73 char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL, *e = NULL;
e23a0ce8
LP
74 int r;
75 FILE *f = NULL;
155da457 76 bool noauto, nofail;
e23a0ce8
LP
77
78 assert(name);
79 assert(device);
80
155da457
LP
81 noauto = has_option(options, "noauto");
82 nofail = has_option(options, "nofail");
83
6d37ea8a 84 n = unit_name_build_escape("systemd-cryptsetup", name, ".service");
f7f21d33 85 if (!n) {
e23a0ce8
LP
86 r = -ENOMEM;
87 log_error("Failed to allocate unit name.");
88 goto fail;
89 }
90
f7f21d33
LP
91 p = join(arg_dest, "/", n, NULL);
92 if (!p) {
e23a0ce8
LP
93 r = -ENOMEM;
94 log_error("Failed to allocate unit file name.");
95 goto fail;
96 }
97
f7f21d33
LP
98 u = fstab_node_to_udev_node(device);
99 if (!u) {
e23a0ce8
LP
100 r = -ENOMEM;
101 log_error("Failed to allocate device node.");
102 goto fail;
103 }
104
f7f21d33
LP
105 d = unit_name_from_path(u, ".device");
106 if (!d) {
e23a0ce8
LP
107 r = -ENOMEM;
108 log_error("Failed to allocate device name.");
109 goto fail;
110 }
111
f7f21d33
LP
112 f = fopen(p, "wxe");
113 if (!f) {
e23a0ce8
LP
114 r = -errno;
115 log_error("Failed to create unit file: %m");
116 goto fail;
117 }
118
119 fprintf(f,
6b1dc2bd 120 "# Automatically generated by systemd-cryptsetup-generator\n\n"
e23a0ce8 121 "[Unit]\n"
a4477e68 122 "Description=Cryptography Setup for %%I\n"
1b64d026 123 "SourcePath=/etc/crypttab\n"
155da457 124 "Conflicts=umount.target\n"
e23a0ce8 125 "DefaultDependencies=no\n"
49d50c55 126 "BindTo=%s dev-mapper-%%i.device\n"
e23a0ce8 127 "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n"
87e75fdd 128 "Before=umount.target\n",
e23a0ce8
LP
129 d, d);
130
155da457
LP
131 if (!nofail)
132 fprintf(f,
133 "Before=cryptsetup.target\n");
134
e23a0ce8
LP
135 if (password && (streq(password, "/dev/urandom") ||
136 streq(password, "/dev/random") ||
137 streq(password, "/dev/hw_random")))
1b64d026 138 fputs("After=systemd-random-seed-load.service\n", f);
87e75fdd 139 else
1b64d026 140 fputs("Before=local-fs.target\n", f);
e23a0ce8
LP
141
142 fprintf(f,
143 "\n[Service]\n"
144 "Type=oneshot\n"
145 "RemainAfterExit=yes\n"
90724929 146 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
260ab287 147 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
7f4e0805 148 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
e23a0ce8
LP
149 name, u, strempty(password), strempty(options),
150 name);
151
f653f683 152 if (has_option(options, "tmp"))
e23a0ce8 153 fprintf(f,
50109038 154 "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
1d3399e6 155 name);
e23a0ce8 156
f653f683 157 if (has_option(options, "swap"))
e23a0ce8 158 fprintf(f,
50109038 159 "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
1d3399e6 160 name);
e23a0ce8
LP
161
162 fflush(f);
163
164 if (ferror(f)) {
165 r = -errno;
166 log_error("Failed to write file: %m");
167 goto fail;
168 }
169
74715b82
LP
170 if (asprintf(&from, "../%s", n) < 0) {
171 r = -ENOMEM;
172 goto fail;
173 }
174
155da457 175 if (!noauto) {
e23a0ce8 176
f7f21d33
LP
177 to = join(arg_dest, "/", d, ".wants/", n, NULL);
178 if (!to) {
e23a0ce8
LP
179 r = -ENOMEM;
180 goto fail;
181 }
182
d2e54fae 183 mkdir_parents_label(to, 0755);
e23a0ce8
LP
184 if (symlink(from, to) < 0) {
185 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
186 r = -errno;
187 goto fail;
188 }
2f8cd170
LP
189
190 free(to);
2f8cd170 191
155da457 192 if (!nofail)
f7f21d33 193 to = join(arg_dest, "/cryptsetup.target.requires/", n, NULL);
155da457 194 else
f7f21d33 195 to = join(arg_dest, "/cryptsetup.target.wants/", n, NULL);
155da457
LP
196 if (!to) {
197 r = -ENOMEM;
198 goto fail;
199 }
2f8cd170 200
d2e54fae 201 mkdir_parents_label(to, 0755);
155da457
LP
202 if (symlink(from, to) < 0) {
203 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
204 r = -errno;
205 goto fail;
2f8cd170 206 }
e23a0ce8 207
f7f21d33
LP
208 free(to);
209 to = NULL;
210 }
74715b82
LP
211
212 e = unit_name_escape(name);
f7f21d33
LP
213 to = join(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
214 if (!to) {
74715b82
LP
215 r = -ENOMEM;
216 goto fail;
217 }
218
d2e54fae 219 mkdir_parents_label(to, 0755);
74715b82
LP
220 if (symlink(from, to) < 0) {
221 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
222 r = -errno;
223 goto fail;
224 }
225
e23a0ce8
LP
226 r = 0;
227
228fail:
229 free(p);
230 free(n);
231 free(d);
74715b82 232 free(e);
e23a0ce8
LP
233
234 free(from);
235 free(to);
236
237 if (f)
238 fclose(f);
239
240 return r;
241}
242
66a78c2b
LP
243static int parse_proc_cmdline(void) {
244 char *line, *w, *state;
245 int r;
246 size_t l;
247
248 if (detect_container(NULL) > 0)
249 return 0;
250
251 r = read_one_line_file("/proc/cmdline", &line);
252 if (r < 0) {
253 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
254 return 0;
255 }
256
257 FOREACH_WORD_QUOTED(w, l, line, state) {
258 char *word;
259
260 word = strndup(w, l);
261 if (!word) {
262 r = -ENOMEM;
263 goto finish;
264 }
265
266 if (startswith(word, "luks=")) {
267 r = parse_boolean(word + 5);
268 if (r < 0)
269 log_warning("Failed to parse luks switch %s. Ignoring.", word + 5);
270 else
271 arg_enabled = r;
272
273 } else if (startswith(word, "rd.luks=")) {
274
275 if (in_initrd()) {
276 r = parse_boolean(word + 8);
277 if (r < 0)
278 log_warning("Failed to parse luks switch %s. Ignoring.", word + 8);
279 else
280 arg_enabled = r;
281 }
282
283 } else if (startswith(word, "luks.crypttab=")) {
284 r = parse_boolean(word + 14);
285 if (r < 0)
286 log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 14);
287 else
288 arg_read_crypttab = r;
289
290 } else if (startswith(word, "rd.luks.crypttab=")) {
291
292 if (in_initrd()) {
293 r = parse_boolean(word + 17);
294 if (r < 0)
295 log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 17);
296 else
297 arg_read_crypttab = r;
298 }
299
300 } else if (startswith(word, "luks.uuid=")) {
301 char **t;
302
303 t = strv_append(arg_proc_cmdline_disks, word + 10);
304 if (!t) {
305 log_error("Out of memory");
306 r = -ENOMEM;
307 goto finish;
308 }
309 strv_free(arg_proc_cmdline_disks);
310 arg_proc_cmdline_disks = t;
311
312 } else if (startswith(word, "rd.luks.uuid=")) {
313
314 if (in_initrd()) {
315 char **t;
316
317 t = strv_append(arg_proc_cmdline_disks, word + 13);
318 if (!t) {
319 log_error("Out of memory");
320 r = -ENOMEM;
321 goto finish;
322 }
323 strv_free(arg_proc_cmdline_disks);
324 arg_proc_cmdline_disks = t;
325 }
326
327 } else if (startswith(word, "luks.") ||
328 (in_initrd() && startswith(word, "rd.luks."))) {
329
330 log_warning("Unknown kernel switch %s. Ignoring.", word);
331 }
332
333 free(word);
334 }
335
336 r = 0;
337
338finish:
339 free(line);
340 return r;
341}
342
e23a0ce8 343int main(int argc, char *argv[]) {
66a78c2b 344 FILE *f = NULL;
e23a0ce8
LP
345 int r = EXIT_SUCCESS;
346 unsigned n = 0;
66a78c2b 347 char **i;
e23a0ce8 348
07719a21
LP
349 if (argc > 1 && argc != 4) {
350 log_error("This program takes three or no arguments.");
e23a0ce8
LP
351 return EXIT_FAILURE;
352 }
353
2a796654
LP
354 if (argc > 1)
355 arg_dest = argv[1];
e23a0ce8 356
a6903061 357 log_set_target(LOG_TARGET_SAFE);
e23a0ce8
LP
358 log_parse_environment();
359 log_open();
360
4c12626c
LP
361 umask(0022);
362
66a78c2b
LP
363 if (parse_proc_cmdline() < 0)
364 return EXIT_FAILURE;
365
366 if (!arg_enabled) {
367 r = EXIT_SUCCESS;
368 goto finish;
369 }
370
371 STRV_FOREACH(i, arg_proc_cmdline_disks) {
372 char *name, *device;
373 const char *p = *i;
374
375 if (startswith(p, "luks-"))
376 p += 5;
377
378 name = strappend("luks-", *i);
379 device = strappend("UUID=", *i);
380
381 if (!name || !device) {
382 log_error("Out of memory");
383 r = EXIT_FAILURE;
384 free(name);
385 free(device);
386 goto finish;
387 }
388
389 if (create_disk(name, device, NULL, NULL) < 0)
390 r = EXIT_FAILURE;
391
392 free(name);
393 free(device);
394 }
395
396 if (!arg_read_crypttab)
397 return r;
398
f7f21d33
LP
399 f = fopen("/etc/crypttab", "re");
400 if (!f) {
e23a0ce8
LP
401
402 if (errno == ENOENT)
403 r = EXIT_SUCCESS;
404 else {
405 r = EXIT_FAILURE;
406 log_error("Failed to open /etc/crypttab: %m");
407 }
408
409 goto finish;
410 }
411
412 for (;;) {
413 char line[LINE_MAX], *l;
414 char *name = NULL, *device = NULL, *password = NULL, *options = NULL;
415 int k;
416
f7f21d33 417 if (!fgets(line, sizeof(line), f))
e23a0ce8
LP
418 break;
419
420 n++;
421
422 l = strstrip(line);
423 if (*l == '#' || *l == 0)
424 continue;
425
f7f21d33
LP
426 k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options);
427 if (k < 2 || k > 4) {
e23a0ce8
LP
428 log_error("Failed to parse /etc/crypttab:%u, ignoring.", n);
429 r = EXIT_FAILURE;
430 goto next;
431 }
432
433 if (create_disk(name, device, password, options) < 0)
434 r = EXIT_FAILURE;
435
436 next:
437 free(name);
438 free(device);
439 free(password);
440 free(options);
441 }
442
443finish:
66a78c2b
LP
444 if (f)
445 fclose(f);
446
447 strv_free(arg_proc_cmdline_disks);
448
e23a0ce8
LP
449 return r;
450}