sssd/SOURCES/0017-pam-Conditionalize-passkey-code.patch
eabdullin d405959af2 - Apply 0008-DP-reduce-log-level-in-case-a-responder-asks.patch
- 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
2024-01-25 14:36:52 +03:00

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);