diff options
author | shinygold <10763595+shinygold@users.noreply.github.com> | 2019-07-16 13:06:16 +0200 |
---|---|---|
committer | shinygold <10763595+shinygold@users.noreply.github.com> | 2019-07-17 14:00:29 +0200 |
commit | 50d2eba27b9bfc77ef6b40e5721713846815418b (patch) | |
tree | 9722285ca1b0968871dc1184291ca577285ac523 /src/cryptsetup | |
parent | 4e1334512debb27f4a0c4a6da237a4b8d59fea08 (diff) | |
download | systemd-50d2eba27b9bfc77ef6b40e5721713846815418b.tar.gz |
cryptsetup: add keyfile-timeout to allow a keydev timeout and allow to fallback to a password if it fails.
Diffstat (limited to 'src/cryptsetup')
-rw-r--r-- | src/cryptsetup/cryptsetup-generator.c | 119 | ||||
-rw-r--r-- | src/cryptsetup/cryptsetup.c | 5 |
2 files changed, 89 insertions, 35 deletions
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index 2197160c0f..c51bb9ae18 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -46,10 +46,39 @@ STATIC_DESTRUCTOR_REGISTER(arg_disks, hashmap_freep); STATIC_DESTRUCTOR_REGISTER(arg_default_options, freep); STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile, freep); -static int generate_keydev_mount(const char *name, const char *keydev, char **unit, char **mount) { - _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *name_escaped = NULL; +static int split_keyspec(const char *keyspec, char **keyfile, char **keydev) { + _cleanup_free_ char *kfile = NULL, *kdev = NULL; + char *c; + + assert(keyspec); + assert(keyfile); + assert(keydev); + + c = strrchr(keyspec, ':'); + if (c) { + kfile = strndup(keyspec, c-keyspec); + kdev = strdup(c + 1); + if (!*kfile || !*kdev) + return log_oom(); + } else { + /* No keydev specified */ + kfile = strdup(keyspec); + kdev = NULL; + if (!*kfile) + return log_oom(); + } + + *keyfile = TAKE_PTR(kfile); + *keydev = TAKE_PTR(kdev); + + return 0; +} + +static int generate_keydev_mount(const char *name, const char *keydev, const char *keydev_timeout, bool canfail, char **unit, char **mount) { + _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *name_escaped = NULL, *device_unit = NULL; _cleanup_fclose_ FILE *f = NULL; int r; + usec_t timeout_us; assert(name); assert(keydev); @@ -94,7 +123,25 @@ static int generate_keydev_mount(const char *name, const char *keydev, char **un "[Mount]\n" "What=%s\n" "Where=%s\n" - "Options=ro\n", what, where); + "Options=ro%s\n", what, where, canfail ? ",nofail" : ""); + + if (keydev_timeout) { + r = parse_sec_fix_0(keydev_timeout, &timeout_us); + if (r >= 0) { + r = unit_name_from_path(what, ".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); + 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); + + } r = fflush_and_check(f); if (r < 0) @@ -150,16 +197,17 @@ static int print_dependencies(FILE *f, const char* device_path) { static int create_disk( const char *name, const char *device, - const char *keydev, const char *password, + const char *keydev, const char *options) { _cleanup_free_ char *n = NULL, *d = NULL, *u = NULL, *e = NULL, - *filtered = NULL, *u_escaped = NULL, *password_escaped = NULL, *filtered_escaped = NULL, *name_escaped = NULL, *keydev_mount = NULL, *header_path = NULL; + *keydev_mount = NULL, *keyfile_timeout_value = NULL, *password_escaped = NULL, + *filtered = NULL, *u_escaped = NULL, *filtered_escaped = NULL, *name_escaped = NULL, *header_path = NULL; _cleanup_fclose_ FILE *f = NULL; const char *dmname; bool noauto, nofail, tmp, swap, netdev; - int r, detached_header; + int r, detached_header, keyfile_can_timeout; assert(name); assert(device); @@ -170,6 +218,10 @@ static int create_disk( swap = fstab_test_option(options, "swap\0"); netdev = fstab_test_option(options, "_netdev\0"); + keyfile_can_timeout = fstab_filter_options(options, "keyfile-timeout\0", NULL, &keyfile_timeout_value, NULL); + 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); if (detached_header < 0) return log_error_errno(detached_header, "Failed to parse header= option value: %m"); @@ -203,12 +255,6 @@ static int create_disk( if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); - if (password) { - password_escaped = specifier_escape(password); - if (!password_escaped) - return log_oom(); - } - if (keydev && !password) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key device is specified, but path to the password file is missing."); @@ -228,10 +274,16 @@ static int create_disk( "After=%s\n", netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target"); + if (password) { + password_escaped = specifier_escape(password); + if (!password_escaped) + return log_oom(); + } + if (keydev) { _cleanup_free_ char *unit = NULL, *p = NULL; - r = generate_keydev_mount(name, keydev, &unit, &keydev_mount); + r = generate_keydev_mount(name, keydev, keyfile_timeout_value, keyfile_can_timeout > 0, &unit, &keydev_mount); if (r < 0) return log_error_errno(r, "Failed to generate keydev mount unit: %m"); @@ -240,6 +292,12 @@ static int create_disk( return log_oom(); free_and_replace(password_escaped, p); + + fprintf(f, "After=%s\n", unit); + if (keyfile_can_timeout > 0) + fprintf(f, "Wants=%s\n", unit); + else + fprintf(f, "Requires=%s\n", unit); } if (!nofail) @@ -247,7 +305,7 @@ static int create_disk( "Before=%s\n", netdev ? "remote-cryptsetup.target" : "cryptsetup.target"); - if (password) { + if (password && !keydev) { r = print_dependencies(f, password); if (r < 0) return r; @@ -314,7 +372,7 @@ static int create_disk( if (keydev) fprintf(f, - "ExecStartPost=" UMOUNT_PATH " %s\n\n", + "ExecStartPost=-" UMOUNT_PATH " %s\n\n", keydev_mount); r = fflush_and_check(f); @@ -433,7 +491,6 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat } else if (streq(key, "luks.key")) { size_t n; _cleanup_free_ char *keyfile = NULL, *keydev = NULL; - char *c; const char *keyspec; if (proc_cmdline_value_missing(key, value)) @@ -460,23 +517,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat return log_oom(); keyspec = value + n + 1; - c = strrchr(keyspec, ':'); - if (c) { - *c = '\0'; - keyfile = strdup(keyspec); - keydev = strdup(c + 1); - - if (!keyfile || !keydev) - return log_oom(); - } else { - /* No keydev specified */ - keyfile = strdup(keyspec); - if (!keyfile) - return log_oom(); - } + r = split_keyspec(keyspec, &keyfile, &keydev); + if (r < 0) + return r; free_and_replace(d->keyfile, keyfile); free_and_replace(d->keydev, keydev); + } else if (streq(key, "luks.name")) { if (proc_cmdline_value_missing(key, value)) @@ -520,7 +567,7 @@ static int add_crypttab_devices(void) { } for (;;) { - _cleanup_free_ char *line = NULL, *name = NULL, *device = NULL, *keyfile = NULL, *options = NULL; + _cleanup_free_ char *line = NULL, *name = NULL, *device = NULL, *keydev = NULL, *keyfile = NULL, *keyspec = NULL, *options = NULL; crypto_device *d = NULL; char *l, *uuid; int k; @@ -537,7 +584,7 @@ static int add_crypttab_devices(void) { if (IN_SET(l[0], 0, '#')) continue; - k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &keyfile, &options); + k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &keyspec, &options); if (k < 2 || k > 4) { log_error("Failed to parse /etc/crypttab:%u, ignoring.", crypttab_line); continue; @@ -556,7 +603,11 @@ static int add_crypttab_devices(void) { continue; } - r = create_disk(name, device, NULL, keyfile, (d && d->options) ? d->options : options); + r = split_keyspec(keyspec, &keyfile, &keydev); + if (r < 0) + return r; + + r = create_disk(name, device, keyfile, keydev, (d && d->options) ? d->options : options); if (r < 0) return r; @@ -596,7 +647,7 @@ static int add_proc_cmdline_devices(void) { else options = "timeout=0"; - r = create_disk(d->name, device, d->keydev, d->keyfile ?: arg_default_keyfile, options); + r = create_disk(d->name, device, d->keyfile ?: arg_default_keyfile, d->keydev, options); if (r < 0) return r; } diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 02f131086b..78732a0a57 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -81,7 +81,10 @@ static int parse_one_option(const char *option) { assert(option); /* Handled outside of this tool */ - if (STR_IN_SET(option, "noauto", "auto", "nofail", "fail", "_netdev")) + if (STR_IN_SET(option, "noauto", "auto", "nofail", "fail", "_netdev", "keyfile-timeout")) + return 0; + + if (startswith(option, "keyfile-timeout=")) return 0; if ((val = startswith(option, "cipher="))) { |