1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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"
27 typedef struct crypto_device
{
38 static const char *arg_dest
= NULL
;
39 static bool arg_enabled
= true;
40 static bool arg_read_crypttab
= true;
41 static const char *arg_crypttab
= NULL
;
42 static const char *arg_runtime_directory
= NULL
;
43 static bool arg_allow_list
= false;
44 static Hashmap
*arg_disks
= NULL
;
45 static char *arg_default_options
= NULL
;
46 static char *arg_default_keyfile
= NULL
;
48 STATIC_DESTRUCTOR_REGISTER(arg_disks
, hashmap_freep
);
49 STATIC_DESTRUCTOR_REGISTER(arg_default_options
, freep
);
50 STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile
, freep
);
52 static int split_locationspec(const char *locationspec
, char **ret_file
, char **ret_device
) {
53 _cleanup_free_
char *file
= NULL
, *device
= NULL
;
60 *ret_file
= *ret_device
= NULL
;
64 c
= strrchr(locationspec
, ':');
66 /* The device part has to be either an absolute path to device node (/dev/something,
67 * /dev/foo/something, or even possibly /dev/foo/something:part), or a fstab device
68 * specification starting with LABEL= or similar. The file part has the same syntax.
70 * Let's try to guess if the second part looks like a device specification, or just part of a
71 * filename with a colon. fstab_node_to_udev_node() will convert the fstab device syntax to
72 * an absolute path. If we didn't get an absolute path, assume that it is just part of the
73 * first file argument. */
75 device
= fstab_node_to_udev_node(c
+ 1);
79 if (path_is_absolute(device
))
80 file
= strndup(locationspec
, c
-locationspec
);
82 log_debug("Location specification argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
83 "Assuming that \"%s\" is a single device specification.",
85 device
= mfree(device
);
91 /* No device specified */
92 file
= strdup(locationspec
);
97 *ret_file
= TAKE_PTR(file
);
98 *ret_device
= TAKE_PTR(device
);
103 static int generate_device_mount(
106 const char *type_prefix
, /* "keydev" or "headerdev" */
107 const char *device_timeout
,
113 _cleanup_free_
char *u
= NULL
, *where
= NULL
, *name_escaped
= NULL
, *device_unit
= NULL
;
114 _cleanup_fclose_
FILE *f
= NULL
;
123 r
= mkdir_parents(arg_runtime_directory
, 0755);
127 r
= mkdir(arg_runtime_directory
, 0700);
128 if (r
< 0 && errno
!= EEXIST
)
131 name_escaped
= cescape(name
);
135 where
= strjoin(arg_runtime_directory
, "/", type_prefix
, "-", name_escaped
);
139 r
= mkdir(where
, 0700);
140 if (r
< 0 && errno
!= EEXIST
)
143 r
= unit_name_from_path(where
, ".mount", &u
);
147 r
= generator_open_unit_file(arg_dest
, NULL
, u
, &f
);
153 "DefaultDependencies=no\n\n"
157 "Options=%s%s\n", device
, where
, readonly
? "ro" : "rw", canfail
? ",nofail" : "");
159 if (device_timeout
) {
160 r
= parse_sec_fix_0(device_timeout
, &timeout_us
);
162 r
= unit_name_from_path(device
, ".device", &device_unit
);
164 return log_error_errno(r
, "Failed to generate unit name: %m");
166 r
= write_drop_in_format(arg_dest
, device_unit
, 90, "device-timeout",
167 "# Automatically generated by systemd-cryptsetup-generator \n\n"
168 "[Unit]\nJobRunningTimeoutSec=%s", device_timeout
);
170 return log_error_errno(r
, "Failed to write device drop-in: %m");
173 log_warning_errno(r
, "Failed to parse %s, ignoring: %m", device_timeout
);
177 r
= fflush_and_check(f
);
182 *mount
= TAKE_PTR(where
);
187 static int generate_device_umount(const char *name
,
188 const char *device_mount
,
189 const char *type_prefix
, /* "keydev" or "headerdev" */
190 char **ret_umount_unit
) {
191 _cleanup_fclose_
FILE *f
= NULL
;
192 _cleanup_free_
char *u
= NULL
, *name_escaped
= NULL
, *mount
= NULL
;
196 assert(ret_umount_unit
);
198 name_escaped
= cescape(name
);
202 u
= strjoin(type_prefix
, "-", name_escaped
, "-umount.service");
206 r
= unit_name_from_path(device_mount
, ".mount", &mount
);
210 r
= generator_open_unit_file(arg_dest
, NULL
, u
, &f
);
216 "DefaultDependencies=no\n"
219 "ExecStart=-" UMOUNT_PATH
" %s\n\n", mount
, device_mount
);
221 r
= fflush_and_check(f
);
225 *ret_umount_unit
= TAKE_PTR(u
);
229 static int print_dependencies(FILE *f
, const char* device_path
, const char* timeout_value
, bool canfail
) {
235 if (STR_IN_SET(device_path
, "-", "none"))
236 /* None, nothing to do */
239 if (PATH_IN_SET(device_path
,
244 /* RNG device, add random dep */
245 fputs("After=systemd-random-seed.service\n", f
);
249 _cleanup_free_
char *udev_node
= fstab_node_to_udev_node(device_path
);
253 if (path_equal(udev_node
, "/dev/null"))
256 if (path_startswith(udev_node
, "/dev/")) {
257 /* We are dealing with a block device, add dependency for corresponding unit */
258 _cleanup_free_
char *unit
= NULL
;
260 r
= unit_name_from_path(udev_node
, ".device", &unit
);
262 return log_error_errno(r
, "Failed to generate unit name: %m");
264 fprintf(f
, "After=%1$s\n", unit
);
266 fprintf(f
, "Wants=%1$s\n", unit
);
268 r
= write_drop_in_format(arg_dest
, unit
, 90, "device-timeout",
269 "# Automatically generated by systemd-cryptsetup-generator \n\n"
270 "[Unit]\nJobRunningTimeoutSec=%s", timeout_value
);
272 return log_error_errno(r
, "Failed to write device drop-in: %m");
275 fprintf(f
, "Requires=%1$s\n", unit
);
277 /* Regular file, add mount dependency */
278 _cleanup_free_
char *escaped_path
= specifier_escape(device_path
);
282 fprintf(f
, "%s=%s\n", canfail
? "WantsMountsFor" : "RequiresMountsFor", escaped_path
);
288 static bool attach_in_initrd(const char *name
, const char *options
) {
291 /* Imply x-initrd.attach in case the volume name is among those defined in the Discoverable Partition
292 * Specification for partitions that we require to be mounted during the initrd → host transition,
293 * i.e. for the root fs itself, and /usr/. This mirrors similar behaviour in
294 * systemd-fstab-generator. */
296 return fstab_test_option(options
, "x-initrd.attach\0") ||
297 STR_IN_SET(name
, "root", "usr");
300 static int create_disk(
303 const char *key_file
,
305 const char *headerdev
,
307 const char *source
) {
309 _cleanup_free_
char *n
= NULL
, *d
= NULL
, *u
= NULL
, *e
= NULL
,
310 *keydev_mount
= NULL
, *keyfile_timeout_value
= NULL
,
311 *filtered
= NULL
, *u_escaped
= NULL
, *name_escaped
= NULL
, *header_path
= NULL
, *key_file_buffer
= NULL
,
312 *tmp_fstype
= NULL
, *filtered_header
= NULL
, *headerdev_mount
= NULL
;
313 _cleanup_fclose_
FILE *f
= NULL
;
315 bool noauto
, nofail
, swap
, netdev
;
316 int r
, detached_header
, keyfile_can_timeout
, tmp
;
321 noauto
= fstab_test_yes_no_option(options
, "noauto\0" "auto\0");
322 nofail
= fstab_test_yes_no_option(options
, "nofail\0" "fail\0");
323 swap
= fstab_test_option(options
, "swap\0");
324 netdev
= fstab_test_option(options
, "_netdev\0");
326 keyfile_can_timeout
= fstab_filter_options(options
,
328 NULL
, &keyfile_timeout_value
, NULL
, NULL
);
329 if (keyfile_can_timeout
< 0)
330 return log_error_errno(keyfile_can_timeout
, "Failed to parse keyfile-timeout= option value: %m");
332 detached_header
= fstab_filter_options(
338 headerdev
? &filtered_header
: NULL
);
339 if (detached_header
< 0)
340 return log_error_errno(detached_header
, "Failed to parse header= option value: %m");
342 tmp
= fstab_filter_options(options
, "tmp\0", NULL
, &tmp_fstype
, NULL
, NULL
);
344 return log_error_errno(tmp
, "Failed to parse tmp= option value: %m");
347 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
348 "Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.",
351 name_escaped
= specifier_escape(name
);
355 e
= unit_name_escape(name
);
359 u
= fstab_node_to_udev_node(device
);
363 r
= unit_name_build("systemd-cryptsetup", e
, ".service", &n
);
365 return log_error_errno(r
, "Failed to generate unit name: %m");
367 u_escaped
= specifier_escape(u
);
371 r
= unit_name_from_path(u
, ".device", &d
);
373 return log_error_errno(r
, "Failed to generate unit name: %m");
375 if (keydev
&& !key_file
)
376 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
377 "Key device is specified, but path to the key file is missing.");
379 r
= generator_open_unit_file(arg_dest
, NULL
, n
, &f
);
383 r
= generator_write_cryptsetup_unit_section(f
, source
);
388 fprintf(f
, "After=remote-fs-pre.target\n");
390 /* If initrd takes care of attaching the disk then it should also detach it during shutdown. */
391 if (!attach_in_initrd(name
, options
))
393 "Conflicts=umount.target\n"
394 "Before=umount.target\n");
397 _cleanup_free_
char *unit
= NULL
, *umount_unit
= NULL
;
399 r
= generate_device_mount(
403 keyfile_timeout_value
,
404 /* canfail = */ keyfile_can_timeout
> 0,
405 /* readonly= */ true,
409 return log_error_errno(r
, "Failed to generate keydev mount unit: %m");
411 r
= generate_device_umount(name
, keydev_mount
, "keydev", &umount_unit
);
413 return log_error_errno(r
, "Failed to generate keydev umount unit: %m");
415 key_file_buffer
= path_join(keydev_mount
, key_file
);
416 if (!key_file_buffer
)
419 key_file
= key_file_buffer
;
421 fprintf(f
, "After=%s\n", unit
);
422 if (keyfile_can_timeout
> 0)
423 fprintf(f
, "Wants=%s\n", unit
);
425 fprintf(f
, "Requires=%s\n", unit
);
437 _cleanup_free_
char *unit
= NULL
, *umount_unit
= NULL
, *p
= NULL
;
439 r
= generate_device_mount(
444 /* canfail= */ false, /* header is always necessary */
445 /* readonly= */ false, /* LUKS2 recovery requires rw header access */
449 return log_error_errno(r
, "Failed to generate header device mount unit: %m");
451 r
= generate_device_umount(name
, headerdev_mount
, "headerdev", &umount_unit
);
453 return log_error_errno(r
, "Failed to generate header device umount unit: %m");
455 p
= path_join(headerdev_mount
, header_path
);
459 free_and_replace(header_path
, p
);
461 if (isempty(filtered_header
))
462 p
= strjoin("header=", header_path
);
464 p
= strjoin(filtered_header
, ",header=", header_path
);
469 free_and_replace(filtered_header
, p
);
470 options
= filtered_header
;
472 fprintf(f
, "After=%s\n"
473 "Requires=%s\n", unit
, unit
);
487 netdev
? "remote-cryptsetup.target" : "cryptsetup.target");
489 if (key_file
&& !keydev
) {
490 r
= print_dependencies(f
, key_file
,
491 keyfile_timeout_value
,
492 /* canfail= */ keyfile_can_timeout
> 0 || nofail
);
497 /* Check if a header option was specified */
498 if (detached_header
> 0 && !headerdev
) {
499 r
= print_dependencies(f
, header_path
,
500 /* timeout_value= */ NULL
,
501 /* canfail= */ nofail
);
506 if (path_startswith(u
, "/dev/"))
512 /* For loopback devices make sure to explicitly load loop.ko, as this code might run very
513 * early where device nodes created via systemd-tmpfiles-setup-dev.service might not be
514 * around yet. Hence let's sync on the module itself. */
516 "RequiresMountsFor=%s\n"
517 "Wants=modprobe@loop.service\n"
518 "After=modprobe@loop.service\n",
521 r
= generator_write_timeouts(arg_dest
, device
, name
, options
, &filtered
);
523 log_warning_errno(r
, "Failed to write device timeout drop-in: %m");
525 r
= generator_write_cryptsetup_service_section(f
, name
, u
, key_file
, filtered
);
530 _cleanup_free_
char *tmp_fstype_escaped
= NULL
;
533 tmp_fstype_escaped
= specifier_escape(tmp_fstype
);
534 if (!tmp_fstype_escaped
)
539 "ExecStartPost=" LIBEXECDIR
"/systemd-makefs '%s' '/dev/mapper/%s'\n",
540 tmp_fstype_escaped
?: "ext4", name_escaped
);
545 "ExecStartPost=" LIBEXECDIR
"/systemd-makefs swap '/dev/mapper/%s'\n",
548 r
= fflush_and_check(f
);
550 return log_error_errno(r
, "Failed to write unit file %s: %m", n
);
553 r
= generator_add_symlink(arg_dest
,
554 netdev
? "remote-cryptsetup.target" : "cryptsetup.target",
555 nofail
? "wants" : "requires", n
);
560 dmname
= strjoina("dev-mapper-", e
, ".device");
561 r
= generator_add_symlink(arg_dest
, dmname
, "requires", n
);
565 if (!noauto
&& !nofail
) {
566 r
= write_drop_in(arg_dest
, dmname
, 40, "device-timeout",
567 "# Automatically generated by systemd-cryptsetup-generator\n\n"
569 "JobTimeoutSec=infinity\n");
571 log_warning_errno(r
, "Failed to write device timeout drop-in: %m");
577 static crypto_device
* crypt_device_free(crypto_device
*d
) {
589 static crypto_device
*get_crypto_device(const char *uuid
) {
595 d
= hashmap_get(arg_disks
, uuid
);
597 d
= new0(struct crypto_device
, 1);
601 d
->uuid
= strdup(uuid
);
605 r
= hashmap_put(arg_disks
, d
->uuid
, d
);
615 static bool warn_uuid_invalid(const char *uuid
, const char *key
) {
618 if (!id128_is_valid(uuid
)) {
619 log_warning("Failed to parse %s= kernel command line switch. UUID is invalid, ignoring.", key
);
626 static int filter_header_device(const char *options
,
627 char **ret_headerdev
,
628 char **ret_filtered_headerdev_options
) {
630 _cleanup_free_
char *headerfile
= NULL
, *headerdev
= NULL
, *headerspec
= NULL
,
631 *filtered_headerdev
= NULL
, *filtered_headerspec
= NULL
;
633 assert(ret_headerdev
);
634 assert(ret_filtered_headerdev_options
);
636 r
= fstab_filter_options(options
, "header\0", NULL
, &headerspec
, NULL
, &filtered_headerspec
);
638 return log_error_errno(r
, "Failed to parse header= option value: %m");
641 r
= split_locationspec(headerspec
, &headerfile
, &headerdev
);
645 if (isempty(filtered_headerspec
))
646 filtered_headerdev
= strjoin("header=", headerfile
);
648 filtered_headerdev
= strjoin(filtered_headerspec
, ",header=", headerfile
);
650 if (!filtered_headerdev
)
653 filtered_headerdev
= TAKE_PTR(filtered_headerspec
);
655 *ret_filtered_headerdev_options
= TAKE_PTR(filtered_headerdev
);
656 *ret_headerdev
= TAKE_PTR(headerdev
);
661 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
662 _cleanup_free_
char *uuid
= NULL
, *uuid_value
= NULL
;
666 if (streq(key
, "luks")) {
668 r
= value
? parse_boolean(value
) : 1;
670 log_warning("Failed to parse luks= kernel command line switch %s. Ignoring.", value
);
674 } else if (streq(key
, "luks.crypttab")) {
676 r
= value
? parse_boolean(value
) : 1;
678 log_warning("Failed to parse luks.crypttab= kernel command line switch %s. Ignoring.", value
);
680 arg_read_crypttab
= r
;
682 } else if (streq(key
, "luks.uuid")) {
684 if (proc_cmdline_value_missing(key
, value
))
687 d
= get_crypto_device(startswith(value
, "luks-") ?: value
);
691 d
->create
= arg_allow_list
= true;
693 } else if (streq(key
, "luks.options")) {
694 _cleanup_free_
char *headerdev
= NULL
, *filtered_headerdev_options
= NULL
;
696 if (proc_cmdline_value_missing(key
, value
))
699 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
701 return free_and_strdup_warn(&arg_default_options
, value
);
703 if (warn_uuid_invalid(uuid
, key
))
706 d
= get_crypto_device(uuid
);
710 r
= filter_header_device(uuid_value
, &headerdev
, &filtered_headerdev_options
);
714 free_and_replace(d
->options
, filtered_headerdev_options
);
715 free_and_replace(d
->headerdev
, headerdev
);
716 } else if (streq(key
, "luks.key")) {
718 _cleanup_free_
char *keyfile
= NULL
, *keydev
= NULL
;
721 if (proc_cmdline_value_missing(key
, value
))
724 n
= strspn(value
, ALPHANUMERICAL
"-");
726 return free_and_strdup_warn(&arg_default_keyfile
, value
);
728 uuid
= strndup(value
, n
);
732 if (warn_uuid_invalid(uuid
, key
))
735 d
= get_crypto_device(uuid
);
739 keyspec
= value
+ n
+ 1;
740 r
= split_locationspec(keyspec
, &keyfile
, &keydev
);
744 free_and_replace(d
->keyfile
, keyfile
);
745 free_and_replace(d
->keydev
, keydev
);
746 } else if (streq(key
, "luks.data")) {
748 _cleanup_free_
char *datadev
= NULL
;
750 if (proc_cmdline_value_missing(key
, value
))
753 n
= strspn(value
, ALPHANUMERICAL
"-");
754 if (value
[n
] != '=') {
755 log_warning("Failed to parse luks.data= kernel command line switch. UUID is invalid, ignoring.");
759 uuid
= strndup(value
, n
);
763 if (warn_uuid_invalid(uuid
, key
))
766 d
= get_crypto_device(uuid
);
770 datadev
= fstab_node_to_udev_node(value
+ n
+ 1);
774 free_and_replace(d
->datadev
, datadev
);
775 } else if (streq(key
, "luks.name")) {
777 if (proc_cmdline_value_missing(key
, value
))
780 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
782 d
= get_crypto_device(uuid
);
786 d
->create
= arg_allow_list
= true;
788 free_and_replace(d
->name
, uuid_value
);
790 log_warning("Failed to parse luks name switch %s. Ignoring.", value
);
796 static int add_crypttab_devices(void) {
797 _cleanup_fclose_
FILE *f
= NULL
;
798 unsigned crypttab_line
= 0;
801 if (!arg_read_crypttab
)
804 r
= fopen_unlocked(arg_crypttab
, "re", &f
);
807 log_error_errno(errno
, "Failed to open %s: %m", arg_crypttab
);
812 _cleanup_free_
char *line
= NULL
, *name
= NULL
, *device
= NULL
, *keyspec
= NULL
, *options
= NULL
,
813 *keyfile
= NULL
, *keydev
= NULL
, *headerdev
= NULL
, *filtered_header
= NULL
;
814 crypto_device
*d
= NULL
;
818 r
= read_stripped_line(f
, LONG_LINE_MAX
, &line
);
820 return log_error_errno(r
, "Failed to read %s: %m", arg_crypttab
);
826 if (IN_SET(line
[0], 0, '#'))
829 k
= sscanf(line
, "%ms %ms %ms %ms", &name
, &device
, &keyspec
, &options
);
830 if (k
< 2 || k
> 4) {
831 log_error("Failed to parse %s:%u, ignoring.", arg_crypttab
, crypttab_line
);
835 uuid
= startswith(device
, "UUID=");
837 uuid
= path_startswith(device
, "/dev/disk/by-uuid/");
839 uuid
= startswith(name
, "luks-");
841 d
= hashmap_get(arg_disks
, uuid
);
843 if (arg_allow_list
&& !d
) {
844 log_info("Not creating device '%s' because it was not specified on the kernel command line.", name
);
848 r
= split_locationspec(keyspec
, &keyfile
, &keydev
);
852 if (options
&& (!d
|| !d
->options
)) {
853 r
= filter_header_device(options
, &headerdev
, &filtered_header
);
856 free_and_replace(options
, filtered_header
);
859 r
= create_disk(name
,
863 (d
&& d
->options
) ? d
->headerdev
: headerdev
,
864 (d
&& d
->options
) ? d
->options
: options
,
876 static int add_proc_cmdline_devices(void) {
880 HASHMAP_FOREACH(d
, arg_disks
) {
881 _cleanup_free_
char *device
= NULL
;
887 d
->name
= strjoin("luks-", d
->uuid
);
892 device
= strjoin("UUID=", d
->uuid
);
896 r
= create_disk(d
->name
,
897 d
->datadev
?: device
,
898 d
->keyfile
?: arg_default_keyfile
,
901 d
->options
?: arg_default_options
,
910 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(crypt_device_hash_ops
, char, string_hash_func
, string_compare_func
,
911 crypto_device
, crypt_device_free
);
913 static int run(const char *dest
, const char *dest_early
, const char *dest_late
) {
916 assert_se(arg_dest
= dest
);
918 arg_crypttab
= getenv("SYSTEMD_CRYPTTAB") ?: "/etc/crypttab";
919 arg_runtime_directory
= getenv("RUNTIME_DIRECTORY") ?: "/run/systemd/cryptsetup";
921 arg_disks
= hashmap_new(&crypt_device_hash_ops
);
925 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, PROC_CMDLINE_STRIP_RD_PREFIX
);
927 return log_warning_errno(r
, "Failed to parse kernel command line: %m");
932 r
= add_crypttab_devices();
936 r
= add_proc_cmdline_devices();
943 DEFINE_MAIN_GENERATOR_FUNCTION(run
);