]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
homectl: add --pkcs11-uri=auto and --pkcs-11-uri=list support
authorLennart Poettering <lennart@poettering.net>
Thu, 16 Apr 2020 07:44:55 +0000 (09:44 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 1 Jul 2020 09:20:26 +0000 (11:20 +0200)
We have the same for FIDO2 devices, for listing suitable devices, or
picking the right one automatically, let's add that for PKCS11 too.

src/home/homectl-pkcs11.c
src/home/homectl-pkcs11.h
src/home/homectl.c
src/shared/pkcs11-util.c
src/shared/pkcs11-util.h

index 6762d44e7e16b83e72e08eeb1d341edf1f0c1098..830aafaab14494b6ce7ac835a2ebe960ae36bc1a 100644 (file)
@@ -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
+}
index efe1a2f223c0b68506ebbead851341bb178ac216..0403c73ea1afd3583a73242bb3bafb0d2eafa6ae 100644 (file)
@@ -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);
index 95fcead038dc1ed2d8cfa54ca99fb92dc83a11bc..74c967eb265cbc3895c482fc3aac58c716dcee35 100644 (file)
@@ -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;
 
index b8863d25257b8ab2618a2a750adca3be295eb2b6..632964df4491c81de264cb1112eae0c3676b02f2 100644 (file)
@@ -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)
index 46791eb23b74c1a627282e9da3c63ad179d343ca..959e7c3e0d9c90f63760ab1898aae978beb81dcc 100644 (file)
@@ -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);