eabdullin
d405959af2
- Apply 0009-SSS_CLIENT-MC-in-case-mem-cache-file-validation-fails.patch - Apply 0010-SSS_CLIENT-check-if-mem-cache-fd-was-hijacked.patch - Apply 0011-SSS_CLIENT-check-if-reponder-socket-was-hijacked.patch - Apply 0012-LDAP-make-groups_by_user_send-recv-public.patch - Apply 0013-ad-gpo-evalute-host-groups.patch - Apply 0014-sysdb-remove-sysdb_computer.ch.patch - Apply 0015-sdap-add-set_non_posix-parameter.patch - Apply 0016-ipa-Add-BUILD_PASSKEY-conditional-for-passkey-codepath.patch - Apply 0017-pam-Conditionalize-passkey-code.patch - Apply 0018-Makefile-Respect-BUILD_PASSKEY-conditional.patch
872 lines
27 KiB
Diff
872 lines
27 KiB
Diff
From eadee9a2a8f0dfe4f22c460537d6c87c493fa622 Mon Sep 17 00:00:00 2001
|
|
From: Justin Stephenson <jstephen@redhat.com>
|
|
Date: Mon, 14 Aug 2023 14:42:51 -0400
|
|
Subject: [PATCH] pam: Conditionalize passkey code
|
|
|
|
Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
|
|
Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
|
|
---
|
|
Makefile.am | 4 +-
|
|
src/responder/pam/pamsrv_cmd.c | 364 +----------------------------
|
|
src/responder/pam/pamsrv_passkey.c | 351 ++++++++++++++++++++++++++++
|
|
src/responder/pam/pamsrv_passkey.h | 8 +
|
|
4 files changed, 372 insertions(+), 355 deletions(-)
|
|
|
|
diff --git a/Makefile.am b/Makefile.am
|
|
index 066f5d94ee..273ac1c523 100644
|
|
--- a/Makefile.am
|
|
+++ b/Makefile.am
|
|
@@ -1558,8 +1558,10 @@ sssd_pam_SOURCES = \
|
|
src/responder/pam/pam_prompting_config.c \
|
|
src/sss_client/pam_sss_prompt_config.c \
|
|
src/responder/pam/pam_helpers.c \
|
|
- src/responder/pam/pamsrv_passkey.c \
|
|
$(SSSD_RESPONDER_OBJ)
|
|
+if BUILD_PASSKEY
|
|
+ sssd_pam_SOURCES += src/responder/pam/pamsrv_passkey.c
|
|
+endif
|
|
sssd_pam_CFLAGS = \
|
|
$(AM_CFLAGS) \
|
|
$(GSSAPI_KRB5_CFLAGS) \
|
|
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
|
|
index 94cbf13e8d..eed283f4e9 100644
|
|
--- a/src/responder/pam/pamsrv_cmd.c
|
|
+++ b/src/responder/pam/pamsrv_cmd.c
|
|
@@ -50,12 +50,6 @@ struct pam_initgroup_enum_str {
|
|
const char *option;
|
|
};
|
|
|
|
-struct pam_passkey_table_data {
|
|
- hash_table_t *table;
|
|
- char *key;
|
|
- struct pk_child_user_data *data;
|
|
-};
|
|
-
|
|
struct pam_initgroup_enum_str pam_initgroup_enum_str[] = {
|
|
{ PAM_INITGR_NEVER, "never" },
|
|
{ PAM_INITGR_NO_SESSION, "no_session" },
|
|
@@ -105,10 +99,6 @@ static errno_t check_cert(TALLOC_CTX *mctx,
|
|
struct pam_auth_req *preq,
|
|
struct pam_data *pd);
|
|
|
|
-errno_t passkey_kerberos(struct pam_ctx *pctx,
|
|
- struct pam_data *pd,
|
|
- struct pam_auth_req *preq);
|
|
-
|
|
int pam_check_user_done(struct pam_auth_req *preq, int ret);
|
|
|
|
static errno_t pack_user_info_msg(TALLOC_CTX *mem_ctx,
|
|
@@ -871,229 +861,6 @@ done:
|
|
return ret;
|
|
}
|
|
|
|
-errno_t decode_pam_passkey_msg(TALLOC_CTX *mem_ctx,
|
|
- uint8_t *buf,
|
|
- size_t len,
|
|
- struct pk_child_user_data **_data)
|
|
-{
|
|
-
|
|
- size_t p = 0;
|
|
- size_t pctr = 0;
|
|
- errno_t ret;
|
|
- size_t offset;
|
|
- struct pk_child_user_data *data = NULL;
|
|
- TALLOC_CTX *tmp_ctx;
|
|
-
|
|
- tmp_ctx = talloc_new(NULL);
|
|
- if (tmp_ctx == NULL) {
|
|
- return ENOMEM;
|
|
- }
|
|
-
|
|
- data = talloc_zero(tmp_ctx, struct pk_child_user_data);
|
|
- if (data == NULL) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "Failed to talloc passkey data.\n");
|
|
- ret = ENOMEM;
|
|
- goto done;
|
|
- }
|
|
-
|
|
- data->user_verification = talloc_strdup(data, (char *) &buf[p]);
|
|
- if (data->user_verification == NULL) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "Failed to strdup passkey prompt.\n");
|
|
- ret = ENOMEM;
|
|
- goto done;
|
|
- }
|
|
-
|
|
- offset = strlen(data->user_verification) + 1;
|
|
- if (offset >= len) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "passkey prompt offset failure.\n");
|
|
- ret = EIO;
|
|
- goto done;
|
|
- }
|
|
-
|
|
- data->crypto_challenge = talloc_strdup(data, (char *) &buf[p + offset]);
|
|
- if (data->crypto_challenge == NULL) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "Failed to strdup passkey challenge.\n");
|
|
- ret = ENOMEM;
|
|
- goto done;
|
|
- }
|
|
-
|
|
- offset += strlen(data->crypto_challenge) + 1;
|
|
- if (offset >= len) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "passkey challenge offset failure.\n");
|
|
- ret = EIO;
|
|
- goto done;
|
|
- }
|
|
-
|
|
-
|
|
- data->domain = talloc_strdup(data, (char *) &buf[p] + offset);
|
|
- if (data->domain == NULL) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "Failed to strdup passkey domain.\n");
|
|
- ret = ENOMEM;
|
|
- goto done;
|
|
- }
|
|
-
|
|
- offset += strlen(data->domain) + 1;
|
|
- if (offset >= len) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "passkey domain offset failure.\n");
|
|
- ret = EIO;
|
|
- goto done;
|
|
- }
|
|
-
|
|
- SAFEALIGN_COPY_UINT32(&data->num_credentials, &buf[p + offset], &pctr);
|
|
- size_t list_sz = (size_t) data->num_credentials;
|
|
-
|
|
- offset += sizeof(uint32_t);
|
|
-
|
|
- data->key_handles = talloc_zero_array(data, const char *, list_sz);
|
|
-
|
|
- for (int i = 0; i < list_sz; i++) {
|
|
- data->key_handles[i] = talloc_strdup(data->key_handles, (char *) &buf[p + offset]);
|
|
- if (data->key_handles[i] == NULL) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "Failed to strdup passkey list.\n");
|
|
- ret = ENOMEM;
|
|
- goto done;
|
|
- }
|
|
-
|
|
- offset += strlen(data->key_handles[i]) + 1;
|
|
- }
|
|
-
|
|
- *_data = talloc_steal(mem_ctx, data);
|
|
-
|
|
- ret = EOK;
|
|
-done:
|
|
- talloc_free(tmp_ctx);
|
|
- return ret;
|
|
-}
|
|
-
|
|
-
|
|
-errno_t save_passkey_data(TALLOC_CTX *mem_ctx,
|
|
- struct pam_ctx *pctx,
|
|
- struct pk_child_user_data *data,
|
|
- struct pam_auth_req *preq)
|
|
-{
|
|
- char *pk_key;
|
|
- errno_t ret;
|
|
- TALLOC_CTX *tmp_ctx;
|
|
-
|
|
- tmp_ctx = talloc_new(NULL);
|
|
- if (tmp_ctx == NULL) {
|
|
- return ENOMEM;
|
|
- }
|
|
-
|
|
- /* Passkey data (pk_table_data) is stolen onto client ctx, it will
|
|
- * be freed when the client closes, and the sss_ptr_hash interface
|
|
- * takes care of automatically removing it from the hash table then */
|
|
- pctx->pk_table_data = talloc_zero(tmp_ctx, struct pam_passkey_table_data);
|
|
- if (pctx->pk_table_data == NULL) {
|
|
- return ENOMEM;
|
|
- }
|
|
-
|
|
- if (pctx->pk_table_data->table == NULL) {
|
|
- pctx->pk_table_data->table = sss_ptr_hash_create(pctx->pk_table_data,
|
|
- NULL, NULL);
|
|
- if (pctx->pk_table_data->table == NULL) {
|
|
- ret = ENOMEM;
|
|
- goto done;
|
|
- }
|
|
- }
|
|
-
|
|
- pk_key = talloc_asprintf(tmp_ctx, "%s", data->crypto_challenge);
|
|
- if (pk_key == NULL) {
|
|
- ret = ENOMEM;
|
|
- goto done;
|
|
- }
|
|
-
|
|
- pctx->pk_table_data->key = talloc_strdup(pctx->pk_table_data, pk_key);
|
|
- if (pctx->pk_table_data->key == NULL) {
|
|
- ret = ENOMEM;
|
|
- goto done;
|
|
- }
|
|
-
|
|
- ret = sss_ptr_hash_add(pctx->pk_table_data->table, pk_key, data,
|
|
- struct pk_child_user_data);
|
|
- if (ret == EEXIST) {
|
|
- DEBUG(SSSDBG_TRACE_FUNC, "pk_table key [%s] already exists\n",
|
|
- pk_key);
|
|
- goto done;
|
|
- } else if (ret != EOK) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "Unable to add pk data to hash table "
|
|
- "[%d]: %s\n", ret, sss_strerror(ret));
|
|
- goto done;
|
|
- }
|
|
-
|
|
- talloc_steal(mem_ctx, pctx->pk_table_data);
|
|
- pctx->pk_table_data->data = talloc_steal(mem_ctx, data);
|
|
-
|
|
- ret = EOK;
|
|
-
|
|
-done:
|
|
- talloc_free(tmp_ctx);
|
|
-
|
|
- return ret;
|
|
-}
|
|
-
|
|
-errno_t pam_eval_passkey_response(struct pam_ctx *pctx,
|
|
- struct pam_data *pd,
|
|
- struct pam_auth_req *preq,
|
|
- bool *_pk_preauth_done)
|
|
-{
|
|
- struct response_data *pk_resp;
|
|
- struct pk_child_user_data *pk_data;
|
|
- errno_t ret;
|
|
- TALLOC_CTX *tmp_ctx;
|
|
-
|
|
- tmp_ctx = talloc_new(NULL);
|
|
- if (tmp_ctx == NULL) {
|
|
- return ENOMEM;
|
|
- }
|
|
-
|
|
- pk_resp = pd->resp_list;
|
|
-
|
|
- while (pk_resp != NULL) {
|
|
- switch (pk_resp->type) {
|
|
- case SSS_PAM_PASSKEY_KRB_INFO:
|
|
- if (!pctx->passkey_auth) {
|
|
- /* Passkey auth is disabled. To avoid passkey prompts appearing,
|
|
- * don't send SSS_PAM_PASSKEY_KRB_INFO to the client and
|
|
- * add a dummy response to fallback to normal auth */
|
|
- pk_resp->do_not_send_to_client = true;
|
|
- ret = pam_add_response(pd, SSS_OTP, 0, NULL);
|
|
- if (ret != EOK) {
|
|
- DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
|
|
- goto done;
|
|
- }
|
|
- break;
|
|
- }
|
|
- ret = decode_pam_passkey_msg(tmp_ctx, pk_resp->data, pk_resp->len, &pk_data);
|
|
- if (ret != EOK) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "Failed to decode passkey msg\n");
|
|
- ret = EIO;
|
|
- goto done;
|
|
- }
|
|
-
|
|
- ret = save_passkey_data(preq->cctx, pctx, pk_data, preq);
|
|
- if (ret != EOK) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "Failed to save passkey msg\n");
|
|
- ret = EIO;
|
|
- goto done;
|
|
- }
|
|
- break;
|
|
- /* Passkey non-kerberos preauth has already run */
|
|
- case SSS_PAM_PASSKEY_INFO:
|
|
- *_pk_preauth_done = true;
|
|
- default:
|
|
- break;
|
|
- }
|
|
- pk_resp = pk_resp->next;
|
|
- }
|
|
-
|
|
- ret = EOK;
|
|
-done:
|
|
- talloc_free(tmp_ctx);
|
|
-
|
|
- return ret;
|
|
-}
|
|
-
|
|
void pam_reply(struct pam_auth_req *preq)
|
|
{
|
|
@@ -1342,6 +1110,7 @@ void pam_reply(struct pam_auth_req *preq)
|
|
"using defaults.\n");
|
|
}
|
|
|
|
+#ifdef BUILD_PASSKEY
|
|
ret = pam_eval_passkey_response(pctx, pd, preq, &pk_preauth_done);
|
|
if (ret != EOK) {
|
|
DEBUG(SSSDBG_OP_FAILURE, "Failed to eval passkey response\n");
|
|
@@ -1353,6 +1122,7 @@ void pam_reply(struct pam_auth_req *preq)
|
|
pam_check_user_done(preq, ret);
|
|
return;
|
|
}
|
|
+#endif /* BUILD_PASSKEY */
|
|
}
|
|
|
|
/*
|
|
@@ -1810,6 +1580,7 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
|
|
* It is checked in pam_reply() to avoid an endless loop */
|
|
preq->passkey_data_exists = true;
|
|
|
|
+#ifdef BUILD_PASSKEY
|
|
if ((pd->cmd == SSS_PAM_AUTHENTICATE)) {
|
|
if (may_do_passkey_auth(pctx, pd)) {
|
|
if (sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_PASSKEY_KRB) {
|
|
@@ -1822,6 +1593,7 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
|
|
}
|
|
}
|
|
}
|
|
+#endif /* BUILD_PASSKEY */
|
|
|
|
ret = pam_check_user_search(preq);
|
|
|
|
@@ -2220,6 +1992,7 @@ static void pam_forwarder_cb(struct tevent_req *req)
|
|
goto done;
|
|
}
|
|
|
|
+#ifdef BUILD_PASSKEY
|
|
/* This is set to false inside passkey_non_kerberos() if no passkey data is found.
|
|
* It is checked in pam_reply() to avoid an endless loop */
|
|
preq->passkey_data_exists = true;
|
|
@@ -2236,6 +2009,7 @@ static void pam_forwarder_cb(struct tevent_req *req)
|
|
}
|
|
}
|
|
}
|
|
+#endif /* BUILD_PASSKEY */
|
|
|
|
ret = pam_check_user_search(preq);
|
|
|
|
@@ -2557,127 +2331,6 @@ static bool pam_can_user_cache_auth(struct sss_domain_info *domain,
|
|
return result;
|
|
}
|
|
|
|
-void passkey_kerberos_cb(struct tevent_req *req)
|
|
-{
|
|
- struct pam_auth_req *preq = tevent_req_callback_data(req,
|
|
- struct pam_auth_req);
|
|
- errno_t ret = EOK;
|
|
- int child_status;
|
|
-
|
|
- ret = pam_passkey_auth_recv(req, &child_status);
|
|
- talloc_free(req);
|
|
- if (ret != EOK) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "PAM passkey auth failed [%d]: %s\n",
|
|
- ret, sss_strerror(ret));
|
|
- goto done;
|
|
- }
|
|
-
|
|
- DEBUG(SSSDBG_TRACE_FUNC, "passkey child finished with status [%d]\n", child_status);
|
|
-
|
|
- pam_check_user_search(preq);
|
|
-
|
|
-done:
|
|
- pam_check_user_done(preq, ret);
|
|
-}
|
|
-
|
|
-errno_t passkey_kerberos(struct pam_ctx *pctx,
|
|
- struct pam_data *pd,
|
|
- struct pam_auth_req *preq)
|
|
-{
|
|
- errno_t ret;
|
|
- const char *prompt;
|
|
- const char *key;
|
|
- const char *pin;
|
|
- size_t pin_len;
|
|
- struct pk_child_user_data *data;
|
|
- struct tevent_req *req;
|
|
- int timeout;
|
|
- char *verify_opts;
|
|
- bool debug_libfido2;
|
|
- enum passkey_user_verification verification;
|
|
-
|
|
- ret = sss_authtok_get_passkey(preq, preq->pd->authtok,
|
|
- &prompt, &key, &pin, &pin_len);
|
|
- if (ret != EOK) {
|
|
- DEBUG(SSSDBG_OP_FAILURE,
|
|
- "Failure to get passkey authtok\n");
|
|
- return EIO;
|
|
- }
|
|
-
|
|
- if (prompt == NULL || key == NULL) {
|
|
- DEBUG(SSSDBG_OP_FAILURE,
|
|
- "Passkey prompt and key are missing or invalid.\n");
|
|
- return EIO;
|
|
- }
|
|
-
|
|
- data = sss_ptr_hash_lookup(pctx->pk_table_data->table, key,
|
|
- struct pk_child_user_data);
|
|
- if (data == NULL) {
|
|
- DEBUG(SSSDBG_OP_FAILURE,
|
|
- "Failed to lookup passkey authtok\n");
|
|
- return EIO;
|
|
- }
|
|
-
|
|
- ret = confdb_get_int(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
|
|
- CONFDB_PAM_PASSKEY_CHILD_TIMEOUT, PASSKEY_CHILD_TIMEOUT_DEFAULT,
|
|
- &timeout);
|
|
- if (ret != EOK) {
|
|
- DEBUG(SSSDBG_OP_FAILURE,
|
|
- "Failed to read passkey_child_timeout from confdb: [%d]: %s\n",
|
|
- ret, sss_strerror(ret));
|
|
- goto done;
|
|
- }
|
|
-
|
|
- ret = confdb_get_string(pctx->rctx->cdb, preq, CONFDB_MONITOR_CONF_ENTRY,
|
|
- CONFDB_MONITOR_PASSKEY_VERIFICATION, NULL,
|
|
- &verify_opts);
|
|
- if (ret != EOK) {
|
|
- DEBUG(SSSDBG_OP_FAILURE,
|
|
- "Failed to read '"CONFDB_MONITOR_PASSKEY_VERIFICATION"' from confdb: [%d]: %s\n",
|
|
- ret, sss_strerror(ret));
|
|
- goto done;
|
|
- }
|
|
-
|
|
- /* Always use verification sent from passkey krb5 plugin */
|
|
- ret = read_passkey_conf_verification(preq, verify_opts, NULL);
|
|
- if (ret != EOK) {
|
|
- DEBUG(SSSDBG_MINOR_FAILURE, "Unable to parse passkey verificaton options.\n");
|
|
- }
|
|
-
|
|
- if (strcasecmp(data->user_verification, "false") == 0) {
|
|
- verification = PAM_PASSKEY_VERIFICATION_OFF;
|
|
- } else {
|
|
- verification = PAM_PASSKEY_VERIFICATION_ON;
|
|
- }
|
|
-
|
|
- ret = confdb_get_bool(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
|
|
- CONFDB_PAM_PASSKEY_DEBUG_LIBFIDO2, false,
|
|
- &debug_libfido2);
|
|
- if (ret != EOK) {
|
|
- DEBUG(SSSDBG_OP_FAILURE,
|
|
- "Failed to read '"CONFDB_PAM_PASSKEY_DEBUG_LIBFIDO2"' from confdb: [%d]: %s\n",
|
|
- ret, sss_strerror(ret));
|
|
- goto done;
|
|
- }
|
|
-
|
|
- req = pam_passkey_auth_send(preq->cctx, preq->cctx->ev, timeout, debug_libfido2,
|
|
- verification, pd, data, true);
|
|
- if (req == NULL) {
|
|
- DEBUG(SSSDBG_OP_FAILURE, "passkey auth send failed [%d]: [%s]\n",
|
|
- ret, sss_strerror(ret));
|
|
- goto done;
|
|
- }
|
|
-
|
|
- tevent_req_set_callback(req, passkey_kerberos_cb, preq);
|
|
-
|
|
- ret = EAGAIN;
|
|
-
|
|
-done:
|
|
-
|
|
- return ret;
|
|
-
|
|
-}
|
|
-
|
|
static void pam_dom_forwarder(struct pam_auth_req *preq)
|
|
{
|
|
int ret;
|
|
diff --git a/src/responder/pam/pamsrv_passkey.c b/src/responder/pam/pamsrv_passkey.c
|
|
index eb62db03d7..57cba845ae 100644
|
|
--- a/src/responder/pam/pamsrv_passkey.c
|
|
+++ b/src/responder/pam/pamsrv_passkey.c
|
|
@@ -32,6 +32,12 @@ struct pam_passkey_verification_enum_str {
|
|
const char *option;
|
|
};
|
|
|
|
+struct pam_passkey_table_data {
|
|
+ hash_table_t *table;
|
|
+ char *key;
|
|
+ struct pk_child_user_data *data;
|
|
+};
|
|
+
|
|
struct pam_passkey_verification_enum_str pam_passkey_verification_enum_str[] = {
|
|
{ PAM_PASSKEY_VERIFICATION_ON, "on" },
|
|
{ PAM_PASSKEY_VERIFICATION_OFF, "off" },
|
|
@@ -85,6 +91,127 @@ struct passkey_get_mapping_state {
|
|
struct cache_req_result *result;
|
|
};
|
|
|
|
+void passkey_kerberos_cb(struct tevent_req *req)
|
|
+{
|
|
+ struct pam_auth_req *preq = tevent_req_callback_data(req,
|
|
+ struct pam_auth_req);
|
|
+ errno_t ret = EOK;
|
|
+ int child_status;
|
|
+
|
|
+ ret = pam_passkey_auth_recv(req, &child_status);
|
|
+ talloc_free(req);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "PAM passkey auth failed [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_FUNC, "passkey child finished with status [%d]\n", child_status);
|
|
+
|
|
+ pam_check_user_search(preq);
|
|
+
|
|
+done:
|
|
+ pam_check_user_done(preq, ret);
|
|
+}
|
|
+
|
|
+errno_t passkey_kerberos(struct pam_ctx *pctx,
|
|
+ struct pam_data *pd,
|
|
+ struct pam_auth_req *preq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ const char *prompt;
|
|
+ const char *key;
|
|
+ const char *pin;
|
|
+ size_t pin_len;
|
|
+ struct pk_child_user_data *data;
|
|
+ struct tevent_req *req;
|
|
+ int timeout;
|
|
+ char *verify_opts;
|
|
+ bool debug_libfido2;
|
|
+ enum passkey_user_verification verification;
|
|
+
|
|
+ ret = sss_authtok_get_passkey(preq, preq->pd->authtok,
|
|
+ &prompt, &key, &pin, &pin_len);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Failure to get passkey authtok\n");
|
|
+ return EIO;
|
|
+ }
|
|
+
|
|
+ if (prompt == NULL || key == NULL) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Passkey prompt and key are missing or invalid.\n");
|
|
+ return EIO;
|
|
+ }
|
|
+
|
|
+ data = sss_ptr_hash_lookup(pctx->pk_table_data->table, key,
|
|
+ struct pk_child_user_data);
|
|
+ if (data == NULL) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Failed to lookup passkey authtok\n");
|
|
+ return EIO;
|
|
+ }
|
|
+
|
|
+ ret = confdb_get_int(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
|
|
+ CONFDB_PAM_PASSKEY_CHILD_TIMEOUT, PASSKEY_CHILD_TIMEOUT_DEFAULT,
|
|
+ &timeout);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Failed to read passkey_child_timeout from confdb: [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ ret = confdb_get_string(pctx->rctx->cdb, preq, CONFDB_MONITOR_CONF_ENTRY,
|
|
+ CONFDB_MONITOR_PASSKEY_VERIFICATION, NULL,
|
|
+ &verify_opts);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Failed to read '"CONFDB_MONITOR_PASSKEY_VERIFICATION"' from confdb: [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ /* Always use verification sent from passkey krb5 plugin */
|
|
+ ret = read_passkey_conf_verification(preq, verify_opts, NULL);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to parse passkey verificaton options.\n");
|
|
+ }
|
|
+
|
|
+ if (strcasecmp(data->user_verification, "false") == 0) {
|
|
+ verification = PAM_PASSKEY_VERIFICATION_OFF;
|
|
+ } else {
|
|
+ verification = PAM_PASSKEY_VERIFICATION_ON;
|
|
+ }
|
|
+
|
|
+ ret = confdb_get_bool(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
|
|
+ CONFDB_PAM_PASSKEY_DEBUG_LIBFIDO2, false,
|
|
+ &debug_libfido2);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Failed to read '"CONFDB_PAM_PASSKEY_DEBUG_LIBFIDO2"' from confdb: [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ req = pam_passkey_auth_send(preq->cctx, preq->cctx->ev, timeout, debug_libfido2,
|
|
+ verification, pd, data, true);
|
|
+ if (req == NULL) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "passkey auth send failed [%d]: [%s]\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ tevent_req_set_callback(req, passkey_kerberos_cb, preq);
|
|
+
|
|
+ ret = EAGAIN;
|
|
+
|
|
+done:
|
|
+
|
|
+ return ret;
|
|
+
|
|
+}
|
|
+
|
|
errno_t passkey_non_kerberos(TALLOC_CTX *mem_ctx,
|
|
struct tevent_context *ev,
|
|
struct pam_ctx *pam_ctx,
|
|
@@ -994,6 +1121,229 @@ errno_t pam_passkey_auth_recv(struct tevent_req *req,
|
|
return EOK;
|
|
}
|
|
|
|
+errno_t decode_pam_passkey_msg(TALLOC_CTX *mem_ctx,
|
|
+ uint8_t *buf,
|
|
+ size_t len,
|
|
+ struct pk_child_user_data **_data)
|
|
+{
|
|
+
|
|
+ size_t p = 0;
|
|
+ size_t pctr = 0;
|
|
+ errno_t ret;
|
|
+ size_t offset;
|
|
+ struct pk_child_user_data *data = NULL;
|
|
+ TALLOC_CTX *tmp_ctx;
|
|
+
|
|
+ tmp_ctx = talloc_new(NULL);
|
|
+ if (tmp_ctx == NULL) {
|
|
+ return ENOMEM;
|
|
+ }
|
|
+
|
|
+ data = talloc_zero(tmp_ctx, struct pk_child_user_data);
|
|
+ if (data == NULL) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to talloc passkey data.\n");
|
|
+ ret = ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ data->user_verification = talloc_strdup(data, (char *) &buf[p]);
|
|
+ if (data->user_verification == NULL) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to strdup passkey prompt.\n");
|
|
+ ret = ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ offset = strlen(data->user_verification) + 1;
|
|
+ if (offset >= len) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "passkey prompt offset failure.\n");
|
|
+ ret = EIO;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ data->crypto_challenge = talloc_strdup(data, (char *) &buf[p + offset]);
|
|
+ if (data->crypto_challenge == NULL) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to strdup passkey challenge.\n");
|
|
+ ret = ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ offset += strlen(data->crypto_challenge) + 1;
|
|
+ if (offset >= len) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "passkey challenge offset failure.\n");
|
|
+ ret = EIO;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+
|
|
+ data->domain = talloc_strdup(data, (char *) &buf[p] + offset);
|
|
+ if (data->domain == NULL) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to strdup passkey domain.\n");
|
|
+ ret = ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ offset += strlen(data->domain) + 1;
|
|
+ if (offset >= len) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "passkey domain offset failure.\n");
|
|
+ ret = EIO;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ SAFEALIGN_COPY_UINT32(&data->num_credentials, &buf[p + offset], &pctr);
|
|
+ size_t list_sz = (size_t) data->num_credentials;
|
|
+
|
|
+ offset += sizeof(uint32_t);
|
|
+
|
|
+ data->key_handles = talloc_zero_array(data, const char *, list_sz);
|
|
+
|
|
+ for (int i = 0; i < list_sz; i++) {
|
|
+ data->key_handles[i] = talloc_strdup(data->key_handles, (char *) &buf[p + offset]);
|
|
+ if (data->key_handles[i] == NULL) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to strdup passkey list.\n");
|
|
+ ret = ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ offset += strlen(data->key_handles[i]) + 1;
|
|
+ }
|
|
+
|
|
+ *_data = talloc_steal(mem_ctx, data);
|
|
+
|
|
+ ret = EOK;
|
|
+done:
|
|
+ talloc_free(tmp_ctx);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+errno_t save_passkey_data(TALLOC_CTX *mem_ctx,
|
|
+ struct pam_ctx *pctx,
|
|
+ struct pk_child_user_data *data,
|
|
+ struct pam_auth_req *preq)
|
|
+{
|
|
+ char *pk_key;
|
|
+ errno_t ret;
|
|
+ TALLOC_CTX *tmp_ctx;
|
|
+
|
|
+ tmp_ctx = talloc_new(NULL);
|
|
+ if (tmp_ctx == NULL) {
|
|
+ return ENOMEM;
|
|
+ }
|
|
+
|
|
+ /* Passkey data (pk_table_data) is stolen onto client ctx, it will
|
|
+ * be freed when the client closes, and the sss_ptr_hash interface
|
|
+ * takes care of automatically removing it from the hash table then */
|
|
+ pctx->pk_table_data = talloc_zero(tmp_ctx, struct pam_passkey_table_data);
|
|
+ if (pctx->pk_table_data == NULL) {
|
|
+ return ENOMEM;
|
|
+ }
|
|
+
|
|
+ if (pctx->pk_table_data->table == NULL) {
|
|
+ pctx->pk_table_data->table = sss_ptr_hash_create(pctx->pk_table_data,
|
|
+ NULL, NULL);
|
|
+ if (pctx->pk_table_data->table == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pk_key = talloc_asprintf(tmp_ctx, "%s", data->crypto_challenge);
|
|
+ if (pk_key == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ pctx->pk_table_data->key = talloc_strdup(pctx->pk_table_data, pk_key);
|
|
+ if (pctx->pk_table_data->key == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ ret = sss_ptr_hash_add(pctx->pk_table_data->table, pk_key, data,
|
|
+ struct pk_child_user_data);
|
|
+ if (ret == EEXIST) {
|
|
+ DEBUG(SSSDBG_TRACE_FUNC, "pk_table key [%s] already exists\n",
|
|
+ pk_key);
|
|
+ goto done;
|
|
+ } else if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to add pk data to hash table "
|
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ talloc_steal(mem_ctx, pctx->pk_table_data);
|
|
+ pctx->pk_table_data->data = talloc_steal(mem_ctx, data);
|
|
+
|
|
+ ret = EOK;
|
|
+
|
|
+done:
|
|
+ talloc_free(tmp_ctx);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+errno_t pam_eval_passkey_response(struct pam_ctx *pctx,
|
|
+ struct pam_data *pd,
|
|
+ struct pam_auth_req *preq,
|
|
+ bool *_pk_preauth_done)
|
|
+{
|
|
+ struct response_data *pk_resp;
|
|
+ struct pk_child_user_data *pk_data;
|
|
+ errno_t ret;
|
|
+ TALLOC_CTX *tmp_ctx;
|
|
+
|
|
+ tmp_ctx = talloc_new(NULL);
|
|
+ if (tmp_ctx == NULL) {
|
|
+ return ENOMEM;
|
|
+ }
|
|
+
|
|
+ pk_resp = pd->resp_list;
|
|
+
|
|
+ while (pk_resp != NULL) {
|
|
+ switch (pk_resp->type) {
|
|
+ case SSS_PAM_PASSKEY_KRB_INFO:
|
|
+ if (!pctx->passkey_auth) {
|
|
+ /* Passkey auth is disabled. To avoid passkey prompts appearing,
|
|
+ * don't send SSS_PAM_PASSKEY_KRB_INFO to the client and
|
|
+ * add a dummy response to fallback to normal auth */
|
|
+ pk_resp->do_not_send_to_client = true;
|
|
+ ret = pam_add_response(pd, SSS_OTP, 0, NULL);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
|
|
+ goto done;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ ret = decode_pam_passkey_msg(tmp_ctx, pk_resp->data, pk_resp->len, &pk_data);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to decode passkey msg\n");
|
|
+ ret = EIO;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ ret = save_passkey_data(preq->cctx, pctx, pk_data, preq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to save passkey msg\n");
|
|
+ ret = EIO;
|
|
+ goto done;
|
|
+ }
|
|
+ break;
|
|
+ /* Passkey non-kerberos preauth has already run */
|
|
+ case SSS_PAM_PASSKEY_INFO:
|
|
+ *_pk_preauth_done = true;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ pk_resp = pk_resp->next;
|
|
+ }
|
|
+
|
|
+ ret = EOK;
|
|
+done:
|
|
+ talloc_free(tmp_ctx);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+
|
|
static void
|
|
pam_passkey_auth_done(int child_status,
|
|
struct tevent_signal *sige,
|
|
diff --git a/src/responder/pam/pamsrv_passkey.h b/src/responder/pam/pamsrv_passkey.h
|
|
index 6b0d62071f..7c5a532e91 100644
|
|
--- a/src/responder/pam/pamsrv_passkey.h
|
|
+++ b/src/responder/pam/pamsrv_passkey.h
|
|
@@ -23,6 +23,7 @@
|
|
|
|
#include <security/pam_appl.h>
|
|
#include "util/util.h"
|
|
+#include "util/sss_ptr_hash.h"
|
|
#include "responder/common/responder.h"
|
|
#include "responder/common/cache_req/cache_req.h"
|
|
#include "responder/pam/pamsrv.h"
|
|
@@ -40,6 +41,9 @@ errno_t passkey_non_kerberos(TALLOC_CTX *mem_ctx,
|
|
struct pam_ctx *pam_ctx,
|
|
struct pam_auth_req *preq,
|
|
struct pam_data *pd);
|
|
+errno_t passkey_kerberos(struct pam_ctx *pctx,
|
|
+ struct pam_data *pd,
|
|
+ struct pam_auth_req *preq);
|
|
|
|
struct pk_child_user_data {
|
|
/* Both Kerberos and non-kerberos */
|
|
@@ -69,6 +73,10 @@ struct tevent_req *pam_passkey_auth_send(TALLOC_CTX *mem_ctx,
|
|
bool kerberos_pa);
|
|
errno_t pam_passkey_auth_recv(struct tevent_req *req,
|
|
int *child_status);
|
|
+errno_t pam_eval_passkey_response(struct pam_ctx *pctx,
|
|
+ struct pam_data *pd,
|
|
+ struct pam_auth_req *preq,
|
|
+ bool *_pk_preauth_done);
|
|
bool may_do_passkey_auth(struct pam_ctx *pctx,
|
|
struct pam_data *pd);
|
|
|