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 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel