]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cryptsetup: add keyfile-timeout to allow a keydev timeout and allow to fallback to... 13004/head
authorshinygold <10763595+shinygold@users.noreply.github.com>
Tue, 16 Jul 2019 11:06:16 +0000 (13:06 +0200)
committershinygold <10763595+shinygold@users.noreply.github.com>
Wed, 17 Jul 2019 12:00:29 +0000 (14:00 +0200)
src/cryptsetup/cryptsetup-generator.c
src/cryptsetup/cryptsetup.c

index 2197160c0fac65fa574ca832d2bc787fb21bc526..c51bb9ae189c362341b59bf7a2ec6998e29a69bb 100644 (file)
@@ -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;
         }
index 02f131086bd08d9898ca3c280a74eeefcf65b869..78732a0a577f994b2e63ab4cde7954f88c4ca193 100644 (file)
@@ -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="))) {