From: Lennart Poettering Date: Thu, 16 Apr 2020 07:44:55 +0000 (+0200) Subject: homectl: add --pkcs11-uri=auto and --pkcs-11-uri=list support X-Git-Tag: v246-rc1~45^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0eb3be464446ff98dba63cac6769467514403e10;p=thirdparty%2Fsystemd.git homectl: add --pkcs11-uri=auto and --pkcs-11-uri=list support We have the same for FIDO2 devices, for listing suitable devices, or picking the right one automatically, let's add that for PKCS11 too. --- diff --git a/src/home/homectl-pkcs11.c b/src/home/homectl-pkcs11.c index 6762d44e7e1..830aafaab14 100644 --- a/src/home/homectl-pkcs11.c +++ b/src/home/homectl-pkcs11.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include "errno-util.h" +#include "format-table.h" #include "hexdecoct.h" #include "homectl-pkcs11.h" #include "libcrypt-util.h" @@ -339,3 +340,141 @@ int identity_add_pkcs11_key_data(JsonVariant **v, const char *uri) { return 0; } + +#if HAVE_P11KIT +static int list_callback( + CK_FUNCTION_LIST *m, + CK_SESSION_HANDLE session, + CK_SLOT_ID slot_id, + const CK_SLOT_INFO *slot_info, + const CK_TOKEN_INFO *token_info, + P11KitUri *uri, + void *userdata) { + + _cleanup_free_ char *token_uri_string = NULL, *token_label = NULL, *token_manufacturer_id = NULL, *token_model = NULL; + _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL; + Table *t = userdata; + int uri_result, r; + + assert(slot_info); + assert(token_info); + + /* We only care about hardware devices here with a token inserted. Let's filter everything else + * out. (Note that the user can explicitly specify non-hardware tokens if they like, but during + * enumeration we'll filter those, since software tokens are typically the system certificate store + * and such, and it's typically not what people want to bind their home directories to.) */ + if (!FLAGS_SET(token_info->flags, CKF_HW_SLOT|CKF_TOKEN_PRESENT)) + return -EAGAIN; + + token_label = pkcs11_token_label(token_info); + if (!token_label) + return log_oom(); + + token_manufacturer_id = pkcs11_token_manufacturer_id(token_info); + if (!token_manufacturer_id) + return log_oom(); + + token_model = pkcs11_token_model(token_info); + if (!token_model) + return log_oom(); + + token_uri = uri_from_token_info(token_info); + if (!token_uri) + return log_oom(); + + uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string); + if (uri_result != P11_KIT_URI_OK) + return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result)); + + r = table_add_many( + t, + TABLE_STRING, token_uri_string, + TABLE_STRING, token_label, + TABLE_STRING, token_manufacturer_id, + TABLE_STRING, token_model); + if (r < 0) + return table_log_add_error(r); + + return -EAGAIN; /* keep scanning */ +} +#endif + +int list_pkcs11_tokens(void) { +#if HAVE_P11KIT + _cleanup_(table_unrefp) Table *t = NULL; + int r; + + t = table_new("uri", "label", "manufacturer", "model"); + if (!t) + return log_oom(); + + r = pkcs11_find_token(NULL, list_callback, t); + if (r < 0 && r != -EAGAIN) + return r; + + if (table_get_rows(t) <= 1) { + log_info("No suitable PKCS#11 tokens found."); + return 0; + } + + r = table_print(t, stdout); + if (r < 0) + return log_error_errno(r, "Failed to show device table: %m"); + + return 0; +#else + return log_error_errno(EOPNOTSUPP, "PKCS#11 tokens not supported on this build."); +#endif +} + +#if HAVE_P11KIT +static int auto_callback( + CK_FUNCTION_LIST *m, + CK_SESSION_HANDLE session, + CK_SLOT_ID slot_id, + const CK_SLOT_INFO *slot_info, + const CK_TOKEN_INFO *token_info, + P11KitUri *uri, + void *userdata) { + + _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL; + char **t = userdata; + int uri_result; + + assert(slot_info); + assert(token_info); + + if (!FLAGS_SET(token_info->flags, CKF_HW_SLOT|CKF_TOKEN_PRESENT)) + return -EAGAIN; + + if (*t) + return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), + "More than one suitable PKCS#11 token found."); + + token_uri = uri_from_token_info(token_info); + if (!token_uri) + return log_oom(); + + uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, t); + if (uri_result != P11_KIT_URI_OK) + return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result)); + + return 0; +} +#endif + +int find_pkcs11_token_auto(char **ret) { +#if HAVE_P11KIT + int r; + + r = pkcs11_find_token(NULL, auto_callback, ret); + if (r == -EAGAIN) + return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No suitable PKCS#11 tokens found."); + if (r < 0) + return r; + + return 0; +#else + return log_error_errno(EOPNOTSUPP, "PKCS#11 tokens not supported on this build."); +#endif +} diff --git a/src/home/homectl-pkcs11.h b/src/home/homectl-pkcs11.h index efe1a2f223c..0403c73ea1a 100644 --- a/src/home/homectl-pkcs11.h +++ b/src/home/homectl-pkcs11.h @@ -6,3 +6,6 @@ int identity_add_token_pin(JsonVariant **v, const char *pin); int identity_add_pkcs11_key_data(JsonVariant **v, const char *token_uri); + +int list_pkcs11_tokens(void); +int find_pkcs11_token_auto(char **ret); diff --git a/src/home/homectl.c b/src/home/homectl.c index 95fcead038d..74c967eb265 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -3098,6 +3098,9 @@ static int parse_argv(int argc, char *argv[]) { case ARG_PKCS11_TOKEN_URI: { const char *p; + if (streq(optarg, "list")) + return list_pkcs11_tokens(); + /* If --pkcs11-token-uri= is specified we always drop everything old */ FOREACH_STRING(p, "pkcs11TokenUri", "pkcs11EncryptedKey") { r = drop_from_identity(p); @@ -3110,10 +3113,19 @@ static int parse_argv(int argc, char *argv[]) { break; } - if (!pkcs11_uri_valid(optarg)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid PKCS#11 URI: %s", optarg); + if (streq(optarg, "auto")) { + _cleanup_free_ char *found = NULL; - r = strv_extend(&arg_pkcs11_token_uri, optarg); + r = find_pkcs11_token_auto(&found); + if (r < 0) + return r; + r = strv_consume(&arg_pkcs11_token_uri, TAKE_PTR(found)); + } else { + if (!pkcs11_uri_valid(optarg)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid PKCS#11 URI: %s", optarg); + + r = strv_extend(&arg_pkcs11_token_uri, optarg); + } if (r < 0) return r; diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c index b8863d25257..632964df449 100644 --- a/src/shared/pkcs11-util.c +++ b/src/shared/pkcs11-util.c @@ -151,6 +151,28 @@ char *pkcs11_token_label(const CK_TOKEN_INFO *token_info) { return t; } +char *pkcs11_token_manufacturer_id(const CK_TOKEN_INFO *token_info) { + char *t; + + t = strndup((char*) token_info->manufacturerID, sizeof(token_info->manufacturerID)); + if (!t) + return NULL; + + strstrip(t); + return t; +} + +char *pkcs11_token_model(const CK_TOKEN_INFO *token_info) { + char *t; + + t = strndup((char*) token_info->model, sizeof(token_info->model)); + if (!t) + return NULL; + + strstrip(t); + return t; +} + int pkcs11_token_login( CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, @@ -165,9 +187,8 @@ int pkcs11_token_login( _cleanup_free_ char *token_uri_string = NULL, *token_uri_escaped = NULL, *id = NULL, *token_label = NULL; _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL; CK_TOKEN_INFO updated_token_info; - int uri_result; + int uri_result, r; CK_RV rv; - int r; assert(m); assert(token_info); @@ -703,7 +724,6 @@ static int token_process( assert(m); assert(slot_info); assert(token_info); - assert(search_uri); token_label = pkcs11_token_label(token_info); if (!token_label) @@ -741,7 +761,6 @@ static int slot_process( CK_RV rv; assert(m); - assert(search_uri); /* We return -EAGAIN for all failures we can attribute to a specific slot in some way, so that the * caller might try other slots before giving up. */ @@ -787,7 +806,7 @@ static int slot_process( return -EAGAIN; } - if (!p11_kit_uri_match_token_info(search_uri, &token_info)) { + if (search_uri && !p11_kit_uri_match_token_info(search_uri, &token_info)) { log_debug("Found non-matching token with URI %s.", token_uri_string); return -EAGAIN; } @@ -821,7 +840,6 @@ static int module_process( int r; assert(m); - assert(search_uri); /* We ignore most errors from modules here, in order to skip over faulty modules: one faulty module * should not have the effect that we don't try the others anymore. We indicate such per-module @@ -884,14 +902,14 @@ int pkcs11_find_token( _cleanup_(p11_kit_uri_freep) P11KitUri *search_uri = NULL; int r; - assert(pkcs11_uri); - /* Execute the specified callback for each matching token found. If nothing is found returns * -EAGAIN. Logs about all errors, except for EAGAIN, which the caller has to log about. */ - r = uri_from_string(pkcs11_uri, &search_uri); - if (r < 0) - return log_error_errno(r, "Failed to parse PKCS#11 URI '%s': %m", pkcs11_uri); + if (pkcs11_uri) { + r = uri_from_string(pkcs11_uri, &search_uri); + if (r < 0) + return log_error_errno(r, "Failed to parse PKCS#11 URI '%s': %m", pkcs11_uri); + } modules = p11_kit_modules_load_and_initialize(0); if (!modules) diff --git a/src/shared/pkcs11-util.h b/src/shared/pkcs11-util.h index 46791eb23b7..959e7c3e0d9 100644 --- a/src/shared/pkcs11-util.h +++ b/src/shared/pkcs11-util.h @@ -27,6 +27,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(CK_FUNCTION_LIST**, p11_kit_modules_finalize_and_rel CK_RV pkcs11_get_slot_list_malloc(CK_FUNCTION_LIST *m, CK_SLOT_ID **ret_slotids, CK_ULONG *ret_n_slotids); char *pkcs11_token_label(const CK_TOKEN_INFO *token_info); +char *pkcs11_token_manufacturer_id(const CK_TOKEN_INFO *token_info); +char *pkcs11_token_model(const CK_TOKEN_INFO *token_info); int pkcs11_token_login(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, CK_SLOT_ID slotid, const CK_TOKEN_INFO *token_info, const char *friendly_name, const char *icon_name, const char *keyname, usec_t until, char **ret_used_pin);