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 const char *arg_crypttab
= NULL
;
41 static const char *arg_runtime_directory
= NULL
;
42 static bool arg_allow_list
= false;
43 static Hashmap
*arg_disks
= NULL
;
44 static char *arg_default_options
= NULL
;
45 static char *arg_default_keyfile
= NULL
;
47 STATIC_DESTRUCTOR_REGISTER(arg_disks
, hashmap_freep
);
48 STATIC_DESTRUCTOR_REGISTER(arg_default_options
, freep
);
49 STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile
, freep
);
51 static int split_keyspec(const char *keyspec
, char **ret_keyfile
, char **ret_keydev
) {
52 _cleanup_free_
char *keyfile
= NULL
, *keydev
= NULL
;
59 *ret_keyfile
= *ret_keydev
= NULL
;
63 c
= strrchr(keyspec
, ':');
65 /* The keydev part has to be either an absolute path to device node (/dev/something,
66 * /dev/foo/something, or even possibly /dev/foo/something:part), or a fstab device
67 * specification starting with LABEL= or similar. The keyfile part has the same syntax.
69 * Let's try to guess if the second part looks like a keydev specification, or just part of a
70 * filename with a colon. fstab_node_to_udev_node() will convert the fstab device syntax to
71 * an absolute path. If we didn't get an absolute path, assume that it is just part of the
72 * first keyfile argument. */
74 keydev
= fstab_node_to_udev_node(c
+ 1);
78 if (path_is_absolute(keydev
))
79 keyfile
= strndup(keyspec
, c
-keyspec
);
81 log_debug("Keyspec argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
82 "Assuming that \"%s\" is a single device specification.",
84 keydev
= mfree(keydev
);
90 /* No keydev specified */
91 keyfile
= strdup(keyspec
);
96 *ret_keyfile
= TAKE_PTR(keyfile
);
97 *ret_keydev
= TAKE_PTR(keydev
);
102 static int generate_device_mount(
105 const char *type_prefix
, /* "keydev" or "headerdev" */
106 const char *device_timeout
,
112 _cleanup_free_
char *u
= NULL
, *where
= NULL
, *name_escaped
= NULL
, *device_unit
= NULL
;
113 _cleanup_fclose_
FILE *f
= NULL
;
122 r
= mkdir_parents(arg_runtime_directory
, 0755);
126 r
= mkdir(arg_runtime_directory
, 0700);
127 if (r
< 0 && errno
!= EEXIST
)
130 name_escaped
= cescape(name
);
134 where
= strjoin(arg_runtime_directory
, "/", type_prefix
, "-", name_escaped
);
138 r
= mkdir(where
, 0700);
139 if (r
< 0 && errno
!= EEXIST
)
142 r
= unit_name_from_path(where
, ".mount", &u
);
146 r
= generator_open_unit_file(arg_dest
, NULL
, u
, &f
);
152 "DefaultDependencies=no\n\n"
156 "Options=%s%s\n", device
, where
, readonly
? "ro" : "rw", canfail
? ",nofail" : "");
158 if (device_timeout
) {
159 r
= parse_sec_fix_0(device_timeout
, &timeout_us
);
161 r
= unit_name_from_path(device
, ".device", &device_unit
);
163 return log_error_errno(r
, "Failed to generate unit name: %m");
165 r
= write_drop_in_format(arg_dest
, device_unit
, 90, "device-timeout",
166 "# Automatically generated by systemd-cryptsetup-generator \n\n"
167 "[Unit]\nJobRunningTimeoutSec=%s", device_timeout
);
169 return log_error_errno(r
, "Failed to write device drop-in: %m");
172 log_warning_errno(r
, "Failed to parse %s, ignoring: %m", device_timeout
);
176 r
= fflush_and_check(f
);
181 *mount
= TAKE_PTR(where
);
186 static int generate_device_umount(const char *name
,
187 const char *device_mount
,
188 const char *type_prefix
, /* "keydev" or "headerdev" */
189 char **ret_umount_unit
) {
190 _cleanup_fclose_
FILE *f
= NULL
;
191 _cleanup_free_
char *u
= NULL
, *name_escaped
= NULL
, *mount
= NULL
;
195 assert(ret_umount_unit
);
197 name_escaped
= cescape(name
);
201 u
= strjoin(type_prefix
, "-", name_escaped
, "-umount.service");
205 r
= unit_name_from_path(device_mount
, ".mount", &mount
);
209 r
= generator_open_unit_file(arg_dest
, NULL
, u
, &f
);
215 "DefaultDependencies=no\n"
218 "ExecStart=-" UMOUNT_PATH
" %s\n\n", mount
, device_mount
);
220 r
= fflush_and_check(f
);
224 *ret_umount_unit
= TAKE_PTR(u
);
228 static int print_dependencies(FILE *f
, const char* device_path
) {
231 if (STR_IN_SET(device_path
, "-", "none"))
232 /* None, nothing to do */
235 if (PATH_IN_SET(device_path
,
240 /* RNG device, add random dep */
241 fputs("After=systemd-random-seed.service\n", f
);
245 _cleanup_free_
char *udev_node
= fstab_node_to_udev_node(device_path
);
249 if (path_equal(udev_node
, "/dev/null"))
252 if (path_startswith(udev_node
, "/dev/")) {
253 /* We are dealing with a block device, add dependency for corresponding unit */
254 _cleanup_free_
char *unit
= NULL
;
256 r
= unit_name_from_path(udev_node
, ".device", &unit
);
258 return log_error_errno(r
, "Failed to generate unit name: %m");
262 "Requires=%1$s\n", unit
);
264 /* Regular file, add mount dependency */
265 _cleanup_free_
char *escaped_path
= specifier_escape(device_path
);
269 fprintf(f
, "RequiresMountsFor=%s\n", escaped_path
);
275 static int create_disk(
278 const char *password
,
281 const char *source
) {
283 _cleanup_free_
char *n
= NULL
, *d
= NULL
, *u
= NULL
, *e
= NULL
,
284 *keydev_mount
= NULL
, *keyfile_timeout_value
= NULL
,
285 *filtered
= NULL
, *u_escaped
= NULL
, *name_escaped
= NULL
, *header_path
= NULL
, *password_buffer
= NULL
,
287 _cleanup_fclose_
FILE *f
= NULL
;
289 bool noauto
, nofail
, swap
, netdev
, attach_in_initrd
;
290 int r
, detached_header
, keyfile_can_timeout
, tmp
;
295 noauto
= fstab_test_yes_no_option(options
, "noauto\0" "auto\0");
296 nofail
= fstab_test_yes_no_option(options
, "nofail\0" "fail\0");
297 swap
= fstab_test_option(options
, "swap\0");
298 netdev
= fstab_test_option(options
, "_netdev\0");
299 attach_in_initrd
= fstab_test_option(options
, "x-initrd.attach\0");
301 keyfile_can_timeout
= fstab_filter_options(options
, "keyfile-timeout\0", NULL
, &keyfile_timeout_value
, NULL
);
302 if (keyfile_can_timeout
< 0)
303 return log_error_errno(keyfile_can_timeout
, "Failed to parse keyfile-timeout= option value: %m");
305 detached_header
= fstab_filter_options(options
, "header\0", NULL
, &header_path
, NULL
);
306 if (detached_header
< 0)
307 return log_error_errno(detached_header
, "Failed to parse header= option value: %m");
309 tmp
= fstab_filter_options(options
, "tmp\0", NULL
, &tmp_fstype
, NULL
);
311 return log_error_errno(tmp
, "Failed to parse tmp= option value: %m");
314 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
315 "Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.",
318 name_escaped
= specifier_escape(name
);
322 e
= unit_name_escape(name
);
326 u
= fstab_node_to_udev_node(device
);
330 r
= unit_name_build("systemd-cryptsetup", e
, ".service", &n
);
332 return log_error_errno(r
, "Failed to generate unit name: %m");
334 u_escaped
= specifier_escape(u
);
338 r
= unit_name_from_path(u
, ".device", &d
);
340 return log_error_errno(r
, "Failed to generate unit name: %m");
342 if (keydev
&& !password
)
343 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
344 "Key device is specified, but path to the password file is missing.");
346 r
= generator_open_unit_file(arg_dest
, NULL
, n
, &f
);
350 r
= generator_write_cryptsetup_unit_section(f
, source
);
355 fprintf(f
, "After=remote-fs-pre.target\n");
357 /* If initrd takes care of attaching the disk then it should also detach it during shutdown. */
358 if (!attach_in_initrd
)
359 fprintf(f
, "Conflicts=umount.target\n");
362 _cleanup_free_
char *unit
= NULL
, *umount_unit
= NULL
;
364 r
= generate_device_mount(
368 keyfile_timeout_value
,
369 /* canfail = */ keyfile_can_timeout
> 0,
370 /* readonly= */ true,
374 return log_error_errno(r
, "Failed to generate keydev mount unit: %m");
376 r
= generate_device_umount(name
, keydev_mount
, "keydev", &umount_unit
);
378 return log_error_errno(r
, "Failed to generate keydev umount unit: %m");
380 password_buffer
= path_join(keydev_mount
, password
);
381 if (!password_buffer
)
384 password
= password_buffer
;
386 fprintf(f
, "After=%s\n", unit
);
387 if (keyfile_can_timeout
> 0)
388 fprintf(f
, "Wants=%s\n", unit
);
390 fprintf(f
, "Requires=%s\n", unit
);
405 netdev
? "remote-cryptsetup.target" : "cryptsetup.target");
407 if (password
&& !keydev
) {
408 r
= print_dependencies(f
, password
);
413 /* Check if a header option was specified */
414 if (detached_header
> 0) {
415 r
= print_dependencies(f
, header_path
);
420 if (path_startswith(u
, "/dev/"))
424 "Before=umount.target\n",
427 /* For loopback devices, add systemd-tmpfiles-setup-dev.service
428 dependency to ensure that loopback support is available in
429 the kernel (/dev/loop-control needs to exist) */
431 "RequiresMountsFor=%s\n"
432 "Requires=systemd-tmpfiles-setup-dev.service\n"
433 "After=systemd-tmpfiles-setup-dev.service\n",
436 r
= generator_write_timeouts(arg_dest
, device
, name
, options
, &filtered
);
438 log_warning_errno(r
, "Failed to write device timeout drop-in: %m");
440 r
= generator_write_cryptsetup_service_section(f
, name
, u
, password
, filtered
);
445 _cleanup_free_
char *tmp_fstype_escaped
= NULL
;
448 tmp_fstype_escaped
= specifier_escape(tmp_fstype
);
449 if (!tmp_fstype_escaped
)
454 "ExecStartPost=" ROOTLIBEXECDIR
"/systemd-makefs '%s' '/dev/mapper/%s'\n",
455 tmp_fstype_escaped
?: "ext4", name_escaped
);
460 "ExecStartPost=" ROOTLIBEXECDIR
"/systemd-makefs swap '/dev/mapper/%s'\n",
463 r
= fflush_and_check(f
);
465 return log_error_errno(r
, "Failed to write unit file %s: %m", n
);
468 r
= generator_add_symlink(arg_dest
,
469 netdev
? "remote-cryptsetup.target" : "cryptsetup.target",
470 nofail
? "wants" : "requires", n
);
475 dmname
= strjoina("dev-mapper-", e
, ".device");
476 r
= generator_add_symlink(arg_dest
, dmname
, "requires", n
);
480 if (!noauto
&& !nofail
) {
481 r
= write_drop_in(arg_dest
, dmname
, 40, "device-timeout",
482 "# Automatically generated by systemd-cryptsetup-generator\n\n"
483 "[Unit]\nJobTimeoutSec=0");
485 log_warning_errno(r
, "Failed to write device timeout drop-in: %m");
491 static crypto_device
* crypt_device_free(crypto_device
*d
) {
503 static crypto_device
*get_crypto_device(const char *uuid
) {
509 d
= hashmap_get(arg_disks
, uuid
);
511 d
= new0(struct crypto_device
, 1);
515 d
->uuid
= strdup(uuid
);
519 r
= hashmap_put(arg_disks
, d
->uuid
, d
);
529 static bool warn_uuid_invalid(const char *uuid
, const char *key
) {
532 if (!id128_is_valid(uuid
)) {
533 log_warning("Failed to parse %s= kernel command line switch. UUID is invalid, ignoring.", key
);
540 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
541 _cleanup_free_
char *uuid
= NULL
, *uuid_value
= NULL
;
545 if (streq(key
, "luks")) {
547 r
= value
? parse_boolean(value
) : 1;
549 log_warning("Failed to parse luks= kernel command line switch %s. Ignoring.", value
);
553 } else if (streq(key
, "luks.crypttab")) {
555 r
= value
? parse_boolean(value
) : 1;
557 log_warning("Failed to parse luks.crypttab= kernel command line switch %s. Ignoring.", value
);
559 arg_read_crypttab
= r
;
561 } else if (streq(key
, "luks.uuid")) {
563 if (proc_cmdline_value_missing(key
, value
))
566 d
= get_crypto_device(startswith(value
, "luks-") ?: value
);
570 d
->create
= arg_allow_list
= true;
572 } else if (streq(key
, "luks.options")) {
574 if (proc_cmdline_value_missing(key
, value
))
577 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
579 d
= get_crypto_device(uuid
);
583 free_and_replace(d
->options
, uuid_value
);
584 } else if (free_and_strdup(&arg_default_options
, value
) < 0)
587 } else if (streq(key
, "luks.key")) {
589 _cleanup_free_
char *keyfile
= NULL
, *keydev
= NULL
;
592 if (proc_cmdline_value_missing(key
, value
))
595 n
= strspn(value
, ALPHANUMERICAL
"-");
596 if (value
[n
] != '=') {
597 if (free_and_strdup(&arg_default_keyfile
, value
) < 0)
602 uuid
= strndup(value
, n
);
606 if (warn_uuid_invalid(uuid
, key
))
609 d
= get_crypto_device(uuid
);
613 keyspec
= value
+ n
+ 1;
614 r
= split_keyspec(keyspec
, &keyfile
, &keydev
);
618 free_and_replace(d
->keyfile
, keyfile
);
619 free_and_replace(d
->keydev
, keydev
);
621 } else if (streq(key
, "luks.name")) {
623 if (proc_cmdline_value_missing(key
, value
))
626 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
628 d
= get_crypto_device(uuid
);
632 d
->create
= arg_allow_list
= true;
634 free_and_replace(d
->name
, uuid_value
);
636 log_warning("Failed to parse luks name switch %s. Ignoring.", value
);
642 static int add_crypttab_devices(void) {
643 _cleanup_fclose_
FILE *f
= NULL
;
644 unsigned crypttab_line
= 0;
648 if (!arg_read_crypttab
)
651 r
= fopen_unlocked(arg_crypttab
, "re", &f
);
654 log_error_errno(errno
, "Failed to open %s: %m", arg_crypttab
);
658 if (fstat(fileno(f
), &st
) < 0) {
659 log_error_errno(errno
, "Failed to stat %s: %m", arg_crypttab
);
664 _cleanup_free_
char *line
= NULL
, *name
= NULL
, *device
= NULL
, *keyspec
= NULL
, *options
= NULL
, *keyfile
= NULL
, *keydev
= NULL
;
665 crypto_device
*d
= NULL
;
669 r
= read_line(f
, LONG_LINE_MAX
, &line
);
671 return log_error_errno(r
, "Failed to read %s: %m", arg_crypttab
);
678 if (IN_SET(l
[0], 0, '#'))
681 k
= sscanf(l
, "%ms %ms %ms %ms", &name
, &device
, &keyspec
, &options
);
682 if (k
< 2 || k
> 4) {
683 log_error("Failed to parse %s:%u, ignoring.", arg_crypttab
, crypttab_line
);
687 uuid
= startswith(device
, "UUID=");
689 uuid
= path_startswith(device
, "/dev/disk/by-uuid/");
691 uuid
= startswith(name
, "luks-");
693 d
= hashmap_get(arg_disks
, uuid
);
695 if (arg_allow_list
&& !d
) {
696 log_info("Not creating device '%s' because it was not specified on the kernel command line.", name
);
700 r
= split_keyspec(keyspec
, &keyfile
, &keydev
);
704 r
= create_disk(name
, device
, keyfile
, keydev
, (d
&& d
->options
) ? d
->options
: options
, arg_crypttab
);
715 static int add_proc_cmdline_devices(void) {
719 HASHMAP_FOREACH(d
, arg_disks
) {
720 _cleanup_free_
char *device
= NULL
;
726 d
->name
= strjoin("luks-", d
->uuid
);
731 device
= strjoin("UUID=", d
->uuid
);
735 r
= create_disk(d
->name
,
737 d
->keyfile
?: arg_default_keyfile
,
739 d
->options
?: arg_default_options
,
748 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(crypt_device_hash_ops
, char, string_hash_func
, string_compare_func
,
749 crypto_device
, crypt_device_free
);
751 static int run(const char *dest
, const char *dest_early
, const char *dest_late
) {
754 assert_se(arg_dest
= dest
);
756 arg_crypttab
= getenv("SYSTEMD_CRYPTTAB") ?: "/etc/crypttab";
757 arg_runtime_directory
= getenv("RUNTIME_DIRECTORY") ?: "/run/systemd/cryptsetup";
759 arg_disks
= hashmap_new(&crypt_device_hash_ops
);
763 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, PROC_CMDLINE_STRIP_RD_PREFIX
);
765 return log_warning_errno(r
, "Failed to parse kernel command line: %m");
770 r
= add_crypttab_devices();
774 r
= add_proc_cmdline_devices();
781 DEFINE_MAIN_GENERATOR_FUNCTION(run
);