[systemd-devel] [PATCH] cryptsetup-generator: support rd.luks.key=keyfile:keyfile_device

Jan Synacek jsynacek at redhat.com
Fri Feb 20 01:56:42 PST 2015


To be more consistent with how dracut parses rd.luks.key, it is now
allowed to specified it in the format "keyfile[:keyfile_device]".

Should keyfile_device be provided, it needs to be in "UUID=uuid-here"
format. Also, keyfile path is then treated relatively to the root of the
keyfile device.

If no keyfile_device appears on the command line, keyfile is then
treated as an absolute path.

Examples:

rd.luks.key=/etc/key/secret-partition.key

The keyfile is treated as an absolute path.

rd.luks.key=/root.key:UUID=dead-beef

First, the device UUID=dead-beef is temporarily mounted in /mnt and the
absolute path to the keyfile is constructed as /mnt/root.key.
---
 src/cryptsetup/cryptsetup-generator.c | 163 +++++++++++++++++++++++++++++++---
 1 file changed, 150 insertions(+), 13 deletions(-)

diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 05061c0..3590787 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -43,6 +43,12 @@ typedef struct crypto_device {
         bool create;
 } crypto_device;
 
+typedef struct key_device {
+        const crypto_device *device;
+        char *keyfile;
+        char *name;
+} key_device;
+
 static const char *arg_dest = "/tmp";
 static bool arg_enabled = true;
 static bool arg_read_crypttab = true;
@@ -50,6 +56,39 @@ static bool arg_whitelist = false;
 static Hashmap *arg_disks = NULL;
 static char *arg_default_options = NULL;
 static char *arg_default_keyfile = NULL;
+static key_device *arg_key_device = NULL;
+
+static char *crypt_service_name_build(const char *name)
+{
+        _cleanup_free_ char *e = NULL;
+
+        e = unit_name_escape(name);
+        if (!e)
+                return e;
+
+        return unit_name_build("systemd-cryptsetup", e, ".service");
+}
+
+static key_device *get_key_device(void)
+{
+        key_device *d;
+
+        if (arg_key_device)
+                return arg_key_device;
+
+        d = new0(struct key_device, 1);
+        if (!d)
+                return NULL;
+
+        arg_key_device = d;
+        return arg_key_device;
+}
+
+static void free_key_device(key_device *kd)
+{
+        free(kd->keyfile);
+        free(kd->name);
+}
 
 static int create_disk(
                 const char *name,
@@ -77,11 +116,7 @@ static int create_disk(
                 return -EINVAL;
         }
 
-        e = unit_name_escape(name);
-        if (!e)
-                return log_oom();
-
-        n = unit_name_build("systemd-cryptsetup", e, ".service");
+        n = crypt_service_name_build(name);
         if (!n)
                 return log_oom();
 
@@ -233,6 +268,76 @@ static int create_disk(
         return 0;
 }
 
+static int create_temporary_mount(void)
+{
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *p = NULL, *n = NULL, *c = NULL, *wants_dir = NULL, *to = NULL, *u = NULL;
+        const char *m = "mnt.mount";
+        key_device *kd;
+
+        kd = get_key_device();
+        if (!kd)
+                return log_oom();
+
+        /* no uuid where we should search for the key was specified */
+        if (!kd->name)
+                return 0;
+
+
+        if (!kd->device) {
+                log_warning("No rd.luks.uuid specified. Can't generate a temporary mount unit");
+                return 0;
+        }
+
+        p = strjoin(arg_dest, "/", m, NULL);
+        if (!p)
+                return log_oom();
+
+
+        f = fopen(p, "wxe");
+        if (!f)
+                return log_error_errno(errno, "Failed to open %s: %m", p);
+
+        fprintf(f, "# Automatically generated by systemd-cryptsetup-generator\n\n"
+                "[Unit]\n"
+                "Description=Temporary keyfile mount point.\n"
+                "JobTimeoutSec=30\n");
+
+        n = strjoin("luks-", kd->device->uuid, NULL);
+        if (!n)
+                return log_oom();
+
+        c = crypt_service_name_build(n);
+        if (!c)
+                return log_oom();
+
+        u = fstab_node_to_udev_node(kd->name);
+        if (!u)
+                return log_oom();
+
+        fprintf(f, "Before=%s\n\n"
+                "[Mount]\n"
+                "What=%s\n"
+                "Where=/mnt\n",
+                c, u);
+
+        wants_dir = strjoin(arg_dest, "/", c, ".wants", NULL);
+        if (!wants_dir)
+                return log_oom();
+
+        to = strjoin(wants_dir, "/", m, NULL);
+        if (!to)
+                return log_oom();
+
+        if (mkdir_safe(wants_dir, 0700, 0, 0) < 0)
+                log_error("Failed to create %s: %m", wants_dir);
+
+        if (symlink("../mnt.mount", to) < 0)
+                return log_error_errno(errno, "Failed to create symlink %s: %m", to);
+
+        return 0;
+}
+
 static void free_arg_disks(void) {
         crypto_device *d;
 
@@ -282,6 +387,7 @@ static crypto_device *get_crypto_device(const char *uuid) {
 static int parse_proc_cmdline_item(const char *key, const char *value) {
         int r;
         crypto_device *d;
+        key_device *kd;
         _cleanup_free_ char *uuid = NULL, *uuid_value = NULL;
 
         if (STR_IN_SET(key, "luks", "rd.luks") && value) {
@@ -308,6 +414,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
 
                 d->create = arg_whitelist = true;
 
+                kd = get_key_device();
+                if (!kd)
+                        return log_oom();
+
+                kd->device = d;
+
         } else if (STR_IN_SET(key, "luks.options", "rd.luks.options") && value) {
 
                 r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
@@ -324,16 +436,37 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
 
         } else if (STR_IN_SET(key, "luks.key", "rd.luks.key") && value) {
 
-                r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
-                if (r == 2) {
-                        d = get_crypto_device(uuid);
-                        if (!d)
+                char **parts = NULL;
+                int l;
+
+                parts = strv_split(value, ":");
+                if (!parts)
+                        return log_oom();
+                l = strv_length(parts);
+
+                if (l > 1) {
+                        kd = get_key_device();
+                        if (!kd)
                                 return log_oom();
 
-                        free(d->keyfile);
-                        d->keyfile = uuid_value;
-                        uuid_value = NULL;
-                } else if (free_and_strdup(&arg_default_keyfile, value))
+                        kd->keyfile = strdup(parts[0]);
+                        if (!kd->keyfile)
+                                return log_oom();
+
+                        if (!startswith(parts[1], "UUID="))
+                                log_warning("Keyfile device should start with \"UUID=\"");
+                        else {
+                                kd->name = strdup(parts[1]);
+                                if (!kd->name)
+                                        return log_oom();
+
+                                value = strjoin("/mnt", parts[0], NULL);
+                                if (!value)
+                                        return log_oom();
+                        }
+                }
+
+                if (free_and_strdup(&arg_default_keyfile, value) < 0)
                         return log_oom();
 
         } else if (STR_IN_SET(key, "luks.name", "rd.luks.name") && value) {
@@ -504,12 +637,16 @@ int main(int argc, char *argv[]) {
         if (add_proc_cmdline_devices() < 0)
                 goto cleanup;
 
+        if (create_temporary_mount() < 0)
+                goto cleanup;
+
         r = EXIT_SUCCESS;
 
 cleanup:
         free_arg_disks();
         free(arg_default_options);
         free(arg_default_keyfile);
+        free_key_device(arg_key_device);
 
         return r;
 }
-- 
2.1.0



More information about the systemd-devel mailing list