From 008fd4f9d46c1b7ea4633d92603544299f700621 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Tue, 21 Jul 2020 10:12:27 +0200 Subject: [PATCH 1/6] cryptsetup-generator: use proper constant for uuid alphabet --- src/cryptsetup/cryptsetup-generator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index 3ff50f4b6b..dc80423eca 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -570,7 +570,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (proc_cmdline_value_missing(key, value)) return 0; - n = strspn(value, LETTERS DIGITS "-"); + n = strspn(value, ALPHANUMERICAL "-"); if (value[n] != '=') { if (free_and_strdup(&arg_default_keyfile, value) < 0) return log_oom(); From eb7d9aa3919709a0cba8916145786721f96cc27f Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Fri, 21 Feb 2020 12:45:33 +0100 Subject: [PATCH 2/6] cryptsetup-generator: rename and extend device mount helpers. Those functions will be used later also for (u)mounting LUKS header devices. --- src/cryptsetup/cryptsetup-generator.c | 47 +++++++++++++++++---------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index dc80423eca..3b436ec967 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -99,11 +99,13 @@ static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_key return 0; } -static int generate_keydev_mount( +static int generate_device_mount( const char *name, - const char *keydev, - const char *keydev_timeout, + const char *device, + const char *type_prefix, /* "keydev" or "headerdev" */ + const char *device_timeout, bool canfail, + bool readonly, char **unit, char **mount) { @@ -113,7 +115,7 @@ static int generate_keydev_mount( usec_t timeout_us; assert(name); - assert(keydev); + assert(device); assert(unit); assert(mount); @@ -129,7 +131,7 @@ static int generate_keydev_mount( if (!name_escaped) return -ENOMEM; - where = strjoin(arg_runtime_directory, "/keydev-", name_escaped); + where = strjoin(arg_runtime_directory, "/", type_prefix, "-", name_escaped); if (!where) return -ENOMEM; @@ -151,23 +153,23 @@ static int generate_keydev_mount( "[Mount]\n" "What=%s\n" "Where=%s\n" - "Options=ro%s\n", keydev, where, canfail ? ",nofail" : ""); + "Options=%s%s\n", device, where, readonly ? "ro" : "rw", canfail ? ",nofail" : ""); - if (keydev_timeout) { - r = parse_sec_fix_0(keydev_timeout, &timeout_us); + if (device_timeout) { + r = parse_sec_fix_0(device_timeout, &timeout_us); if (r >= 0) { - r = unit_name_from_path(keydev, ".device", &device_unit); + r = unit_name_from_path(device, ".device", &device_unit); if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); r = write_drop_in_format(arg_dest, device_unit, 90, "device-timeout", "# Automatically generated by systemd-cryptsetup-generator \n\n" - "[Unit]\nJobRunningTimeoutSec=%s", keydev_timeout); + "[Unit]\nJobRunningTimeoutSec=%s", device_timeout); if (r < 0) return log_error_errno(r, "Failed to write device drop-in: %m"); } else - log_warning_errno(r, "Failed to parse %s, ignoring: %m", keydev_timeout); + log_warning_errno(r, "Failed to parse %s, ignoring: %m", device_timeout); } @@ -181,8 +183,9 @@ static int generate_keydev_mount( return 0; } -static int generate_keydev_umount(const char *name, - const char *keydev_mount, +static int generate_device_umount(const char *name, + const char *device_mount, + const char *type_prefix, /* "keydev" or "headerdev" */ char **ret_umount_unit) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *u = NULL, *name_escaped = NULL, *mount = NULL; @@ -195,11 +198,11 @@ static int generate_keydev_umount(const char *name, if (!name_escaped) return -ENOMEM; - u = strjoin("keydev-", name_escaped, "-umount.service"); + u = strjoin(type_prefix, "-", name_escaped, "-umount.service"); if (!u) return -ENOMEM; - r = unit_name_from_path(keydev_mount, ".mount", &mount); + r = unit_name_from_path(device_mount, ".mount", &mount); if (r < 0) return r; @@ -212,7 +215,7 @@ static int generate_keydev_umount(const char *name, "DefaultDependencies=no\n" "After=%s\n\n" "[Service]\n" - "ExecStart=-" UMOUNT_PATH " %s\n\n", mount, keydev_mount); + "ExecStart=-" UMOUNT_PATH " %s\n\n", mount, device_mount); r = fflush_and_check(f); if (r < 0) @@ -358,11 +361,19 @@ static int create_disk( if (keydev) { _cleanup_free_ char *unit = NULL, *umount_unit = NULL; - r = generate_keydev_mount(name, keydev, keyfile_timeout_value, keyfile_can_timeout > 0, &unit, &keydev_mount); + r = generate_device_mount( + name, + keydev, + "keydev", + keyfile_timeout_value, + /* canfail = */ keyfile_can_timeout > 0, + /* readonly= */ true, + &unit, + &keydev_mount); if (r < 0) return log_error_errno(r, "Failed to generate keydev mount unit: %m"); - r = generate_keydev_umount(name, keydev_mount, &umount_unit); + r = generate_device_umount(name, keydev_mount, "keydev", &umount_unit); if (r < 0) return log_error_errno(r, "Failed to generate keydev umount unit: %m"); From c3ee5b34f50f2d779bc4a848c650b8258c479528 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Wed, 22 Jul 2020 12:26:18 +0200 Subject: [PATCH 3/6] cryptsetup-generator: Add warn_uuid_invalid helper --- src/cryptsetup/cryptsetup-generator.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index 3b436ec967..4710b66653 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -526,6 +526,17 @@ static crypto_device *get_crypto_device(const char *uuid) { return d; } +static bool warn_uuid_invalid(const char *uuid, const char *key) { + assert(key); + + if (!id128_is_valid(uuid)) { + log_warning("Failed to parse %s= kernel command line switch. UUID is invalid, ignoring.", key); + return true; + } + + return false; +} + static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { _cleanup_free_ char *uuid = NULL, *uuid_value = NULL; crypto_device *d; @@ -592,10 +603,8 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (!uuid) return log_oom(); - if (!id128_is_valid(uuid)) { - log_warning("Failed to parse luks.key= kernel command line switch. UUID is invalid, ignoring."); + if (warn_uuid_invalid(uuid, key)) return 0; - } d = get_crypto_device(uuid); if (!d) From fc6f1ad1211e7add81f6f14f09d141e1fe7d09a0 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Tue, 1 Sep 2020 10:51:33 +0200 Subject: [PATCH 4/6] cryptsetup-generator: rename split_keyspec to split_locationspec To be used later not only for splitting key specifications --- src/cryptsetup/cryptsetup-generator.c | 50 +++++++++++++-------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index 4710b66653..4857f8ae15 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -48,53 +48,53 @@ STATIC_DESTRUCTOR_REGISTER(arg_disks, hashmap_freep); STATIC_DESTRUCTOR_REGISTER(arg_default_options, freep); STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile, freep); -static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_keydev) { - _cleanup_free_ char *keyfile = NULL, *keydev = NULL; +static int split_locationspec(const char *locationspec, char **ret_file, char **ret_device) { + _cleanup_free_ char *file = NULL, *device = NULL; const char *c; - assert(ret_keyfile); - assert(ret_keydev); + assert(ret_file); + assert(ret_device); - if (!keyspec) { - *ret_keyfile = *ret_keydev = NULL; + if (!locationspec) { + *ret_file = *ret_device = NULL; return 0; } - c = strrchr(keyspec, ':'); + c = strrchr(locationspec, ':'); if (c) { - /* The keydev part has to be either an absolute path to device node (/dev/something, + /* The device part has to be either an absolute path to device node (/dev/something, * /dev/foo/something, or even possibly /dev/foo/something:part), or a fstab device - * specification starting with LABEL= or similar. The keyfile part has the same syntax. + * specification starting with LABEL= or similar. The file part has the same syntax. * - * Let's try to guess if the second part looks like a keydev specification, or just part of a + * Let's try to guess if the second part looks like a device specification, or just part of a * filename with a colon. fstab_node_to_udev_node() will convert the fstab device syntax to * an absolute path. If we didn't get an absolute path, assume that it is just part of the - * first keyfile argument. */ + * first file argument. */ - keydev = fstab_node_to_udev_node(c + 1); - if (!keydev) + device = fstab_node_to_udev_node(c + 1); + if (!device) return log_oom(); - if (path_is_absolute(keydev)) - keyfile = strndup(keyspec, c-keyspec); + if (path_is_absolute(device)) + file = strndup(locationspec, c-locationspec); else { - log_debug("Keyspec argument contains a colon, but \"%s\" doesn't look like a device specification.\n" + log_debug("Location specification argument contains a colon, but \"%s\" doesn't look like a device specification.\n" "Assuming that \"%s\" is a single device specification.", - c + 1, keyspec); - keydev = mfree(keydev); + c + 1, locationspec); + device = mfree(device); c = NULL; } } if (!c) - /* No keydev specified */ - keyfile = strdup(keyspec); + /* No device specified */ + file = strdup(locationspec); - if (!keyfile) + if (!file) return log_oom(); - *ret_keyfile = TAKE_PTR(keyfile); - *ret_keydev = TAKE_PTR(keydev); + *ret_file = TAKE_PTR(file); + *ret_device = TAKE_PTR(device); return 0; } @@ -611,7 +611,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat return log_oom(); keyspec = value + n + 1; - r = split_keyspec(keyspec, &keyfile, &keydev); + r = split_locationspec(keyspec, &keyfile, &keydev); if (r < 0) return r; @@ -697,7 +697,7 @@ static int add_crypttab_devices(void) { continue; } - r = split_keyspec(keyspec, &keyfile, &keydev); + r = split_locationspec(keyspec, &keyfile, &keydev); if (r < 0) return r; From a8574d00552dc9f3012a3f84ab2bcac5fb6d7e7b Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Wed, 19 Feb 2020 12:39:26 +0100 Subject: [PATCH 5/6] cryptsetup-generator: add detached LUKS header support Adds support for LUKS detached header device on kernel command line. It's introduced via extension to existing luks.options 'header=' argument beyond colon (see examples below). If LUKS header device is specified it's expected to contain filesystem with LUKS header image on a path specified in the first part of header specification. The second parameter 'luks.data' specifies LUKS data device supposed to be paired with detached LUKS header (note that encrypted LUKS data device with detached header is unrecognisable by standard blkid probe). This adds support for LUKS encrypted rootfs partition with detached header. It can also be used for initializing online LUKS2 encryption of data device. Examples: luks.data==/dev/sdz luks.data==/dev/vg/lv luks.data==/dev/mapper/lv luks.data==PARTUUID= luks.data==PARTLABEL= luks.options==header=/header/path:UUID= luks.options==header=/header/path:PARTUUID= luks.options==header=/header/path:PARTLABEL= luks.options==header=/header/path:LABEL= luks.options==header=/header/path:/dev/sdx luks.options==header=/header/path:/dev/vg/lv The '/header/path' is considered to be relative location within filesystem residing on the header device specified beyond colon character --- man/systemd-cryptsetup-generator.xml | 80 +++++++++++--- src/cryptsetup/cryptsetup-generator.c | 151 ++++++++++++++++++++++++-- 2 files changed, 207 insertions(+), 24 deletions(-) diff --git a/man/systemd-cryptsetup-generator.xml b/man/systemd-cryptsetup-generator.xml index e3c17d64d8..cb18db246b 100644 --- a/man/systemd-cryptsetup-generator.xml +++ b/man/systemd-cryptsetup-generator.xml @@ -105,6 +105,9 @@ LUKS device given by the UUID appear under the provided name. + This parameter is the analogue of the first crypttab + 5 field volume-name. + rd.luks.name= is honored only by initial RAM disk (initrd) while luks.name= is honored by both the main system and the initrd. @@ -112,20 +115,30 @@ - luks.options= - rd.luks.options= + luks.data= + rd.luks.data= - Takes a LUKS super block UUID followed by an - = and a string of options separated by - commas as argument. This will override the options for the - given UUID. - If only a list of options, without an UUID, is - specified, they apply to any UUIDs not specified elsewhere, - and without an entry in - /etc/crypttab. - rd.luks.options= is honored only by initial - RAM disk (initrd) while luks.options= is - honored by both the main system and the initrd. + Takes a LUKS super block UUID followed by a = and a block device + specification for device hosting encrypted data. + + For those entries specified with rd.luks.uuid= or + luks.uuid=, the data device will be set to the one specified by + rd.luks.data= or luks.data= of the corresponding UUID. + + LUKS data device parameter is usefull for specifying encrypted data devices with detached headers specified in + luks.options entry containing header= argument. For example, + rd.luks.uuid=b40f1abf-2a53-400a-889a-2eccc27eaa40 + rd.luks.options=b40f1abf-2a53-400a-889a-2eccc27eaa40=header=/path/to/luks.hdr + rd.luks.data=b40f1abf-2a53-400a-889a-2eccc27eaa40=/dev/sdx. + Hence, in this case, we will attempt to unlock LUKS device assembled from data device /dev/sdx + and LUKS header (metadata) put in /path/to/luks.hdr file. This syntax is for now + only supported on a per-device basis, i.e. you have to specify LUKS device UUID. + + This parameter is the analogue of the second crypttab + 5 field encrypted-device. + + rd.luks.data= is honored only by initial RAM disk (initrd) while + luks.data= is honored by both the main system and the initrd. @@ -157,6 +170,9 @@ This syntax is for now only supported on a per-device basis, i.e. you have to specify LUKS device UUID. + This parameter is the analogue of the third crypttab + 5 field key-file. + rd.luks.key= is honored only by initial RAM disk (initrd) while @@ -165,6 +181,44 @@ the initrd. + + + luks.options= + rd.luks.options= + + Takes a LUKS super block UUID followed by an + = and a string of options separated by + commas as argument. This will override the options for the + given UUID. + If only a list of options, without an UUID, is + specified, they apply to any UUIDs not specified elsewhere, + and without an entry in + /etc/crypttab. + + This parameter is the analogue of the fourth crypttab + 5 field options. + + It is possible to specify an external device which + should be mounted before we attempt to unlock the LUKS device. + systemd-cryptsetup will assemble LUKS device by combining + data device specified in luks.data with + detached LUKS header found in header= + argument. For example, + rd.luks.uuid=b40f1abf-2a53-400a-889a-2eccc27eaa40 + rd.luks.options=b40f1abf-2a53-400a-889a-2eccc27eaa40=header=/luks.hdr:LABEL=hdrdev + rd.luks.data=b40f1abf-2a53-400a-889a-2eccc27eaa40=/dev/sdx. + Hence, in this case, we will attempt to mount file system + residing on the block device with label hdrdev, and look + for luks.hdr on that file system. Said header will be used + to unlock (decrypt) encrypted data stored on /dev/sdx. + This syntax is for now only supported on a per-device basis, + i.e. you have to specify LUKS device UUID. + + rd.luks.options= is honored only by initial + RAM disk (initrd) while luks.options= is + honored by both the main system and the initrd. + + diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index 4857f8ae15..ea9965d6c4 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -29,6 +29,8 @@ typedef struct crypto_device { char *uuid; char *keyfile; char *keydev; + char *headerdev; + char *datadev; char *name; char *options; bool create; @@ -277,13 +279,14 @@ static int create_disk( const char *device, const char *password, const char *keydev, + const char *headerdev, const char *options, const char *source) { _cleanup_free_ char *n = NULL, *d = NULL, *u = NULL, *e = NULL, *keydev_mount = NULL, *keyfile_timeout_value = NULL, *filtered = NULL, *u_escaped = NULL, *name_escaped = NULL, *header_path = NULL, *password_buffer = NULL, - *tmp_fstype = NULL; + *tmp_fstype = NULL, *filtered_header = NULL, *headerdev_mount = NULL; _cleanup_fclose_ FILE *f = NULL; const char *dmname; bool noauto, nofail, swap, netdev, attach_in_initrd; @@ -302,7 +305,12 @@ static int create_disk( if (keyfile_can_timeout < 0) return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m"); - detached_header = fstab_filter_options(options, "header\0", NULL, &header_path, NULL); + detached_header = fstab_filter_options( + options, + "header\0", + NULL, + &header_path, + headerdev ? &filtered_header : NULL); if (detached_header < 0) return log_error_errno(detached_header, "Failed to parse header= option value: %m"); @@ -399,6 +407,55 @@ static int create_disk( } } + if (headerdev) { + _cleanup_free_ char *unit = NULL, *umount_unit = NULL, *p = NULL; + + r = generate_device_mount( + name, + headerdev, + "headerdev", + NULL, + /* canfail= */ false, /* header is always necessary */ + /* readonly= */ false, /* LUKS2 recovery requires rw header access */ + &unit, + &headerdev_mount); + if (r < 0) + return log_error_errno(r, "Failed to generate header device mount unit: %m"); + + r = generate_device_umount(name, headerdev_mount, "headerdev", &umount_unit); + if (r < 0) + return log_error_errno(r, "Failed to generate header device umount unit: %m"); + + p = path_join(headerdev_mount, header_path); + if (!p) + return log_oom(); + + free_and_replace(header_path, p); + + if (isempty(filtered_header)) + p = strjoin("header=", header_path); + else + p = strjoin(filtered_header, ",header=", header_path); + + if (!p) + return log_oom(); + + free_and_replace(filtered_header, p); + options = filtered_header; + + fprintf(f, "After=%s\n" + "Requires=%s\n", unit, unit); + + if (umount_unit) { + fprintf(f, + "Wants=%s\n" + "Before=%s\n", + umount_unit, + umount_unit + ); + } + } + if (!nofail) fprintf(f, "Before=%s\n", @@ -411,7 +468,7 @@ static int create_disk( } /* Check if a header option was specified */ - if (detached_header > 0) { + if (detached_header > 0 && !headerdev) { r = print_dependencies(f, header_path); if (r < 0) return r; @@ -537,6 +594,41 @@ static bool warn_uuid_invalid(const char *uuid, const char *key) { return false; } +static int filter_header_device(const char *options, + char **ret_headerdev, + char **ret_filtered_headerdev_options) { + int r; + _cleanup_free_ char *headerfile = NULL, *headerdev = NULL, *headerspec = NULL, + *filtered_headerdev = NULL, *filtered_headerspec = NULL; + + assert(ret_headerdev); + assert(ret_filtered_headerdev_options); + + r = fstab_filter_options(options, "header\0", NULL, &headerspec, &filtered_headerspec); + if (r < 0) + return log_error_errno(r, "Failed to parse header= option value: %m"); + + if (r > 0) { + r = split_locationspec(headerspec, &headerfile, &headerdev); + if (r < 0) + return r; + + if (isempty(filtered_headerspec)) + filtered_headerdev = strjoin("header=", headerfile); + else + filtered_headerdev = strjoin(filtered_headerspec, ",header=", headerfile); + + if (!filtered_headerdev) + return log_oom(); + } else + filtered_headerdev = TAKE_PTR(filtered_headerspec); + + *ret_filtered_headerdev_options = TAKE_PTR(filtered_headerdev); + *ret_headerdev = TAKE_PTR(headerdev); + + return 0; +} + static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { _cleanup_free_ char *uuid = NULL, *uuid_value = NULL; crypto_device *d; @@ -570,20 +662,28 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat d->create = arg_allow_list = true; } else if (streq(key, "luks.options")) { + _cleanup_free_ char *headerdev = NULL, *filtered_headerdev_options = NULL; if (proc_cmdline_value_missing(key, value)) return 0; r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value); - if (r == 2) { - d = get_crypto_device(uuid); - if (!d) - return log_oom(); + if (r != 2) + return free_and_strdup(&arg_default_options, value) < 0 ? log_oom() : 0; - free_and_replace(d->options, uuid_value); - } else if (free_and_strdup(&arg_default_options, value) < 0) + if (warn_uuid_invalid(uuid, key)) + return 0; + + d = get_crypto_device(uuid); + if (!d) return log_oom(); + r = filter_header_device(uuid_value, &headerdev, &filtered_headerdev_options); + if (r < 0) + return r; + + free_and_replace(d->options, filtered_headerdev_options); + free_and_replace(d->headerdev, headerdev); } else if (streq(key, "luks.key")) { size_t n; _cleanup_free_ char *keyfile = NULL, *keydev = NULL; @@ -617,7 +717,35 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat free_and_replace(d->keyfile, keyfile); free_and_replace(d->keydev, keydev); + } else if (streq(key, "luks.data")) { + size_t n; + _cleanup_free_ char *datadev = NULL; + if (proc_cmdline_value_missing(key, value)) + return 0; + + n = strspn(value, ALPHANUMERICAL "-"); + if (value[n] != '=') { + log_warning("Failed to parse luks.data= kernel command line switch. UUID is invalid, ignoring."); + return 0; + } + + uuid = strndup(value, n); + if (!uuid) + return log_oom(); + + if (warn_uuid_invalid(uuid, key)) + return 0; + + d = get_crypto_device(uuid); + if (!d) + return log_oom(); + + datadev = fstab_node_to_udev_node(value + n + 1); + if (!datadev) + return log_oom(); + + free_and_replace(d->datadev, datadev); } else if (streq(key, "luks.name")) { if (proc_cmdline_value_missing(key, value)) @@ -701,7 +829,7 @@ static int add_crypttab_devices(void) { if (r < 0) return r; - r = create_disk(name, device, keyfile, keydev, (d && d->options) ? d->options : options, arg_crypttab); + r = create_disk(name, device, keyfile, keydev, d ? d->headerdev : NULL, (d && d->options) ? d->options : options, arg_crypttab); if (r < 0) return r; @@ -733,9 +861,10 @@ static int add_proc_cmdline_devices(void) { return log_oom(); r = create_disk(d->name, - device, + d->datadev ?: device, d->keyfile ?: arg_default_keyfile, d->keydev, + d->headerdev, d->options ?: arg_default_options, "/proc/cmdline"); if (r < 0) From 13445d9775614367d521204d677c5775b5e53bea Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Mon, 24 Aug 2020 12:54:14 +0200 Subject: [PATCH 6/6] cryptsetup-generator: Add support for header device in crypttab --- man/crypttab.xml | 7 ++++++- src/cryptsetup/cryptsetup-generator.c | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/man/crypttab.xml b/man/crypttab.xml index ee54499bfe..2c0a8266a5 100644 --- a/man/crypttab.xml +++ b/man/crypttab.xml @@ -112,7 +112,12 @@ relevant for LUKS devices. See cryptsetup8 for possible values and the default value of this - option. + option. + + Optionally, the path may be followed by : and an fstab device specification + (e.g. starting with UUID= or similar); in which case, the path is relative to the + device file system root. The device gets mounted automatically for LUKS device activation duration only. + diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index ea9965d6c4..cd40cb4208 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -789,7 +789,8 @@ static int add_crypttab_devices(void) { } for (;;) { - _cleanup_free_ char *line = NULL, *name = NULL, *device = NULL, *keyspec = NULL, *options = NULL, *keyfile = NULL, *keydev = NULL; + _cleanup_free_ char *line = NULL, *name = NULL, *device = NULL, *keyspec = NULL, *options = NULL, + *keyfile = NULL, *keydev = NULL, *headerdev = NULL, *filtered_header = NULL; crypto_device *d = NULL; char *l, *uuid; int k; @@ -829,7 +830,20 @@ static int add_crypttab_devices(void) { if (r < 0) return r; - r = create_disk(name, device, keyfile, keydev, d ? d->headerdev : NULL, (d && d->options) ? d->options : options, arg_crypttab); + if (options && (!d || !d->options)) { + r = filter_header_device(options, &headerdev, &filtered_header); + if (r < 0) + return r; + free_and_replace(options, filtered_header); + } + + r = create_disk(name, + device, + keyfile, + keydev, + (d && d->options) ? d->headerdev : headerdev, + (d && d->options) ? d->options : options, + arg_crypttab); if (r < 0) return r;