From fb2d839c0660482e6605a6766fb5e67e68f86a9d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 25 Nov 2020 15:15:25 +0100 Subject: [PATCH] homed: move fido2 device enumeration logic to shared code --- src/home/homectl-fido2.c | 135 ------------------------------------ src/home/homectl-fido2.h | 4 -- src/home/homectl.c | 5 +- src/shared/libfido2-util.c | 137 +++++++++++++++++++++++++++++++++++++ src/shared/libfido2-util.h | 3 + 5 files changed, 143 insertions(+), 141 deletions(-) diff --git a/src/home/homectl-fido2.c b/src/home/homectl-fido2.c index 983891e0e0..99a6bd5d9d 100644 --- a/src/home/homectl-fido2.c +++ b/src/home/homectl-fido2.c @@ -410,138 +410,3 @@ int identity_add_fido2_parameters( "FIDO2 tokens not supported on this build."); #endif } - -int list_fido2_devices(void) { -#if HAVE_LIBFIDO2 - _cleanup_(table_unrefp) Table *t = NULL; - size_t allocated = 64, found = 0; - fido_dev_info_t *di = NULL; - int r; - - r = dlopen_libfido2(); - if (r < 0) - return log_error_errno(r, "FIDO2 token support is not installed."); - - di = sym_fido_dev_info_new(allocated); - if (!di) - return log_oom(); - - r = sym_fido_dev_info_manifest(di, allocated, &found); - if (r == FIDO_ERR_INTERNAL || (r == FIDO_OK && found == 0)) { - /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */ - log_info("No FIDO2 devices found."); - r = 0; - goto finish; - } - if (r != FIDO_OK) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO2 devices: %s", sym_fido_strerr(r)); - goto finish; - } - - t = table_new("path", "manufacturer", "product"); - if (!t) { - r = log_oom(); - goto finish; - } - - for (size_t i = 0; i < found; i++) { - const fido_dev_info_t *entry; - - entry = sym_fido_dev_info_ptr(di, i); - if (!entry) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to get device information for FIDO device %zu.", i); - goto finish; - } - - r = table_add_many( - t, - TABLE_PATH, sym_fido_dev_info_path(entry), - TABLE_STRING, sym_fido_dev_info_manufacturer_string(entry), - TABLE_STRING, sym_fido_dev_info_product_string(entry)); - if (r < 0) { - table_log_add_error(r); - goto finish; - } - } - - r = table_print(t, stdout); - if (r < 0) { - log_error_errno(r, "Failed to show device table: %m"); - goto finish; - } - - r = 0; - -finish: - sym_fido_dev_info_free(&di, allocated); - return r; -#else - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "FIDO2 tokens not supported on this build."); -#endif -} - -int find_fido2_auto(char **ret) { -#if HAVE_LIBFIDO2 - _cleanup_free_ char *copy = NULL; - size_t di_size = 64, found = 0; - const fido_dev_info_t *entry; - fido_dev_info_t *di = NULL; - const char *path; - int r; - - r = dlopen_libfido2(); - if (r < 0) - return log_error_errno(r, "FIDO2 token support is not installed."); - - di = sym_fido_dev_info_new(di_size); - if (!di) - return log_oom(); - - r = sym_fido_dev_info_manifest(di, di_size, &found); - if (r == FIDO_ERR_INTERNAL || (r == FIDO_OK && found == 0)) { - /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */ - r = log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No FIDO2 devices found."); - goto finish; - } - if (r != FIDO_OK) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO2 devices: %s", sym_fido_strerr(r)); - goto finish; - } - if (found > 1) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), "More than one FIDO2 device found."); - goto finish; - } - - entry = sym_fido_dev_info_ptr(di, 0); - if (!entry) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to get device information for FIDO device 0."); - goto finish; - } - - path = sym_fido_dev_info_path(entry); - if (!path) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to query FIDO device path."); - goto finish; - } - - copy = strdup(path); - if (!copy) { - r = log_oom(); - goto finish; - } - - *ret = TAKE_PTR(copy); - r = 0; - -finish: - sym_fido_dev_info_free(&di, di_size); - return r; -#else - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "FIDO2 tokens not supported on this build."); -#endif -} diff --git a/src/home/homectl-fido2.h b/src/home/homectl-fido2.h index d0349f5405..7b8d9f60ac 100644 --- a/src/home/homectl-fido2.h +++ b/src/home/homectl-fido2.h @@ -4,7 +4,3 @@ #include "json.h" int identity_add_fido2_parameters(JsonVariant **v, const char *device); - -int list_fido2_devices(void); - -int find_fido2_auto(char **ret); diff --git a/src/home/homectl.c b/src/home/homectl.c index e10cfaf2a4..c9e54b1e67 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -18,6 +18,7 @@ #include "homectl-fido2.h" #include "homectl-pkcs11.h" #include "homectl-recovery-key.h" +#include "libfido2-util.h" #include "locale-util.h" #include "main-func.h" #include "memory-util.h" @@ -3184,7 +3185,7 @@ static int parse_argv(int argc, char *argv[]) { const char *p; if (streq(optarg, "list")) - return list_fido2_devices(); + return fido2_list_devices(); FOREACH_STRING(p, "fido2HmacCredential", "fido2HmacSalt") { r = drop_from_identity(p); @@ -3200,7 +3201,7 @@ static int parse_argv(int argc, char *argv[]) { if (streq(optarg, "auto")) { _cleanup_free_ char *found = NULL; - r = find_fido2_auto(&found); + r = fido2_find_device_auto(&found); if (r < 0) return r; diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c index 281eb7537a..8358aa2fe3 100644 --- a/src/shared/libfido2-util.c +++ b/src/shared/libfido2-util.c @@ -5,6 +5,8 @@ #if HAVE_LIBFIDO2 #include "alloc-util.h" #include "dlfcn-util.h" +#include "format-table.h" +#include "locale-util.h" #include "log.h" static void *libfido2_dl = NULL; @@ -115,3 +117,138 @@ int dlopen_libfido2(void) { return 1; } #endif + +int fido2_list_devices(void) { +#if HAVE_LIBFIDO2 + _cleanup_(table_unrefp) Table *t = NULL; + size_t allocated = 64, found = 0; + fido_dev_info_t *di = NULL; + int r; + + r = dlopen_libfido2(); + if (r < 0) + return log_error_errno(r, "FIDO2 token support is not installed."); + + di = sym_fido_dev_info_new(allocated); + if (!di) + return log_oom(); + + r = sym_fido_dev_info_manifest(di, allocated, &found); + if (r == FIDO_ERR_INTERNAL || (r == FIDO_OK && found == 0)) { + /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */ + log_info("No FIDO2 devices found."); + r = 0; + goto finish; + } + if (r != FIDO_OK) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO2 devices: %s", sym_fido_strerr(r)); + goto finish; + } + + t = table_new("path", "manufacturer", "product"); + if (!t) { + r = log_oom(); + goto finish; + } + + for (size_t i = 0; i < found; i++) { + const fido_dev_info_t *entry; + + entry = sym_fido_dev_info_ptr(di, i); + if (!entry) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to get device information for FIDO device %zu.", i); + goto finish; + } + + r = table_add_many( + t, + TABLE_PATH, sym_fido_dev_info_path(entry), + TABLE_STRING, sym_fido_dev_info_manufacturer_string(entry), + TABLE_STRING, sym_fido_dev_info_product_string(entry)); + if (r < 0) { + table_log_add_error(r); + goto finish; + } + } + + r = table_print(t, stdout); + if (r < 0) { + log_error_errno(r, "Failed to show device table: %m"); + goto finish; + } + + r = 0; + +finish: + sym_fido_dev_info_free(&di, allocated); + return r; +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "FIDO2 tokens not supported on this build."); +#endif +} + +int fido2_find_device_auto(char **ret) { +#if HAVE_LIBFIDO2 + _cleanup_free_ char *copy = NULL; + size_t di_size = 64, found = 0; + const fido_dev_info_t *entry; + fido_dev_info_t *di = NULL; + const char *path; + int r; + + r = dlopen_libfido2(); + if (r < 0) + return log_error_errno(r, "FIDO2 token support is not installed."); + + di = sym_fido_dev_info_new(di_size); + if (!di) + return log_oom(); + + r = sym_fido_dev_info_manifest(di, di_size, &found); + if (r == FIDO_ERR_INTERNAL || (r == FIDO_OK && found == 0)) { + /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */ + r = log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No FIDO devices found."); + goto finish; + } + if (r != FIDO_OK) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO devices: %s", sym_fido_strerr(r)); + goto finish; + } + if (found > 1) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), "More than one FIDO device found."); + goto finish; + } + + entry = sym_fido_dev_info_ptr(di, 0); + if (!entry) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to get device information for FIDO device 0."); + goto finish; + } + + path = sym_fido_dev_info_path(entry); + if (!path) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to query FIDO device path."); + goto finish; + } + + copy = strdup(path); + if (!copy) { + r = log_oom(); + goto finish; + } + + *ret = TAKE_PTR(copy); + r = 0; + +finish: + sym_fido_dev_info_free(&di, di_size); + return r; +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "FIDO2 tokens not supported on this build."); +#endif +} diff --git a/src/shared/libfido2-util.h b/src/shared/libfido2-util.h index baa5ee9212..37b2f921ff 100644 --- a/src/shared/libfido2-util.h +++ b/src/shared/libfido2-util.h @@ -70,3 +70,6 @@ static inline void fido_cred_free_wrapper(fido_cred_t **p) { } #endif + +int fido2_list_devices(void); +int fido2_find_device_auto(char **ret);