diff --git a/po/POTFILES.in b/po/POTFILES.in index 7e22598c..6f86301e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -53,5 +53,6 @@ src/utils_reencrypt.c src/utils_reencrypt_luks1.c src/utils_blockdev.c src/utils_args.c +src/utils_key_description.c tokens/ssh/cryptsetup-ssh.c tokens/ssh/ssh-utils.c diff --git a/src/Makemodule.am b/src/Makemodule.am index 57fff402..9004b125 100644 --- a/src/Makemodule.am +++ b/src/Makemodule.am @@ -17,6 +17,7 @@ cryptsetup_SOURCES = \ src/utils_reencrypt.c \ src/utils_reencrypt_luks1.c \ src/utils_progress.c \ + src/utils_key_description.c \ src/cryptsetup.c \ src/cryptsetup.h \ src/cryptsetup_args.h \ diff --git a/src/cryptsetup.c b/src/cryptsetup.c index a49de698..b898a28a 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -1774,154 +1774,6 @@ static int action_luksFormat(void) return luksFormat(NULL, NULL, NULL); } -static int parse_vk_description(const char *key_description, char **ret_key_description) -{ - char *tmp; - int r; - - assert(key_description); - assert(ret_key_description); - - /* apply default key type */ - if (*key_description != '%') - r = asprintf(&tmp, "%%user:%s", key_description) < 0 ? -EINVAL : 0; - else - r = (tmp = strdup(key_description)) ? 0 : -ENOMEM; - if (!r) - *ret_key_description = tmp; - - return r; -} - -static int parse_single_vk_and_keyring_description( - struct crypt_device *cd, - char *keyring_key_description, char **keyring_part_out, char - **key_part_out, char **type_part_out) -{ - int r = -EINVAL; - char *endp, *sep, *key_part, *type_part = NULL; - char *key_part_copy = NULL, *type_part_copy = NULL, *keyring_part = NULL; - - if (!cd || !keyring_key_description) - return -EINVAL; - - /* "::" is separator between keyring specification a key description */ - key_part = strstr(keyring_key_description, "::"); - if (!key_part) - goto out; - - *key_part = '\0'; - key_part = key_part + 2; - - if (*key_part == '%') { - type_part = key_part + 1; - sep = strstr(type_part, ":"); - if (!sep) - goto out; - *sep = '\0'; - - key_part = sep + 1; - } - - if (*keyring_key_description == '%') { - keyring_key_description = strstr(keyring_key_description, ":"); - if (!keyring_key_description) - goto out; - log_verbose(_("Type specification in --link-vk-to-keyring keyring specification is ignored.")); - keyring_key_description++; - } - - (void)strtol(keyring_key_description, &endp, 0); - - r = 0; - if (*keyring_key_description == '@' || !*endp) - keyring_part = strdup(keyring_key_description); - else - r = asprintf(&keyring_part, "%%:%s", keyring_key_description); - - if (!keyring_part || r < 0) { - r = -ENOMEM; - goto out; - } - - if (!(key_part_copy = strdup(key_part))) { - r = -ENOMEM; - goto out; - } - if (type_part && !(type_part_copy = strdup(type_part))) - r = -ENOMEM; - -out: - if (r < 0) { - free(keyring_part); - free(key_part_copy); - free(type_part_copy); - } else { - *keyring_part_out = keyring_part; - *key_part_out = key_part_copy; - *type_part_out = type_part_copy; - } - - return r; -} - -static int parse_vk_and_keyring_description( - struct crypt_device *cd, - char **keyring_key_descriptions, - int keyring_key_links_count) -{ - int r = 0; - - char *keyring_part_out1 = NULL, *key_part_out1 = NULL, *type_part_out1 = NULL; - char *keyring_part_out2 = NULL, *key_part_out2 = NULL, *type_part_out2 = NULL; - - if (keyring_key_links_count > 0) { - r = parse_single_vk_and_keyring_description(cd, - keyring_key_descriptions[0], - &keyring_part_out1, &key_part_out1, - &type_part_out1); - if (r < 0) - goto out; - } - if (keyring_key_links_count > 1) { - r = parse_single_vk_and_keyring_description(cd, - keyring_key_descriptions[1], - &keyring_part_out2, &key_part_out2, - &type_part_out2); - if (r < 0) - goto out; - - if ((type_part_out1 && type_part_out2) && strcmp(type_part_out1, type_part_out2)) { - log_err(_("Key types have to be the same for both volume keys.")); - r = -EINVAL; - goto out; - } - if ((keyring_part_out1 && keyring_part_out2) && strcmp(keyring_part_out1, keyring_part_out2)) { - log_err(_("Both volume keys have to be linked to the same keyring.")); - r = -EINVAL; - goto out; - } - } - - if (keyring_key_links_count > 0) { - r = crypt_set_keyring_to_link(cd, key_part_out1, key_part_out2, - type_part_out1, keyring_part_out1); - if (r == -EAGAIN) - log_err(_("You need to supply more key names.")); - } -out: - if (r == -EINVAL) - log_err(_("Invalid --link-vk-to-keyring value.")); - free(keyring_part_out1); - free(key_part_out1); - free(type_part_out1); - free(keyring_part_out2); - free(key_part_out2); - free(type_part_out2); - - return r; -} - static int action_open_luks(void) { struct crypt_active_device cad; @@ -1985,7 +1837,7 @@ static int action_open_luks(void) } if (ARG_SET(OPT_LINK_VK_TO_KEYRING_ID)) { - r = parse_vk_and_keyring_description(cd, keyring_links, keyring_links_count); + r = tools_parse_vk_and_keyring_description(cd, keyring_links, keyring_links_count); if (r < 0) goto out; } @@ -2006,7 +1858,7 @@ static int action_open_luks(void) key, keysize, activate_flags); } else if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) { if (vks_in_keyring_count == 1) { - r = parse_vk_description(vks_in_keyring[0], &vk_description_activation1); + r = tools_parse_vk_description(vks_in_keyring[0], &vk_description_activation1); if (r < 0) goto out; r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description_activation1, &kc1); @@ -2014,10 +1866,10 @@ static int action_open_luks(void) goto out; r = crypt_activate_by_keyslot_context(cd, activated_name, CRYPT_ANY_SLOT, kc1, CRYPT_ANY_SLOT, NULL, activate_flags); } else if (vks_in_keyring_count == 2) { - r = parse_vk_description(vks_in_keyring[0], &vk_description_activation1); + r = tools_parse_vk_description(vks_in_keyring[0], &vk_description_activation1); if (r < 0) goto out; - r = parse_vk_description(vks_in_keyring[1], &vk_description_activation2); + r = tools_parse_vk_description(vks_in_keyring[1], &vk_description_activation2); if (r < 0) goto out; r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description_activation1, &kc1); @@ -2445,7 +2297,7 @@ static int action_luksAddKey(void) r = crypt_keyslot_context_init_by_volume_key(cd, key, keysize, &kc); crypt_safe_free(key); } else if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) { - r = parse_vk_description(ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &vk_description); + r = tools_parse_vk_description(ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &vk_description); if (!r) { r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description, &kc); free(vk_description); @@ -2874,7 +2726,7 @@ static int action_luksResume(void) return r; if (ARG_SET(OPT_LINK_VK_TO_KEYRING_ID)) { - r = parse_vk_and_keyring_description(cd, keyring_links, keyring_links_count); + r = tools_parse_vk_and_keyring_description(cd, keyring_links, keyring_links_count); if (r < 0) goto out; } @@ -2919,7 +2771,7 @@ static int action_luksResume(void) goto out; if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) { - r = parse_vk_description(ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &vk_description_activation); + r = tools_parse_vk_description(ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &vk_description_activation); if (r < 0) goto out; r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description_activation, &kc); diff --git a/src/cryptsetup.h b/src/cryptsetup.h index 06f5440b..e3579542 100644 --- a/src/cryptsetup.h +++ b/src/cryptsetup.h @@ -117,6 +117,13 @@ int tools_lookup_crypt_device(struct crypt_device *cd, const char *type, /* each utility is required to implement it */ void tools_cleanup(void); +/* keyring helpers */ +int tools_parse_vk_description(const char *key_description, char **ret_key_description); +int tools_parse_vk_and_keyring_description( + struct crypt_device *cd, + char **keyring_key_descriptions, + int keyring_key_links_count); + /* Log */ #define log_dbg(x...) crypt_logf(NULL, CRYPT_LOG_DEBUG, x) #define log_std(x...) crypt_logf(NULL, CRYPT_LOG_NORMAL, x) diff --git a/src/meson.build b/src/meson.build index 3fd1ff5b..533850e0 100644 --- a/src/meson.build +++ b/src/meson.build @@ -11,6 +11,7 @@ if get_option('cryptsetup') 'utils_reencrypt.c', 'utils_reencrypt_luks1.c', 'utils_tools.c', + 'utils_key_description.c', ) cryptsetup_files += lib_tools_files cryptsetup_deps = [ diff --git a/src/utils_key_description.c b/src/utils_key_description.c new file mode 100644 index 00000000..91a64bd8 --- /dev/null +++ b/src/utils_key_description.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Password quality check wrapper + * + * Copyright (C) 2023-2024 Red Hat, Inc. All rights reserved. + * Copyright (C) 2023-2024 Ondrej Kozina + * Copyright (C) 2023-2024 Milan Broz + */ + +#include "cryptsetup.h" +#include + +int tools_parse_vk_description(const char *key_description, char **ret_key_description) +{ + char *tmp; + int r; + + assert(key_description); + assert(ret_key_description); + + /* apply default key type */ + if (*key_description != '%') + r = asprintf(&tmp, "%%user:%s", key_description) < 0 ? -EINVAL : 0; + else + r = (tmp = strdup(key_description)) ? 0 : -ENOMEM; + if (!r) + *ret_key_description = tmp; + + return r; +} + +static int parse_single_vk_and_keyring_description( + struct crypt_device *cd, + char *keyring_key_description, char **keyring_part_out, char + **key_part_out, char **type_part_out) +{ + int r = -EINVAL; + char *endp, *sep, *key_part, *type_part = NULL; + char *key_part_copy = NULL, *type_part_copy = NULL, *keyring_part = NULL; + + if (!cd || !keyring_key_description) + return -EINVAL; + + /* "::" is separator between keyring specification a key description */ + key_part = strstr(keyring_key_description, "::"); + if (!key_part) + goto out; + + *key_part = '\0'; + key_part = key_part + 2; + + if (*key_part == '%') { + type_part = key_part + 1; + sep = strstr(type_part, ":"); + if (!sep) + goto out; + *sep = '\0'; + + key_part = sep + 1; + } + + if (*keyring_key_description == '%') { + keyring_key_description = strstr(keyring_key_description, ":"); + if (!keyring_key_description) + goto out; + log_verbose(_("Type specification in --link-vk-to-keyring keyring specification is ignored.")); + keyring_key_description++; + } + + (void)strtol(keyring_key_description, &endp, 0); + + r = 0; + if (*keyring_key_description == '@' || !*endp) + keyring_part = strdup(keyring_key_description); + else + r = asprintf(&keyring_part, "%%:%s", keyring_key_description); + + if (!keyring_part || r < 0) { + r = -ENOMEM; + goto out; + } + + if (!(key_part_copy = strdup(key_part))) { + r = -ENOMEM; + goto out; + } + if (type_part && !(type_part_copy = strdup(type_part))) + r = -ENOMEM; + +out: + if (r < 0) { + free(keyring_part); + free(key_part_copy); + free(type_part_copy); + } else { + *keyring_part_out = keyring_part; + *key_part_out = key_part_copy; + *type_part_out = type_part_copy; + } + + return r; +} + +int tools_parse_vk_and_keyring_description( + struct crypt_device *cd, + char **keyring_key_descriptions, + int keyring_key_links_count) +{ + int r = 0; + + char *keyring_part_out1 = NULL, *key_part_out1 = NULL, *type_part_out1 = NULL; + char *keyring_part_out2 = NULL, *key_part_out2 = NULL, *type_part_out2 = NULL; + + if (keyring_key_links_count > 0) { + r = parse_single_vk_and_keyring_description(cd, + keyring_key_descriptions[0], + &keyring_part_out1, &key_part_out1, + &type_part_out1); + if (r < 0) + goto out; + } + if (keyring_key_links_count > 1) { + r = parse_single_vk_and_keyring_description(cd, + keyring_key_descriptions[1], + &keyring_part_out2, &key_part_out2, + &type_part_out2); + if (r < 0) + goto out; + + if ((type_part_out1 && type_part_out2) && strcmp(type_part_out1, type_part_out2)) { + log_err(_("Key types have to be the same for both volume keys.")); + r = -EINVAL; + goto out; + } + if ((keyring_part_out1 && keyring_part_out2) && strcmp(keyring_part_out1, keyring_part_out2)) { + log_err(_("Both volume keys have to be linked to the same keyring.")); + r = -EINVAL; + goto out; + } + } + + if (keyring_key_links_count > 0) { + r = crypt_set_keyring_to_link(cd, key_part_out1, key_part_out2, + type_part_out1, keyring_part_out1); + if (r == -EAGAIN) + log_err(_("You need to supply more key names.")); + } +out: + if (r == -EINVAL) + log_err(_("Invalid --link-vk-to-keyring value.")); + free(keyring_part_out1); + free(key_part_out1); + free(type_part_out1); + free(keyring_part_out2); + free(key_part_out2); + free(type_part_out2); + + return r; +}