1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "alloc-util.h"
13 #include "fstab-util.h"
14 #include "generator.h"
16 #include "id128-util.h"
19 #include "parse-util.h"
20 #include "path-util.h"
21 #include "proc-cmdline.h"
22 #include "specifier.h"
23 #include "string-util.h"
25 #include "unit-name.h"
28 typedef struct crypto_device
{
37 static const char *arg_dest
= NULL
;
38 static bool arg_enabled
= true;
39 static bool arg_read_crypttab
= true;
40 static bool arg_whitelist
= false;
41 static Hashmap
*arg_disks
= NULL
;
42 static char *arg_default_options
= NULL
;
43 static char *arg_default_keyfile
= NULL
;
45 STATIC_DESTRUCTOR_REGISTER(arg_disks
, hashmap_freep
);
46 STATIC_DESTRUCTOR_REGISTER(arg_default_options
, freep
);
47 STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile
, freep
);
49 static int split_keyspec(const char *keyspec
, char **keyfile
, char **keydev
) {
50 _cleanup_free_
char *kfile
= NULL
, *kdev
= NULL
;
57 c
= strrchr(keyspec
, ':');
59 kfile
= strndup(keyspec
, c
-keyspec
);
61 if (!*kfile
|| !*kdev
)
64 /* No keydev specified */
65 kfile
= strdup(keyspec
);
71 *keyfile
= TAKE_PTR(kfile
);
72 *keydev
= TAKE_PTR(kdev
);
77 static int generate_keydev_mount(const char *name
, const char *keydev
, const char *keydev_timeout
, bool canfail
, char **unit
, char **mount
) {
78 _cleanup_free_
char *u
= NULL
, *what
= NULL
, *where
= NULL
, *name_escaped
= NULL
, *device_unit
= NULL
;
79 _cleanup_fclose_
FILE *f
= NULL
;
88 r
= mkdir_parents("/run/systemd/cryptsetup", 0755);
92 r
= mkdir("/run/systemd/cryptsetup", 0700);
93 if (r
< 0 && errno
!= EEXIST
)
96 name_escaped
= cescape(name
);
100 where
= strjoin("/run/systemd/cryptsetup/keydev-", name_escaped
);
104 r
= mkdir(where
, 0700);
105 if (r
< 0 && errno
!= EEXIST
)
108 r
= unit_name_from_path(where
, ".mount", &u
);
112 r
= generator_open_unit_file(arg_dest
, NULL
, u
, &f
);
116 what
= fstab_node_to_udev_node(keydev
);
122 "DefaultDependencies=no\n\n"
126 "Options=ro%s\n", what
, where
, canfail
? ",nofail" : "");
128 if (keydev_timeout
) {
129 r
= parse_sec_fix_0(keydev_timeout
, &timeout_us
);
131 r
= unit_name_from_path(what
, ".device", &device_unit
);
133 return log_error_errno(r
, "Failed to generate unit name: %m");
135 r
= write_drop_in_format(arg_dest
, device_unit
, 90, "device-timeout",
136 "# Automatically generated by systemd-cryptsetup-generator \n\n"
137 "[Unit]\nJobRunningTimeoutSec=%s", keydev_timeout
);
139 return log_error_errno(r
, "Failed to write device drop-in: %m");
142 log_warning_errno(r
, "Failed to parse %s, ignoring: %m", keydev_timeout
);
146 r
= fflush_and_check(f
);
151 *mount
= TAKE_PTR(where
);
156 static int print_dependencies(FILE *f
, const char* device_path
) {
159 if (STR_IN_SET(device_path
, "-", "none"))
160 /* None, nothing to do */
163 if (PATH_IN_SET(device_path
, "/dev/urandom", "/dev/random", "/dev/hw_random")) {
164 /* RNG device, add random dep */
165 fputs("After=systemd-random-seed.service\n", f
);
169 _cleanup_free_
char *udev_node
= fstab_node_to_udev_node(device_path
);
173 if (path_equal(udev_node
, "/dev/null"))
176 if (path_startswith(udev_node
, "/dev/")) {
177 /* We are dealing with a block device, add dependency for correspoding unit */
178 _cleanup_free_
char *unit
= NULL
;
180 r
= unit_name_from_path(udev_node
, ".device", &unit
);
182 return log_error_errno(r
, "Failed to generate unit name: %m");
184 fprintf(f
, "After=%1$s\nRequires=%1$s\n", unit
);
186 /* Regular file, add mount dependency */
187 _cleanup_free_
char *escaped_path
= specifier_escape(device_path
);
191 fprintf(f
, "RequiresMountsFor=%s\n", escaped_path
);
197 static int create_disk(
200 const char *password
,
202 const char *options
) {
204 _cleanup_free_
char *n
= NULL
, *d
= NULL
, *u
= NULL
, *e
= NULL
,
205 *keydev_mount
= NULL
, *keyfile_timeout_value
= NULL
, *password_escaped
= NULL
,
206 *filtered
= NULL
, *u_escaped
= NULL
, *filtered_escaped
= NULL
, *name_escaped
= NULL
, *header_path
= NULL
;
207 _cleanup_fclose_
FILE *f
= NULL
;
209 bool noauto
, nofail
, tmp
, swap
, netdev
;
210 int r
, detached_header
, keyfile_can_timeout
;
215 noauto
= fstab_test_yes_no_option(options
, "noauto\0" "auto\0");
216 nofail
= fstab_test_yes_no_option(options
, "nofail\0" "fail\0");
217 tmp
= fstab_test_option(options
, "tmp\0");
218 swap
= fstab_test_option(options
, "swap\0");
219 netdev
= fstab_test_option(options
, "_netdev\0");
221 keyfile_can_timeout
= fstab_filter_options(options
, "keyfile-timeout\0", NULL
, &keyfile_timeout_value
, NULL
);
222 if (keyfile_can_timeout
< 0)
223 return log_error_errno(keyfile_can_timeout
, "Failed to parse keyfile-timeout= option value: %m");
225 detached_header
= fstab_filter_options(options
, "header\0", NULL
, &header_path
, NULL
);
226 if (detached_header
< 0)
227 return log_error_errno(detached_header
, "Failed to parse header= option value: %m");
230 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
231 "Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.",
234 name_escaped
= specifier_escape(name
);
238 e
= unit_name_escape(name
);
242 u
= fstab_node_to_udev_node(device
);
246 r
= unit_name_build("systemd-cryptsetup", e
, ".service", &n
);
248 return log_error_errno(r
, "Failed to generate unit name: %m");
250 u_escaped
= specifier_escape(u
);
254 r
= unit_name_from_path(u
, ".device", &d
);
256 return log_error_errno(r
, "Failed to generate unit name: %m");
258 if (keydev
&& !password
)
259 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
260 "Key device is specified, but path to the password file is missing.");
262 r
= generator_open_unit_file(arg_dest
, NULL
, n
, &f
);
268 "Description=Cryptography Setup for %%I\n"
269 "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
270 "SourcePath=/etc/crypttab\n"
271 "DefaultDependencies=no\n"
272 "Conflicts=umount.target\n"
273 "IgnoreOnIsolate=true\n"
275 netdev
? "remote-fs-pre.target" : "cryptsetup-pre.target");
278 password_escaped
= specifier_escape(password
);
279 if (!password_escaped
)
284 _cleanup_free_
char *unit
= NULL
, *p
= NULL
;
286 r
= generate_keydev_mount(name
, keydev
, keyfile_timeout_value
, keyfile_can_timeout
> 0, &unit
, &keydev_mount
);
288 return log_error_errno(r
, "Failed to generate keydev mount unit: %m");
290 p
= path_join(keydev_mount
, password_escaped
);
294 free_and_replace(password_escaped
, p
);
296 fprintf(f
, "After=%s\n", unit
);
297 if (keyfile_can_timeout
> 0)
298 fprintf(f
, "Wants=%s\n", unit
);
300 fprintf(f
, "Requires=%s\n", unit
);
306 netdev
? "remote-cryptsetup.target" : "cryptsetup.target");
308 if (password
&& !keydev
) {
309 r
= print_dependencies(f
, password
);
314 /* Check if a header option was specified */
315 if (detached_header
> 0) {
316 r
= print_dependencies(f
, header_path
);
321 if (path_startswith(u
, "/dev/")) {
325 "Before=umount.target\n",
329 fputs("Before=dev-mapper-%i.swap\n",
332 /* For loopback devices, add systemd-tmpfiles-setup-dev.service
333 dependency to ensure that loopback support is available in
334 the kernel (/dev/loop-control needs to exist) */
336 "RequiresMountsFor=%s\n"
337 "Requires=systemd-tmpfiles-setup-dev.service\n"
338 "After=systemd-tmpfiles-setup-dev.service\n",
341 r
= generator_write_timeouts(arg_dest
, device
, name
, options
, &filtered
);
346 filtered_escaped
= specifier_escape(filtered
);
347 if (!filtered_escaped
)
354 "RemainAfterExit=yes\n"
355 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
356 "KeyringMode=shared\n" /* make sure we can share cached keys among instances */
357 "OOMScoreAdjust=500\n" /* unlocking can allocate a lot of memory if Argon2 is used */
358 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH
" attach '%s' '%s' '%s' '%s'\n"
359 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH
" detach '%s'\n",
360 name_escaped
, u_escaped
, strempty(password_escaped
), strempty(filtered_escaped
),
365 "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
370 "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
375 "ExecStartPost=-" UMOUNT_PATH
" %s\n\n",
378 r
= fflush_and_check(f
);
380 return log_error_errno(r
, "Failed to write unit file %s: %m", n
);
383 r
= generator_add_symlink(arg_dest
,
384 netdev
? "remote-cryptsetup.target" : "cryptsetup.target",
385 nofail
? "wants" : "requires", n
);
390 dmname
= strjoina("dev-mapper-", e
, ".device");
391 r
= generator_add_symlink(arg_dest
, dmname
, "requires", n
);
395 if (!noauto
&& !nofail
) {
396 r
= write_drop_in(arg_dest
, dmname
, 90, "device-timeout",
397 "# Automatically generated by systemd-cryptsetup-generator \n\n"
398 "[Unit]\nJobTimeoutSec=0");
400 return log_error_errno(r
, "Failed to write device drop-in: %m");
406 static crypto_device
* crypt_device_free(crypto_device
*d
) {
418 static crypto_device
*get_crypto_device(const char *uuid
) {
424 d
= hashmap_get(arg_disks
, uuid
);
426 d
= new0(struct crypto_device
, 1);
430 d
->uuid
= strdup(uuid
);
434 r
= hashmap_put(arg_disks
, d
->uuid
, d
);
444 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
445 _cleanup_free_
char *uuid
= NULL
, *uuid_value
= NULL
;
449 if (streq(key
, "luks")) {
451 r
= value
? parse_boolean(value
) : 1;
453 log_warning("Failed to parse luks= kernel command line switch %s. Ignoring.", value
);
457 } else if (streq(key
, "luks.crypttab")) {
459 r
= value
? parse_boolean(value
) : 1;
461 log_warning("Failed to parse luks.crypttab= kernel command line switch %s. Ignoring.", value
);
463 arg_read_crypttab
= r
;
465 } else if (streq(key
, "luks.uuid")) {
467 if (proc_cmdline_value_missing(key
, value
))
470 d
= get_crypto_device(startswith(value
, "luks-") ? value
+5 : value
);
474 d
->create
= arg_whitelist
= true;
476 } else if (streq(key
, "luks.options")) {
478 if (proc_cmdline_value_missing(key
, value
))
481 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
483 d
= get_crypto_device(uuid
);
487 free_and_replace(d
->options
, uuid_value
);
488 } else if (free_and_strdup(&arg_default_options
, value
) < 0)
491 } else if (streq(key
, "luks.key")) {
493 _cleanup_free_
char *keyfile
= NULL
, *keydev
= NULL
;
496 if (proc_cmdline_value_missing(key
, value
))
499 n
= strspn(value
, LETTERS DIGITS
"-");
500 if (value
[n
] != '=') {
501 if (free_and_strdup(&arg_default_keyfile
, value
) < 0)
506 uuid
= strndup(value
, n
);
510 if (!id128_is_valid(uuid
)) {
511 log_warning("Failed to parse luks.key= kernel command line switch. UUID is invalid, ignoring.");
515 d
= get_crypto_device(uuid
);
519 keyspec
= value
+ n
+ 1;
520 r
= split_keyspec(keyspec
, &keyfile
, &keydev
);
524 free_and_replace(d
->keyfile
, keyfile
);
525 free_and_replace(d
->keydev
, keydev
);
527 } else if (streq(key
, "luks.name")) {
529 if (proc_cmdline_value_missing(key
, value
))
532 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
534 d
= get_crypto_device(uuid
);
538 d
->create
= arg_whitelist
= true;
540 free_and_replace(d
->name
, uuid_value
);
542 log_warning("Failed to parse luks name switch %s. Ignoring.", value
);
548 static int add_crypttab_devices(void) {
549 _cleanup_fclose_
FILE *f
= NULL
;
550 unsigned crypttab_line
= 0;
554 if (!arg_read_crypttab
)
557 r
= fopen_unlocked("/etc/crypttab", "re", &f
);
560 log_error_errno(errno
, "Failed to open /etc/crypttab: %m");
564 if (fstat(fileno(f
), &st
) < 0) {
565 log_error_errno(errno
, "Failed to stat /etc/crypttab: %m");
570 _cleanup_free_
char *line
= NULL
, *name
= NULL
, *device
= NULL
, *keydev
= NULL
, *keyfile
= NULL
, *keyspec
= NULL
, *options
= NULL
;
571 crypto_device
*d
= NULL
;
575 r
= read_line(f
, LONG_LINE_MAX
, &line
);
577 return log_error_errno(r
, "Failed to read /etc/crypttab: %m");
584 if (IN_SET(l
[0], 0, '#'))
587 k
= sscanf(l
, "%ms %ms %ms %ms", &name
, &device
, &keyspec
, &options
);
588 if (k
< 2 || k
> 4) {
589 log_error("Failed to parse /etc/crypttab:%u, ignoring.", crypttab_line
);
593 uuid
= startswith(device
, "UUID=");
595 uuid
= path_startswith(device
, "/dev/disk/by-uuid/");
597 uuid
= startswith(name
, "luks-");
599 d
= hashmap_get(arg_disks
, uuid
);
601 if (arg_whitelist
&& !d
) {
602 log_info("Not creating device '%s' because it was not specified on the kernel command line.", name
);
606 r
= split_keyspec(keyspec
, &keyfile
, &keydev
);
610 r
= create_disk(name
, device
, keyfile
, keydev
, (d
&& d
->options
) ? d
->options
: options
);
621 static int add_proc_cmdline_devices(void) {
626 HASHMAP_FOREACH(d
, arg_disks
, i
) {
628 _cleanup_free_
char *device
= NULL
;
634 d
->name
= strjoin("luks-", d
->uuid
);
639 device
= strjoin("UUID=", d
->uuid
);
644 options
= d
->options
;
645 else if (arg_default_options
)
646 options
= arg_default_options
;
648 options
= "timeout=0";
650 r
= create_disk(d
->name
, device
, d
->keyfile
?: arg_default_keyfile
, d
->keydev
, options
);
658 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(crypt_device_hash_ops
, char, string_hash_func
, string_compare_func
,
659 crypto_device
, crypt_device_free
);
661 static int run(const char *dest
, const char *dest_early
, const char *dest_late
) {
664 assert_se(arg_dest
= dest
);
666 arg_disks
= hashmap_new(&crypt_device_hash_ops
);
670 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, PROC_CMDLINE_STRIP_RD_PREFIX
);
672 return log_warning_errno(r
, "Failed to parse kernel command line: %m");
677 r
= add_crypttab_devices();
681 r
= add_proc_cmdline_devices();
688 DEFINE_MAIN_GENERATOR_FUNCTION(run
);