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"
28 typedef struct crypto_device
{
39 static const char *arg_dest
= NULL
;
40 static bool arg_enabled
= true;
41 static bool arg_read_crypttab
= true;
42 static const char *arg_crypttab
= NULL
;
43 static const char *arg_runtime_directory
= NULL
;
44 static bool arg_allow_list
= false;
45 static Hashmap
*arg_disks
= NULL
;
46 static char *arg_default_options
= NULL
;
47 static char *arg_default_keyfile
= NULL
;
49 STATIC_DESTRUCTOR_REGISTER(arg_disks
, hashmap_freep
);
50 STATIC_DESTRUCTOR_REGISTER(arg_default_options
, freep
);
51 STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile
, freep
);
53 static int split_locationspec(const char *locationspec
, char **ret_file
, char **ret_device
) {
54 _cleanup_free_
char *file
= NULL
, *device
= NULL
;
61 *ret_file
= *ret_device
= NULL
;
65 c
= strrchr(locationspec
, ':');
67 /* The device part has to be either an absolute path to device node (/dev/something,
68 * /dev/foo/something, or even possibly /dev/foo/something:part), or a fstab device
69 * specification starting with LABEL= or similar. The file part has the same syntax.
71 * Let's try to guess if the second part looks like a device specification, or just part of a
72 * filename with a colon. fstab_node_to_udev_node() will convert the fstab device syntax to
73 * an absolute path. If we didn't get an absolute path, assume that it is just part of the
74 * first file argument. */
76 device
= fstab_node_to_udev_node(c
+ 1);
80 if (path_is_absolute(device
))
81 file
= strndup(locationspec
, c
-locationspec
);
83 log_debug("Location specification argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
84 "Assuming that \"%s\" is a single device specification.",
86 device
= mfree(device
);
92 /* No device specified */
93 file
= strdup(locationspec
);
98 *ret_file
= TAKE_PTR(file
);
99 *ret_device
= TAKE_PTR(device
);
104 static int generate_device_mount(
107 const char *type_prefix
, /* "keydev" or "headerdev" */
108 const char *device_timeout
,
114 _cleanup_free_
char *u
= NULL
, *where
= NULL
, *name_escaped
= NULL
, *device_unit
= NULL
;
115 _cleanup_fclose_
FILE *f
= NULL
;
124 r
= mkdir_parents(arg_runtime_directory
, 0755);
128 r
= mkdir(arg_runtime_directory
, 0700);
129 if (r
< 0 && errno
!= EEXIST
)
132 name_escaped
= cescape(name
);
136 where
= strjoin(arg_runtime_directory
, "/", type_prefix
, "-", name_escaped
);
140 r
= mkdir(where
, 0700);
141 if (r
< 0 && errno
!= EEXIST
)
144 r
= unit_name_from_path(where
, ".mount", &u
);
148 r
= generator_open_unit_file(arg_dest
, NULL
, u
, &f
);
154 "DefaultDependencies=no\n\n"
158 "Options=%s%s\n", device
, where
, readonly
? "ro" : "rw", canfail
? ",nofail" : "");
160 if (device_timeout
) {
161 r
= parse_sec_fix_0(device_timeout
, &timeout_us
);
163 r
= unit_name_from_path(device
, ".device", &device_unit
);
165 return log_error_errno(r
, "Failed to generate unit name: %m");
167 r
= write_drop_in_format(arg_dest
, device_unit
, 90, "device-timeout",
168 "# Automatically generated by systemd-cryptsetup-generator \n\n"
169 "[Unit]\nJobRunningTimeoutSec=%s", device_timeout
);
171 return log_error_errno(r
, "Failed to write device drop-in: %m");
174 log_warning_errno(r
, "Failed to parse %s, ignoring: %m", device_timeout
);
178 r
= fflush_and_check(f
);
183 *mount
= TAKE_PTR(where
);
188 static int generate_device_umount(const char *name
,
189 const char *device_mount
,
190 const char *type_prefix
, /* "keydev" or "headerdev" */
191 char **ret_umount_unit
) {
192 _cleanup_fclose_
FILE *f
= NULL
;
193 _cleanup_free_
char *u
= NULL
, *name_escaped
= NULL
, *mount
= NULL
;
197 assert(ret_umount_unit
);
199 name_escaped
= cescape(name
);
203 u
= strjoin(type_prefix
, "-", name_escaped
, "-umount.service");
207 r
= unit_name_from_path(device_mount
, ".mount", &mount
);
211 r
= generator_open_unit_file(arg_dest
, NULL
, u
, &f
);
217 "DefaultDependencies=no\n"
220 "ExecStart=-" UMOUNT_PATH
" %s\n\n", mount
, device_mount
);
222 r
= fflush_and_check(f
);
226 *ret_umount_unit
= TAKE_PTR(u
);
230 static int print_dependencies(FILE *f
, const char* device_path
) {
233 if (STR_IN_SET(device_path
, "-", "none"))
234 /* None, nothing to do */
237 if (PATH_IN_SET(device_path
,
242 /* RNG device, add random dep */
243 fputs("After=systemd-random-seed.service\n", f
);
247 _cleanup_free_
char *udev_node
= fstab_node_to_udev_node(device_path
);
251 if (path_equal(udev_node
, "/dev/null"))
254 if (path_startswith(udev_node
, "/dev/")) {
255 /* We are dealing with a block device, add dependency for corresponding unit */
256 _cleanup_free_
char *unit
= NULL
;
258 r
= unit_name_from_path(udev_node
, ".device", &unit
);
260 return log_error_errno(r
, "Failed to generate unit name: %m");
264 "Requires=%1$s\n", unit
);
266 /* Regular file, add mount dependency */
267 _cleanup_free_
char *escaped_path
= specifier_escape(device_path
);
271 fprintf(f
, "RequiresMountsFor=%s\n", escaped_path
);
277 static int create_disk(
280 const char *password
,
282 const char *headerdev
,
284 const char *source
) {
286 _cleanup_free_
char *n
= NULL
, *d
= NULL
, *u
= NULL
, *e
= NULL
,
287 *keydev_mount
= NULL
, *keyfile_timeout_value
= NULL
,
288 *filtered
= NULL
, *u_escaped
= NULL
, *name_escaped
= NULL
, *header_path
= NULL
, *password_buffer
= NULL
,
289 *tmp_fstype
= NULL
, *filtered_header
= NULL
, *headerdev_mount
= NULL
;
290 _cleanup_fclose_
FILE *f
= NULL
;
292 bool noauto
, nofail
, swap
, netdev
, attach_in_initrd
;
293 int r
, detached_header
, keyfile_can_timeout
, tmp
;
298 noauto
= fstab_test_yes_no_option(options
, "noauto\0" "auto\0");
299 nofail
= fstab_test_yes_no_option(options
, "nofail\0" "fail\0");
300 swap
= fstab_test_option(options
, "swap\0");
301 netdev
= fstab_test_option(options
, "_netdev\0");
302 attach_in_initrd
= fstab_test_option(options
, "x-initrd.attach\0");
304 keyfile_can_timeout
= fstab_filter_options(options
, "keyfile-timeout\0", NULL
, &keyfile_timeout_value
, NULL
);
305 if (keyfile_can_timeout
< 0)
306 return log_error_errno(keyfile_can_timeout
, "Failed to parse keyfile-timeout= option value: %m");
308 detached_header
= fstab_filter_options(
313 headerdev
? &filtered_header
: NULL
);
314 if (detached_header
< 0)
315 return log_error_errno(detached_header
, "Failed to parse header= option value: %m");
317 tmp
= fstab_filter_options(options
, "tmp\0", NULL
, &tmp_fstype
, NULL
);
319 return log_error_errno(tmp
, "Failed to parse tmp= option value: %m");
322 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
323 "Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.",
326 name_escaped
= specifier_escape(name
);
330 e
= unit_name_escape(name
);
334 u
= fstab_node_to_udev_node(device
);
338 r
= unit_name_build("systemd-cryptsetup", e
, ".service", &n
);
340 return log_error_errno(r
, "Failed to generate unit name: %m");
342 u_escaped
= specifier_escape(u
);
346 r
= unit_name_from_path(u
, ".device", &d
);
348 return log_error_errno(r
, "Failed to generate unit name: %m");
350 if (keydev
&& !password
)
351 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
352 "Key device is specified, but path to the password file is missing.");
354 r
= generator_open_unit_file(arg_dest
, NULL
, n
, &f
);
358 r
= generator_write_cryptsetup_unit_section(f
, source
);
363 fprintf(f
, "After=remote-fs-pre.target\n");
365 /* If initrd takes care of attaching the disk then it should also detach it during shutdown. */
366 if (!attach_in_initrd
)
367 fprintf(f
, "Conflicts=umount.target\n");
370 _cleanup_free_
char *unit
= NULL
, *umount_unit
= NULL
;
372 r
= generate_device_mount(
376 keyfile_timeout_value
,
377 /* canfail = */ keyfile_can_timeout
> 0,
378 /* readonly= */ true,
382 return log_error_errno(r
, "Failed to generate keydev mount unit: %m");
384 r
= generate_device_umount(name
, keydev_mount
, "keydev", &umount_unit
);
386 return log_error_errno(r
, "Failed to generate keydev umount unit: %m");
388 password_buffer
= path_join(keydev_mount
, password
);
389 if (!password_buffer
)
392 password
= password_buffer
;
394 fprintf(f
, "After=%s\n", unit
);
395 if (keyfile_can_timeout
> 0)
396 fprintf(f
, "Wants=%s\n", unit
);
398 fprintf(f
, "Requires=%s\n", unit
);
410 _cleanup_free_
char *unit
= NULL
, *umount_unit
= NULL
, *p
= NULL
;
412 r
= generate_device_mount(
417 /* canfail= */ false, /* header is always necessary */
418 /* readonly= */ false, /* LUKS2 recovery requires rw header access */
422 return log_error_errno(r
, "Failed to generate header device mount unit: %m");
424 r
= generate_device_umount(name
, headerdev_mount
, "headerdev", &umount_unit
);
426 return log_error_errno(r
, "Failed to generate header device umount unit: %m");
428 p
= path_join(headerdev_mount
, header_path
);
432 free_and_replace(header_path
, p
);
434 if (isempty(filtered_header
))
435 p
= strjoin("header=", header_path
);
437 p
= strjoin(filtered_header
, ",header=", header_path
);
442 free_and_replace(filtered_header
, p
);
443 options
= filtered_header
;
445 fprintf(f
, "After=%s\n"
446 "Requires=%s\n", unit
, unit
);
460 netdev
? "remote-cryptsetup.target" : "cryptsetup.target");
462 if (password
&& !keydev
) {
463 r
= print_dependencies(f
, password
);
468 /* Check if a header option was specified */
469 if (detached_header
> 0 && !headerdev
) {
470 r
= print_dependencies(f
, header_path
);
475 if (path_startswith(u
, "/dev/"))
479 "Before=umount.target\n",
482 /* For loopback devices, add systemd-tmpfiles-setup-dev.service
483 dependency to ensure that loopback support is available in
484 the kernel (/dev/loop-control needs to exist) */
486 "RequiresMountsFor=%s\n"
487 "Requires=systemd-tmpfiles-setup-dev.service\n"
488 "After=systemd-tmpfiles-setup-dev.service\n",
491 r
= generator_write_timeouts(arg_dest
, device
, name
, options
, &filtered
);
493 log_warning_errno(r
, "Failed to write device timeout drop-in: %m");
495 r
= generator_write_cryptsetup_service_section(f
, name
, u
, password
, filtered
);
500 _cleanup_free_
char *tmp_fstype_escaped
= NULL
;
503 tmp_fstype_escaped
= specifier_escape(tmp_fstype
);
504 if (!tmp_fstype_escaped
)
509 "ExecStartPost=" ROOTLIBEXECDIR
"/systemd-makefs '%s' '/dev/mapper/%s'\n",
510 tmp_fstype_escaped
?: "ext4", name_escaped
);
515 "ExecStartPost=" ROOTLIBEXECDIR
"/systemd-makefs swap '/dev/mapper/%s'\n",
518 r
= fflush_and_check(f
);
520 return log_error_errno(r
, "Failed to write unit file %s: %m", n
);
523 r
= generator_add_symlink(arg_dest
,
524 netdev
? "remote-cryptsetup.target" : "cryptsetup.target",
525 nofail
? "wants" : "requires", n
);
530 dmname
= strjoina("dev-mapper-", e
, ".device");
531 r
= generator_add_symlink(arg_dest
, dmname
, "requires", n
);
535 if (!noauto
&& !nofail
) {
536 r
= write_drop_in(arg_dest
, dmname
, 40, "device-timeout",
537 "# Automatically generated by systemd-cryptsetup-generator\n\n"
538 "[Unit]\nJobTimeoutSec=0");
540 log_warning_errno(r
, "Failed to write device timeout drop-in: %m");
546 static crypto_device
* crypt_device_free(crypto_device
*d
) {
558 static crypto_device
*get_crypto_device(const char *uuid
) {
564 d
= hashmap_get(arg_disks
, uuid
);
566 d
= new0(struct crypto_device
, 1);
570 d
->uuid
= strdup(uuid
);
574 r
= hashmap_put(arg_disks
, d
->uuid
, d
);
584 static bool warn_uuid_invalid(const char *uuid
, const char *key
) {
587 if (!id128_is_valid(uuid
)) {
588 log_warning("Failed to parse %s= kernel command line switch. UUID is invalid, ignoring.", key
);
595 static int filter_header_device(const char *options
,
596 char **ret_headerdev
,
597 char **ret_filtered_headerdev_options
) {
599 _cleanup_free_
char *headerfile
= NULL
, *headerdev
= NULL
, *headerspec
= NULL
,
600 *filtered_headerdev
= NULL
, *filtered_headerspec
= NULL
;
602 assert(ret_headerdev
);
603 assert(ret_filtered_headerdev_options
);
605 r
= fstab_filter_options(options
, "header\0", NULL
, &headerspec
, &filtered_headerspec
);
607 return log_error_errno(r
, "Failed to parse header= option value: %m");
610 r
= split_locationspec(headerspec
, &headerfile
, &headerdev
);
614 if (isempty(filtered_headerspec
))
615 filtered_headerdev
= strjoin("header=", headerfile
);
617 filtered_headerdev
= strjoin(filtered_headerspec
, ",header=", headerfile
);
619 if (!filtered_headerdev
)
622 filtered_headerdev
= TAKE_PTR(filtered_headerspec
);
624 *ret_filtered_headerdev_options
= TAKE_PTR(filtered_headerdev
);
625 *ret_headerdev
= TAKE_PTR(headerdev
);
630 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
631 _cleanup_free_
char *uuid
= NULL
, *uuid_value
= NULL
;
635 if (streq(key
, "luks")) {
637 r
= value
? parse_boolean(value
) : 1;
639 log_warning("Failed to parse luks= kernel command line switch %s. Ignoring.", value
);
643 } else if (streq(key
, "luks.crypttab")) {
645 r
= value
? parse_boolean(value
) : 1;
647 log_warning("Failed to parse luks.crypttab= kernel command line switch %s. Ignoring.", value
);
649 arg_read_crypttab
= r
;
651 } else if (streq(key
, "luks.uuid")) {
653 if (proc_cmdline_value_missing(key
, value
))
656 d
= get_crypto_device(startswith(value
, "luks-") ?: value
);
660 d
->create
= arg_allow_list
= true;
662 } else if (streq(key
, "luks.options")) {
663 _cleanup_free_
char *headerdev
= NULL
, *filtered_headerdev_options
= NULL
;
665 if (proc_cmdline_value_missing(key
, value
))
668 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
670 return free_and_strdup(&arg_default_options
, value
) < 0 ? log_oom() : 0;
672 if (warn_uuid_invalid(uuid
, key
))
675 d
= get_crypto_device(uuid
);
679 r
= filter_header_device(uuid_value
, &headerdev
, &filtered_headerdev_options
);
683 free_and_replace(d
->options
, filtered_headerdev_options
);
684 free_and_replace(d
->headerdev
, headerdev
);
685 } else if (streq(key
, "luks.key")) {
687 _cleanup_free_
char *keyfile
= NULL
, *keydev
= NULL
;
690 if (proc_cmdline_value_missing(key
, value
))
693 n
= strspn(value
, ALPHANUMERICAL
"-");
694 if (value
[n
] != '=') {
695 if (free_and_strdup(&arg_default_keyfile
, value
) < 0)
700 uuid
= strndup(value
, n
);
704 if (warn_uuid_invalid(uuid
, key
))
707 d
= get_crypto_device(uuid
);
711 keyspec
= value
+ n
+ 1;
712 r
= split_locationspec(keyspec
, &keyfile
, &keydev
);
716 free_and_replace(d
->keyfile
, keyfile
);
717 free_and_replace(d
->keydev
, keydev
);
718 } else if (streq(key
, "luks.data")) {
720 _cleanup_free_
char *datadev
= NULL
;
722 if (proc_cmdline_value_missing(key
, value
))
725 n
= strspn(value
, ALPHANUMERICAL
"-");
726 if (value
[n
] != '=') {
727 log_warning("Failed to parse luks.data= kernel command line switch. UUID is invalid, ignoring.");
731 uuid
= strndup(value
, n
);
735 if (warn_uuid_invalid(uuid
, key
))
738 d
= get_crypto_device(uuid
);
742 datadev
= fstab_node_to_udev_node(value
+ n
+ 1);
746 free_and_replace(d
->datadev
, datadev
);
747 } else if (streq(key
, "luks.name")) {
749 if (proc_cmdline_value_missing(key
, value
))
752 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
754 d
= get_crypto_device(uuid
);
758 d
->create
= arg_allow_list
= true;
760 free_and_replace(d
->name
, uuid_value
);
762 log_warning("Failed to parse luks name switch %s. Ignoring.", value
);
768 static int add_crypttab_devices(void) {
769 _cleanup_fclose_
FILE *f
= NULL
;
770 unsigned crypttab_line
= 0;
773 if (!arg_read_crypttab
)
776 r
= fopen_unlocked(arg_crypttab
, "re", &f
);
779 log_error_errno(errno
, "Failed to open %s: %m", arg_crypttab
);
784 _cleanup_free_
char *line
= NULL
, *name
= NULL
, *device
= NULL
, *keyspec
= NULL
, *options
= NULL
,
785 *keyfile
= NULL
, *keydev
= NULL
, *headerdev
= NULL
, *filtered_header
= NULL
;
786 crypto_device
*d
= NULL
;
790 r
= read_line(f
, LONG_LINE_MAX
, &line
);
792 return log_error_errno(r
, "Failed to read %s: %m", arg_crypttab
);
799 if (IN_SET(l
[0], 0, '#'))
802 k
= sscanf(l
, "%ms %ms %ms %ms", &name
, &device
, &keyspec
, &options
);
803 if (k
< 2 || k
> 4) {
804 log_error("Failed to parse %s:%u, ignoring.", arg_crypttab
, crypttab_line
);
808 uuid
= startswith(device
, "UUID=");
810 uuid
= path_startswith(device
, "/dev/disk/by-uuid/");
812 uuid
= startswith(name
, "luks-");
814 d
= hashmap_get(arg_disks
, uuid
);
816 if (arg_allow_list
&& !d
) {
817 log_info("Not creating device '%s' because it was not specified on the kernel command line.", name
);
821 r
= split_locationspec(keyspec
, &keyfile
, &keydev
);
825 if (options
&& (!d
|| !d
->options
)) {
826 r
= filter_header_device(options
, &headerdev
, &filtered_header
);
829 free_and_replace(options
, filtered_header
);
832 r
= create_disk(name
,
836 (d
&& d
->options
) ? d
->headerdev
: headerdev
,
837 (d
&& d
->options
) ? d
->options
: options
,
849 static int add_proc_cmdline_devices(void) {
853 HASHMAP_FOREACH(d
, arg_disks
) {
854 _cleanup_free_
char *device
= NULL
;
860 d
->name
= strjoin("luks-", d
->uuid
);
865 device
= strjoin("UUID=", d
->uuid
);
869 r
= create_disk(d
->name
,
870 d
->datadev
?: device
,
871 d
->keyfile
?: arg_default_keyfile
,
874 d
->options
?: arg_default_options
,
883 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(crypt_device_hash_ops
, char, string_hash_func
, string_compare_func
,
884 crypto_device
, crypt_device_free
);
886 static int run(const char *dest
, const char *dest_early
, const char *dest_late
) {
889 assert_se(arg_dest
= dest
);
891 arg_crypttab
= getenv("SYSTEMD_CRYPTTAB") ?: "/etc/crypttab";
892 arg_runtime_directory
= getenv("RUNTIME_DIRECTORY") ?: "/run/systemd/cryptsetup";
894 arg_disks
= hashmap_new(&crypt_device_hash_ops
);
898 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, PROC_CMDLINE_STRIP_RD_PREFIX
);
900 return log_warning_errno(r
, "Failed to parse kernel command line: %m");
905 r
= add_crypttab_devices();
909 r
= add_proc_cmdline_devices();
916 DEFINE_MAIN_GENERATOR_FUNCTION(run
);