]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup-generator.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
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
11 (at your option) any later version.
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
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "fstab-util.h"
27 #include "generator.h"
31 #include "path-util.h"
32 #include "string-util.h"
34 #include "unit-name.h"
37 typedef struct crypto_device
{
45 static const char *arg_dest
= "/tmp";
46 static bool arg_enabled
= true;
47 static bool arg_read_crypttab
= true;
48 static bool arg_whitelist
= false;
49 static Hashmap
*arg_disks
= NULL
;
50 static char *arg_default_options
= NULL
;
51 static char *arg_default_keyfile
= NULL
;
53 static int create_disk(
57 const char *options
) {
59 _cleanup_free_
char *p
= NULL
, *n
= NULL
, *d
= NULL
, *u
= NULL
, *to
= NULL
, *e
= NULL
,
61 _cleanup_fclose_
FILE *f
= NULL
;
62 bool noauto
, nofail
, tmp
, swap
;
69 noauto
= fstab_test_yes_no_option(options
, "noauto\0" "auto\0");
70 nofail
= fstab_test_yes_no_option(options
, "nofail\0" "fail\0");
71 tmp
= fstab_test_option(options
, "tmp\0");
72 swap
= fstab_test_option(options
, "swap\0");
75 log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name
);
79 e
= unit_name_escape(name
);
83 r
= unit_name_build("systemd-cryptsetup", e
, ".service", &n
);
85 return log_error_errno(r
, "Failed to generate unit name: %m");
87 p
= strjoin(arg_dest
, "/", n
, NULL
);
91 u
= fstab_node_to_udev_node(device
);
95 r
= unit_name_from_path(u
, ".device", &d
);
97 return log_error_errno(r
, "Failed to generate unit name: %m");
101 return log_error_errno(errno
, "Failed to create unit file %s: %m", p
);
104 "# Automatically generated by systemd-cryptsetup-generator\n\n"
106 "Description=Cryptography Setup for %I\n"
107 "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
108 "SourcePath=/etc/crypttab\n"
109 "DefaultDependencies=no\n"
110 "Conflicts=umount.target\n"
111 "BindsTo=dev-mapper-%i.device\n"
112 "IgnoreOnIsolate=true\n"
113 "After=cryptsetup-pre.target\n",
118 "Before=cryptsetup.target\n");
121 if (STR_IN_SET(password
, "/dev/urandom", "/dev/random", "/dev/hw_random"))
122 fputs("After=systemd-random-seed.service\n", f
);
123 else if (!streq(password
, "-") && !streq(password
, "none")) {
124 _cleanup_free_
char *uu
;
126 uu
= fstab_node_to_udev_node(password
);
130 if (!path_equal(uu
, "/dev/null")) {
132 if (is_device_path(uu
)) {
133 _cleanup_free_
char *dd
= NULL
;
135 r
= unit_name_from_path(uu
, ".device", &dd
);
137 return log_error_errno(r
, "Failed to generate unit name: %m");
139 fprintf(f
, "After=%1$s\nRequires=%1$s\n", dd
);
141 fprintf(f
, "RequiresMountsFor=%s\n", password
);
146 if (is_device_path(u
))
150 "Before=umount.target\n",
154 "RequiresMountsFor=%s\n",
157 r
= generator_write_timeouts(arg_dest
, device
, name
, options
, &filtered
);
164 "RemainAfterExit=yes\n"
165 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
166 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH
" attach '%s' '%s' '%s' '%s'\n"
167 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH
" detach '%s'\n",
168 name
, u
, strempty(password
), strempty(filtered
),
173 "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
178 "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
181 r
= fflush_and_check(f
);
183 return log_error_errno(r
, "Failed to write file %s: %m", p
);
185 from
= strjoina("../", n
);
189 to
= strjoin(arg_dest
, "/", d
, ".wants/", n
, NULL
);
193 mkdir_parents_label(to
, 0755);
194 if (symlink(from
, to
) < 0)
195 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
199 to
= strjoin(arg_dest
, "/cryptsetup.target.requires/", n
, NULL
);
201 to
= strjoin(arg_dest
, "/cryptsetup.target.wants/", n
, NULL
);
205 mkdir_parents_label(to
, 0755);
206 if (symlink(from
, to
) < 0)
207 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
211 to
= strjoin(arg_dest
, "/dev-mapper-", e
, ".device.requires/", n
, NULL
);
215 mkdir_parents_label(to
, 0755);
216 if (symlink(from
, to
) < 0)
217 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
219 if (!noauto
&& !nofail
) {
220 _cleanup_free_
char *dmname
;
221 dmname
= strjoin("dev-mapper-", e
, ".device", NULL
);
225 r
= write_drop_in(arg_dest
, dmname
, 90, "device-timeout",
226 "# Automatically generated by systemd-cryptsetup-generator \n\n"
227 "[Unit]\nJobTimeoutSec=0");
229 return log_error_errno(r
, "Failed to write device drop-in: %m");
235 static void free_arg_disks(void) {
238 while ((d
= hashmap_steal_first(arg_disks
))) {
246 hashmap_free(arg_disks
);
249 static crypto_device
*get_crypto_device(const char *uuid
) {
255 d
= hashmap_get(arg_disks
, uuid
);
257 d
= new0(struct crypto_device
, 1);
262 d
->keyfile
= d
->options
= d
->name
= NULL
;
264 d
->uuid
= strdup(uuid
);
270 r
= hashmap_put(arg_disks
, d
->uuid
, d
);
281 static int parse_proc_cmdline_item(const char *key
, const char *value
) {
284 _cleanup_free_
char *uuid
= NULL
, *uuid_value
= NULL
;
286 if (STR_IN_SET(key
, "luks", "rd.luks") && value
) {
288 r
= parse_boolean(value
);
290 log_warning("Failed to parse luks switch %s. Ignoring.", value
);
294 } else if (STR_IN_SET(key
, "luks.crypttab", "rd.luks.crypttab") && value
) {
296 r
= parse_boolean(value
);
298 log_warning("Failed to parse luks crypttab switch %s. Ignoring.", value
);
300 arg_read_crypttab
= r
;
302 } else if (STR_IN_SET(key
, "luks.uuid", "rd.luks.uuid") && value
) {
304 d
= get_crypto_device(startswith(value
, "luks-") ? value
+5 : value
);
308 d
->create
= arg_whitelist
= true;
310 } else if (STR_IN_SET(key
, "luks.options", "rd.luks.options") && value
) {
312 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
314 d
= get_crypto_device(uuid
);
319 d
->options
= uuid_value
;
321 } else if (free_and_strdup(&arg_default_options
, value
) < 0)
324 } else if (STR_IN_SET(key
, "luks.key", "rd.luks.key") && value
) {
326 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
328 d
= get_crypto_device(uuid
);
333 d
->keyfile
= uuid_value
;
335 } else if (free_and_strdup(&arg_default_keyfile
, value
) < 0)
338 } else if (STR_IN_SET(key
, "luks.name", "rd.luks.name") && value
) {
340 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
342 d
= get_crypto_device(uuid
);
346 d
->create
= arg_whitelist
= true;
349 d
->name
= uuid_value
;
352 log_warning("Failed to parse luks name switch %s. Ignoring.", value
);
359 static int add_crypttab_devices(void) {
361 unsigned crypttab_line
= 0;
362 _cleanup_fclose_
FILE *f
= NULL
;
364 if (!arg_read_crypttab
)
367 f
= fopen("/etc/crypttab", "re");
370 log_error_errno(errno
, "Failed to open /etc/crypttab: %m");
374 if (fstat(fileno(f
), &st
) < 0) {
375 log_error_errno(errno
, "Failed to stat /etc/crypttab: %m");
381 char line
[LINE_MAX
], *l
, *uuid
;
382 crypto_device
*d
= NULL
;
383 _cleanup_free_
char *name
= NULL
, *device
= NULL
, *keyfile
= NULL
, *options
= NULL
;
385 if (!fgets(line
, sizeof(line
), f
))
391 if (*l
== '#' || *l
== 0)
394 k
= sscanf(l
, "%ms %ms %ms %ms", &name
, &device
, &keyfile
, &options
);
395 if (k
< 2 || k
> 4) {
396 log_error("Failed to parse /etc/crypttab:%u, ignoring.", crypttab_line
);
400 uuid
= startswith(device
, "UUID=");
402 uuid
= path_startswith(device
, "/dev/disk/by-uuid/");
404 uuid
= startswith(name
, "luks-");
406 d
= hashmap_get(arg_disks
, uuid
);
408 if (arg_whitelist
&& !d
) {
409 log_info("Not creating device '%s' because it was not specified on the kernel command line.", name
);
413 r
= create_disk(name
, device
, keyfile
, (d
&& d
->options
) ? d
->options
: options
);
424 static int add_proc_cmdline_devices(void) {
429 HASHMAP_FOREACH(d
, arg_disks
, i
) {
431 _cleanup_free_
char *device
= NULL
;
437 d
->name
= strappend("luks-", d
->uuid
);
442 device
= strappend("UUID=", d
->uuid
);
447 options
= d
->options
;
448 else if (arg_default_options
)
449 options
= arg_default_options
;
451 options
= "timeout=0";
453 r
= create_disk(d
->name
, device
, d
->keyfile
?: arg_default_keyfile
, options
);
461 int main(int argc
, char *argv
[]) {
462 int r
= EXIT_FAILURE
;
464 if (argc
> 1 && argc
!= 4) {
465 log_error("This program takes three or no arguments.");
472 log_set_target(LOG_TARGET_SAFE
);
473 log_parse_environment();
478 arg_disks
= hashmap_new(&string_hash_ops
);
482 r
= parse_proc_cmdline(parse_proc_cmdline_item
);
484 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
493 if (add_crypttab_devices() < 0)
496 if (add_proc_cmdline_devices() < 0)
503 free(arg_default_options
);
504 free(arg_default_keyfile
);