]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/cryptsetup/cryptsetup-generator.c
cryptsetup-generator: introduce basic keydev support
[thirdparty/systemd.git] / src / cryptsetup / cryptsetup-generator.c
index d8e65c0098e8de287454ac0c514f7074a5b74e49..24ccf0427341b90f3b6c4c946652d70cdee876a4 100644 (file)
@@ -24,6 +24,7 @@
 typedef struct crypto_device {
         char *uuid;
         char *keyfile;
+        char *keydev;
         char *name;
         char *options;
         bool create;
@@ -37,14 +38,71 @@ static Hashmap *arg_disks = NULL;
 static char *arg_default_options = NULL;
 static char *arg_default_keyfile = NULL;
 
+static int generate_keydev_mount(const char *name, const char *keydev, char **unit, char **mount) {
+        _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        assert(name);
+        assert(keydev);
+        assert(unit);
+        assert(mount);
+
+        r = mkdir_parents("/run/systemd/cryptsetup", 0755);
+        if (r < 0)
+                return r;
+
+        r = mkdir("/run/systemd/cryptsetup", 0700);
+        if (r < 0)
+                return r;
+
+        where = strjoin("/run/systemd/cryptsetup/keydev-", name);
+        if (!where)
+                return -ENOMEM;
+
+        r = mkdir(where, 0700);
+        if (r < 0)
+                return r;
+
+        r = unit_name_from_path(where, ".mount", &u);
+        if (r < 0)
+                return r;
+
+        r = generator_open_unit_file(arg_dest, NULL, u, &f);
+        if (r < 0)
+                return r;
+
+        what = fstab_node_to_udev_node(keydev);
+        if (!what)
+                return -ENOMEM;
+
+        fprintf(f,
+                "[Unit]\n"
+                "DefaultDependencies=no\n\n"
+                "[Mount]\n"
+                "What=%s\n"
+                "Where=%s\n"
+                "Options=ro\n", what, where);
+
+        r = fflush_and_check(f);
+        if (r < 0)
+                return r;
+
+        *unit = TAKE_PTR(u);
+        *mount = TAKE_PTR(where);
+
+        return 0;
+}
+
 static int create_disk(
                 const char *name,
                 const char *device,
+                const char *keydev,
                 const char *password,
                 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;
+                *filtered = NULL, *u_escaped = NULL, *password_escaped = NULL, *filtered_escaped = NULL, *name_escaped = NULL, *keydev_mount = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         const char *dmname;
         bool noauto, nofail, tmp, swap, netdev;
@@ -94,6 +152,9 @@ static int create_disk(
                         return log_oom();
         }
 
+        if (keydev && !password)
+                return log_error_errno(-EINVAL, "Keydev is specified, but path to the password file is missing: %m");
+
         r = generator_open_unit_file(arg_dest, NULL, n, &f);
         if (r < 0)
                 return r;
@@ -109,6 +170,20 @@ static int create_disk(
                 "After=%s\n",
                 netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");
 
+        if (keydev) {
+                _cleanup_free_ char *unit = NULL, *p = NULL;
+
+                r = generate_keydev_mount(name, keydev, &unit, &keydev_mount);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to generate keydev mount unit: %m");
+
+                p = prefix_root(keydev_mount, password_escaped);
+                if (!p)
+                        return log_oom();
+
+                free_and_replace(password_escaped, p);
+        }
+
         if (!nofail)
                 fprintf(f,
                         "Before=%s\n",
@@ -191,6 +266,11 @@ static int create_disk(
                         "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
                         name_escaped);
 
+        if (keydev)
+                fprintf(f,
+                        "ExecStartPost=" UMOUNT_PATH " %s\n\n",
+                        keydev_mount);
+
         r = fflush_and_check(f);
         if (r < 0)
                 return log_error_errno(r, "Failed to write unit file %s: %m", n);
@@ -226,6 +306,7 @@ static int create_disk(
 static void crypt_device_free(crypto_device *d) {
         free(d->uuid);
         free(d->keyfile);
+        free(d->keydev);
         free(d->name);
         free(d->options);
         free(d);
@@ -314,11 +395,27 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
 
                 r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
                 if (r == 2) {
+                        char *c;
+                        _cleanup_free_ char *keyfile = NULL, *keydev = NULL;
+
                         d = get_crypto_device(uuid);
                         if (!d)
                                 return log_oom();
 
-                        free_and_replace(d->keyfile, uuid_value);
+                        c = strrchr(uuid_value, ':');
+                        if (!c)
+                                /* No keydev specified */
+                                return free_and_replace(d->keyfile, uuid_value);
+
+                        *c = '\0';
+                        keyfile = strdup(uuid_value);
+                        keydev = strdup(++c);
+
+                        if (!keyfile || !keydev)
+                                return log_oom();
+
+                        free_and_replace(d->keyfile, keyfile);
+                        free_and_replace(d->keydev, keydev);
                 } else if (free_and_strdup(&arg_default_keyfile, value) < 0)
                         return log_oom();
 
@@ -399,7 +496,7 @@ static int add_crypttab_devices(void) {
                         continue;
                 }
 
-                r = create_disk(name, device, keyfile, (d && d->options) ? d->options : options);
+                r = create_disk(name, device, NULL, keyfile, (d && d->options) ? d->options : options);
                 if (r < 0)
                         return r;
 
@@ -439,7 +536,7 @@ static int add_proc_cmdline_devices(void) {
                 else
                         options = "timeout=0";
 
-                r = create_disk(d->name, device, d->keyfile ?: arg_default_keyfile, options);
+                r = create_disk(d->name, device, d->keydev, d->keyfile ?: arg_default_keyfile, options);
                 if (r < 0)
                         return r;
         }