mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-24 21:34:08 +03:00
cryptsetup: add keyfile-timeout to allow a keydev timeout and allow to fallback to a password if it fails.
This commit is contained in:
parent
4e1334512d
commit
50d2eba27b
@ -46,10 +46,39 @@ STATIC_DESTRUCTOR_REGISTER(arg_disks, hashmap_freep);
|
|||||||
STATIC_DESTRUCTOR_REGISTER(arg_default_options, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_default_options, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile, freep);
|
||||||
|
|
||||||
static int generate_keydev_mount(const char *name, const char *keydev, char **unit, char **mount) {
|
static int split_keyspec(const char *keyspec, char **keyfile, char **keydev) {
|
||||||
_cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *name_escaped = NULL;
|
_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;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
usec_t timeout_us;
|
||||||
|
|
||||||
assert(name);
|
assert(name);
|
||||||
assert(keydev);
|
assert(keydev);
|
||||||
@ -94,7 +123,25 @@ static int generate_keydev_mount(const char *name, const char *keydev, char **un
|
|||||||
"[Mount]\n"
|
"[Mount]\n"
|
||||||
"What=%s\n"
|
"What=%s\n"
|
||||||
"Where=%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);
|
r = fflush_and_check(f);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -150,16 +197,17 @@ static int print_dependencies(FILE *f, const char* device_path) {
|
|||||||
static int create_disk(
|
static int create_disk(
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *device,
|
const char *device,
|
||||||
const char *keydev,
|
|
||||||
const char *password,
|
const char *password,
|
||||||
|
const char *keydev,
|
||||||
const char *options) {
|
const char *options) {
|
||||||
|
|
||||||
_cleanup_free_ char *n = NULL, *d = NULL, *u = NULL, *e = NULL,
|
_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;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
const char *dmname;
|
const char *dmname;
|
||||||
bool noauto, nofail, tmp, swap, netdev;
|
bool noauto, nofail, tmp, swap, netdev;
|
||||||
int r, detached_header;
|
int r, detached_header, keyfile_can_timeout;
|
||||||
|
|
||||||
assert(name);
|
assert(name);
|
||||||
assert(device);
|
assert(device);
|
||||||
@ -170,6 +218,10 @@ static int create_disk(
|
|||||||
swap = fstab_test_option(options, "swap\0");
|
swap = fstab_test_option(options, "swap\0");
|
||||||
netdev = fstab_test_option(options, "_netdev\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);
|
detached_header = fstab_filter_options(options, "header\0", NULL, &header_path, NULL);
|
||||||
if (detached_header < 0)
|
if (detached_header < 0)
|
||||||
return log_error_errno(detached_header, "Failed to parse header= option value: %m");
|
return log_error_errno(detached_header, "Failed to parse header= option value: %m");
|
||||||
@ -203,12 +255,6 @@ static int create_disk(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to generate unit name: %m");
|
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)
|
if (keydev && !password)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Key device is specified, but path to the password file is missing.");
|
"Key device is specified, but path to the password file is missing.");
|
||||||
@ -228,10 +274,16 @@ static int create_disk(
|
|||||||
"After=%s\n",
|
"After=%s\n",
|
||||||
netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");
|
netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");
|
||||||
|
|
||||||
|
if (password) {
|
||||||
|
password_escaped = specifier_escape(password);
|
||||||
|
if (!password_escaped)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
if (keydev) {
|
if (keydev) {
|
||||||
_cleanup_free_ char *unit = NULL, *p = NULL;
|
_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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to generate keydev mount unit: %m");
|
return log_error_errno(r, "Failed to generate keydev mount unit: %m");
|
||||||
|
|
||||||
@ -240,6 +292,12 @@ static int create_disk(
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
free_and_replace(password_escaped, p);
|
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)
|
if (!nofail)
|
||||||
@ -247,7 +305,7 @@ static int create_disk(
|
|||||||
"Before=%s\n",
|
"Before=%s\n",
|
||||||
netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
|
netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
|
||||||
|
|
||||||
if (password) {
|
if (password && !keydev) {
|
||||||
r = print_dependencies(f, password);
|
r = print_dependencies(f, password);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -314,7 +372,7 @@ static int create_disk(
|
|||||||
|
|
||||||
if (keydev)
|
if (keydev)
|
||||||
fprintf(f,
|
fprintf(f,
|
||||||
"ExecStartPost=" UMOUNT_PATH " %s\n\n",
|
"ExecStartPost=-" UMOUNT_PATH " %s\n\n",
|
||||||
keydev_mount);
|
keydev_mount);
|
||||||
|
|
||||||
r = fflush_and_check(f);
|
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")) {
|
} else if (streq(key, "luks.key")) {
|
||||||
size_t n;
|
size_t n;
|
||||||
_cleanup_free_ char *keyfile = NULL, *keydev = NULL;
|
_cleanup_free_ char *keyfile = NULL, *keydev = NULL;
|
||||||
char *c;
|
|
||||||
const char *keyspec;
|
const char *keyspec;
|
||||||
|
|
||||||
if (proc_cmdline_value_missing(key, value))
|
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();
|
return log_oom();
|
||||||
|
|
||||||
keyspec = value + n + 1;
|
keyspec = value + n + 1;
|
||||||
c = strrchr(keyspec, ':');
|
r = split_keyspec(keyspec, &keyfile, &keydev);
|
||||||
if (c) {
|
if (r < 0)
|
||||||
*c = '\0';
|
return r;
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
free_and_replace(d->keyfile, keyfile);
|
free_and_replace(d->keyfile, keyfile);
|
||||||
free_and_replace(d->keydev, keydev);
|
free_and_replace(d->keydev, keydev);
|
||||||
|
|
||||||
} else if (streq(key, "luks.name")) {
|
} else if (streq(key, "luks.name")) {
|
||||||
|
|
||||||
if (proc_cmdline_value_missing(key, value))
|
if (proc_cmdline_value_missing(key, value))
|
||||||
@ -520,7 +567,7 @@ static int add_crypttab_devices(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
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;
|
crypto_device *d = NULL;
|
||||||
char *l, *uuid;
|
char *l, *uuid;
|
||||||
int k;
|
int k;
|
||||||
@ -537,7 +584,7 @@ static int add_crypttab_devices(void) {
|
|||||||
if (IN_SET(l[0], 0, '#'))
|
if (IN_SET(l[0], 0, '#'))
|
||||||
continue;
|
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) {
|
if (k < 2 || k > 4) {
|
||||||
log_error("Failed to parse /etc/crypttab:%u, ignoring.", crypttab_line);
|
log_error("Failed to parse /etc/crypttab:%u, ignoring.", crypttab_line);
|
||||||
continue;
|
continue;
|
||||||
@ -556,7 +603,11 @@ static int add_crypttab_devices(void) {
|
|||||||
continue;
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -596,7 +647,7 @@ static int add_proc_cmdline_devices(void) {
|
|||||||
else
|
else
|
||||||
options = "timeout=0";
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,10 @@ static int parse_one_option(const char *option) {
|
|||||||
assert(option);
|
assert(option);
|
||||||
|
|
||||||
/* Handled outside of this tool */
|
/* 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;
|
return 0;
|
||||||
|
|
||||||
if ((val = startswith(option, "cipher="))) {
|
if ((val = startswith(option, "cipher="))) {
|
||||||
|
Loading…
Reference in New Issue
Block a user