diff --git a/zkey/kms.c b/zkey/kms.c index f54a3365..214d2c08 100644 --- a/zkey/kms.c +++ b/zkey/kms.c @@ -53,6 +53,30 @@ typedef const struct kms_functions *(*kms_get_functions_t)(void); warnx(fmt); \ } while (0) +#define ARRAY_ADD(array, num_elemnts, element_size, new_element) \ + do { \ + (num_elemnts)++; \ + (array) = util_realloc((array), \ + (num_elemnts) * element_size); \ + memcpy(&(array)[(num_elemnts) - 1], new_element, \ + element_size); \ + } while (0) + +#define ARRAY_REMOVE(array, num_elemnts, element_size, index) \ + do { \ + if ((index) < (num_elemnts) - 1) \ + memmove(&(array)[(index)], \ + &(array)[(index) + 1], \ + ((num_elemnts) - (index) - 1) * \ + element_size); \ + (num_elemnts)--; \ + if ((num_elemnts) > 0) { \ + (array) = util_realloc((array), \ + (num_elemnts) * element_size); \ + } \ + } while (0) + + /** * Opens kms-plugins.conf. Looks for the file in /etc/zkey/, or if environment * variable ZKEY_KMS_PLUGINS is set then it uses the file name and path @@ -812,3 +836,148 @@ kms_info: out: return rc; } + +/** + * Gets the KMS plugin command specific option vector and puts them into the + * placeholder slots in opt_vec. + * + * @param[in] kms_info information of the currently bound plugin. + * @param[in] opt_vec the option vector to modify. + * @param[in] placeholder_cmd the command with which the placeholder option + * vector entries are marked + * @param[in] plugin_command the plugin command to get the options for + * @param[in] opt_vec_command the command to use in the option vector entries + * @param[out] first_plugin_opt on return: the index of the first plugin option + * in opt_vec, or -1 if no plugin options are used. + * @param[in] verbose if true, verbose messages are printed + * + * @returns 0 for success or a negative errno in case of an error. + */ +int get_kms_options(struct kms_info *kms_info, struct util_opt *opt_vec, + const char *placeholder_cmd, const char *plugin_command, + const char *opt_vec_command, int *first_plugin_opt, + bool verbose) +{ + const struct util_opt *plugin_opts; + int i, k, first = 0, num_slots = 0; + + util_assert(kms_info != NULL, "Internal error: kms_info is NULL"); + util_assert(opt_vec != NULL, "Internal error: opt_vec is NULL"); + util_assert(placeholder_cmd != NULL, + "Internal error: placeholder_cmd is NULL"); + util_assert(plugin_command != NULL, + "Internal error: plugin_command is NULL"); + util_assert(first_plugin_opt != NULL, + "Internal error: first_plugin_opt is NULL"); + + *first_plugin_opt = -1; + + if (kms_info->plugin_lib == NULL) { + pr_verbose(verbose, "not bound to a KMS plugin"); + return 0; + } + + if (kms_info->funcs->kms_get_command_options == NULL) { + pr_verbose(verbose, "Plugin does not support command options"); + return 0; + } + + if (strcmp(plugin_command, KMS_COMMAND_CONFIGURE) != 0 && + strcmp(plugin_command, KMS_COMMAND_REENCIPHER) != 0 && + strcmp(plugin_command, KMS_COMMAND_GENERATE) != 0 && + strcmp(plugin_command, KMS_COMMAND_REMOVE) != 0 && + strcmp(plugin_command, KMS_COMMAND_LIST) != 0 && + strcmp(plugin_command, KMS_COMMAND_LIST_IMPORT) != 0) { + pr_verbose(verbose, "Command %s is not eligible for plugin " + "options", plugin_command); + return 0; + } + + for (i = 0; opt_vec[i].desc != NULL; i++) { + if (opt_vec[i].command != NULL && + strcmp(opt_vec[i].command, placeholder_cmd) == 0) { + if (first == 0) + first = i; + num_slots++; + } + } + + pr_verbose(verbose, "%u placeholder slots found", num_slots); + + plugin_opts = kms_info->funcs->kms_get_command_options(plugin_command, + num_slots); + if (plugin_opts == NULL) { + pr_verbose(verbose, "No plugin options for command %s", + plugin_command); + return 0; + } + + for (k = 0, i = first; plugin_opts[k].desc != NULL && + i < first + num_slots; i++, k++) { + memcpy(&opt_vec[i], &plugin_opts[k], sizeof(struct util_opt)); + opt_vec[i].command = (char *)opt_vec_command; + } + + pr_verbose(verbose, "%u plugin options", k); + + *first_plugin_opt = first; + + return 0; +} + +/** + * Checks if the option is a KMS plugin specific option and if so, adds it to + * list of KMS options. If the option is not handled by the plugin, then + * -ENOENT is returned. + * + * @param[in] kms_info information of the currently bound plugin. + * @param[in] opt_vec the option vector. + * @param[in] first_kms_option index of first KMS option in opt_vec + * @param[in] command the plugin command to handle + * @param[in] option the option character to handle + * @param[in] optarg the option argument or NULL + * @param[out] kms_options on return: an array of KMS options handled. The + * array is resized to add more options. + * @param[out] num_kms_options on return: The number of options in above array + * @param[in] verbose if true, verbose messages are printed + * + * @returns 0 for success or a negative errno in case of an error. + * + */ +int handle_kms_option(struct kms_info *kms_info, struct util_opt *opt_vec, + int first_kms_option, const char *command, int option, + const char *optarg, struct kms_option **kms_options, + size_t *num_kms_options, bool verbose) +{ + struct kms_option opt = { .option = option, .argument = optarg }; + int i; + + util_assert(kms_info != NULL, "Internal error: kms_info is NULL"); + util_assert(opt_vec != NULL, "Internal error: opt_vec is NULL"); + util_assert(command != NULL, "Internal error: command is NULL"); + util_assert(kms_options != NULL, "Internal error: kms_options is NULL"); + util_assert(num_kms_options != NULL, + "Internal error: num_kms_options is NULL"); + + if (kms_info->plugin_lib == NULL) { + pr_verbose(verbose, "not bound to a KMS plugin"); + return -ENOENT; + } + + if (first_kms_option < 0) { + pr_verbose(verbose, "No plugin specific options"); + return -ENOENT; + } + + for (i = first_kms_option; opt_vec[i].command != NULL && + strcmp(opt_vec[i].command, command) == 0; i++) { + if ((opt_vec[i].flags & UTIL_OPT_FLAG_SECTION) == 0 && + opt_vec[i].option.val == option) { + ARRAY_ADD(*kms_options, *num_kms_options, + sizeof(struct kms_option), &opt); + return 0; + } + } + + return -ENOENT; +} diff --git a/zkey/kms.h b/zkey/kms.h index 467c73ea..5a2ab1c0 100644 --- a/zkey/kms.h +++ b/zkey/kms.h @@ -47,4 +47,14 @@ int unbind_kms_plugin(struct kms_info *kms_info, struct keystore *keystore, int print_kms_info(struct kms_info *kms_info); +int get_kms_options(struct kms_info *kms_info, struct util_opt *opt_vec, + const char *placeholder_cmd, const char *plugin_command, + const char *opt_vec_command, int *first_plugin_opt, + bool verbose); + +int handle_kms_option(struct kms_info *kms_info, struct util_opt *opt_vec, + int first_kms_option, const char *command, int option, + const char *optarg, struct kms_option **kms_options, + size_t *num_kms_options, bool verbose); + #endif diff --git a/zkey/zkey.c b/zkey/zkey.c index 19cc0e75..ab1ce5ac 100644 --- a/zkey/zkey.c +++ b/zkey/zkey.c @@ -93,6 +93,9 @@ static struct zkey_globals { int pkey_fd; struct keystore *keystore; struct kms_info kms_info; + int first_kms_option; + struct kms_option *kms_options; + size_t num_kms_options; } g = { .pkey_fd = -1, .sector_size = -1, @@ -122,6 +125,15 @@ static struct zkey_globals { #define COMMAND_KMS_UNBIND "unbind" #define COMMAND_KMS_INFO "info" +#define OPT_COMMAND_PLACEHOLDER "PLACEHOLDER" + +#define OPT_PLACEHOLDER \ +{ \ + .option = { "", 0, NULL, ' ' }, \ + .desc = OPT_COMMAND_PLACEHOLDER, \ + .command = OPT_COMMAND_PLACEHOLDER, \ +} + #define ZKEY_COMMAND_MAX_LEN 10 #define ENVVAR_ZKEY_REPOSITORY "ZKEY_REPOSITORY" @@ -824,6 +836,47 @@ static struct util_opt opt_vec[] = { .command = COMMAND_CONVERT, }, /***********************************************************/ + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + /***********************************************************/ { .flags = UTIL_OPT_FLAG_SECTION, .desc = "COMMON OPTIONS" @@ -859,6 +912,7 @@ struct zkey_command { char **arg_alternate_value; int need_keystore; int use_kms_plugin; + char *kms_plugin_opts_cmd; struct zkey_command *sub_commands; }; @@ -2253,7 +2307,6 @@ int main(int argc, char *argv[]) int rc, c; util_prg_init(&prg); - util_opt_init(opt_vec, NULL); /* Get command and subcommand if one is specified */ if (arg_count >= 2 && strncmp(args[1], "-", 1) != 0) { @@ -2305,12 +2358,44 @@ int main(int argc, char *argv[]) rc = check_for_kms_plugin(&g.kms_info, g.verbose); if (rc != 0) return EXIT_FAILURE; + + if (cmd->kms_plugin_opts_cmd) { + rc = get_kms_options(&g.kms_info, opt_vec, + OPT_COMMAND_PLACEHOLDER, + cmd->kms_plugin_opts_cmd, + sub_command != NULL ? + command_str : cmd->command, + &g.first_kms_option, + g.verbose); + if (rc != 0) + return EXIT_FAILURE; + } } + util_opt_init(opt_vec, NULL); + while (1) { c = util_opt_getopt_long(arg_count, args); if (c == -1) break; + + if (cmd != NULL && cmd->kms_plugin_opts_cmd) { + rc = handle_kms_option(&g.kms_info, opt_vec, + g.first_kms_option, + sub_command != NULL ? + command_str : cmd->command, + c, optarg, &g.kms_options, + &g.num_kms_options, g.verbose); + if (rc != 0 && rc != -ENOENT) { + warnx("Failed to process KMS plugin option: " + "'%c': %s", c, strerror(-rc)); + return EXIT_FAILURE; + } + + if (rc == 0) + continue; + } + switch (c) { case 'x': g.xts = 1; @@ -2532,5 +2617,7 @@ out: close(g.pkey_fd); if (g.keystore) keystore_free(g.keystore); + if (g.kms_options != NULL) + free(g.kms_options); return rc; }