summaryrefslogtreecommitdiffstats
path: root/src/passkey_child/passkey_child_devices.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/passkey_child/passkey_child_devices.c')
-rw-r--r--src/passkey_child/passkey_child_devices.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/src/passkey_child/passkey_child_devices.c b/src/passkey_child/passkey_child_devices.c
new file mode 100644
index 0000000..2011b12
--- /dev/null
+++ b/src/passkey_child/passkey_child_devices.c
@@ -0,0 +1,246 @@
+/*
+ SSSD
+
+ Helper child to commmunicate with passkey devices
+
+ Authors:
+ Iker Pedrosa <ipedrosa@redhat.com>
+
+ Copyright (C) 2022 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/debug.h"
+#include "util/util.h"
+
+#include "passkey_child.h"
+
+errno_t
+list_devices(fido_dev_info_t *dev_list, size_t *dev_number)
+{
+ errno_t ret;
+
+ for (int i = 0; i < TIMEOUT; i += FREQUENCY) {
+ ret = fido_dev_info_manifest(dev_list, DEVLIST_SIZE, dev_number);
+ if (ret != FIDO_OK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Unable to discover device(s) [%d]: %s.\n",
+ ret, fido_strerr(ret));
+ }
+
+ if ((*dev_number) != 0) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Device found.\n");
+ break;
+ }
+
+ if (i < (TIMEOUT - 1)) {
+ DEBUG(SSSDBG_TRACE_FUNC, "No device available, retrying.\n");
+ sleep(FREQUENCY);
+ }
+ }
+
+ return ret;
+}
+
+errno_t
+select_device(enum action_opt action, fido_dev_info_t *dev_list,
+ size_t dev_list_len, fido_assert_t *assert,
+ fido_dev_t **_dev)
+{
+ fido_dev_t *dev = NULL;
+ const char *path;
+ const fido_dev_info_t *di = NULL;
+ errno_t ret;
+
+ if (dev_list_len == 0) {
+ DEBUG(SSSDBG_OP_FAILURE, "No device found. Aborting.\n");
+ ret = ENOENT;
+ goto done;
+ } else if (action == ACTION_REGISTER && dev_list_len == 1) {
+ dev = fido_dev_new();
+ if (dev == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "fido_dev_new failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ di = fido_dev_info_ptr(dev_list, 0);
+ if (di == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "fido_dev_info_ptr failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ path = fido_dev_info_path(di);
+ if (path == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "fido_dev_info_path failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = fido_dev_open(dev, path);
+ if (ret != FIDO_OK) {
+ DEBUG(SSSDBG_OP_FAILURE, "fido_dev_open failed [%d]: %s.\n",
+ ret, fido_strerr(ret));
+ goto done;
+ }
+
+ *_dev = dev;
+ } else if (action == ACTION_REGISTER && dev_list_len > 1) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Only one device is supported at a time. Aborting.\n");
+ fprintf(stderr, "Only one device is supported at a time. Aborting.\n");
+ ret = EPERM;
+ goto done;
+ } else {
+ if (assert == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "assert cannot be NULL.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ ret = select_from_multiple_devices(dev_list, dev_list_len, assert, _dev);
+ if (ret != FIDO_OK) {
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ if (dev != NULL) {
+ fido_dev_close(dev);
+ }
+ fido_dev_free(&dev);
+ }
+
+ return ret;
+}
+
+errno_t
+select_from_multiple_devices(fido_dev_info_t *dev_list,
+ size_t dev_list_len,
+ fido_assert_t *assert,
+ fido_dev_t **_dev)
+{
+ fido_dev_t *dev = NULL;
+ const fido_dev_info_t *di = NULL;
+ const char *path;
+ bool is_fido2;
+ errno_t ret;
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Working with %ld authenticator(s).\n", dev_list_len);
+
+ for (size_t i = 0; i < dev_list_len; i++) {
+ dev = fido_dev_new();
+ if (dev == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "fido_dev_new failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ di = fido_dev_info_ptr(dev_list, i);
+ if (di == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "fido_dev_info_ptr failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ path = fido_dev_info_path(di);
+ if (path == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "fido_dev_info_path failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = fido_dev_open(dev, path);
+ if (ret != FIDO_OK) {
+ DEBUG(SSSDBG_OP_FAILURE, "fido_dev_open failed [%d]: %s.\n",
+ ret, fido_strerr(ret));
+ }
+
+ is_fido2 = fido_dev_is_fido2(dev);
+ ret = fido_dev_get_assert(dev, assert, NULL);
+ if ((is_fido2 == false && ret == FIDO_ERR_USER_PRESENCE_REQUIRED)
+ || (is_fido2 == true && ret == FIDO_OK)) {
+ *_dev = dev;
+ DEBUG(SSSDBG_FUNC_DATA, "Assertion found in passkey %ld.\n", i);
+ ret = EOK;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_FUNC_DATA, "Assertion not found in passkey %ld.\n", i);
+
+ fido_dev_close(dev);
+ fido_dev_free(&dev);
+ }
+
+ ret = FIDO_ERR_NOTFOUND;
+ DEBUG(SSSDBG_OP_FAILURE, "Assertion not found.\n");
+
+done:
+ return ret;
+}
+
+errno_t
+get_device_options(fido_dev_t *dev, struct passkey_data *_data)
+{
+ bool has_pin;
+ bool has_uv;
+ bool supports_uv;
+ errno_t ret;
+
+ has_uv = fido_dev_has_uv(dev);
+ has_pin = fido_dev_has_pin(dev);
+ supports_uv = fido_dev_supports_uv(dev);
+
+ if (_data->user_verification == FIDO_OPT_TRUE && has_pin != true
+ && has_uv != true) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Policy enabled user-verification but there isn't any "
+ "verification method set.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (_data->user_verification == FIDO_OPT_OMIT
+ && (has_uv == true || has_pin == true)) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Policy didn't indicate any preference for user-verification "
+ "but the key settings are enforcing it. Thus, enforcing the "
+ "user-verification.\n");
+ _data->user_verification = FIDO_OPT_TRUE;
+ ret = EOK;
+ goto done;
+ }
+
+ if (_data->user_verification == FIDO_OPT_FALSE
+ && supports_uv == false) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Policy disabled user-verification but the key doesn't support "
+ "it. Thus, omitting the user-verification.\n");
+ _data->user_verification = FIDO_OPT_OMIT;
+ ret = EOK;
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+
+ return ret;
+}