summaryrefslogtreecommitdiffstats
path: root/src/responder/pam
diff options
context:
space:
mode:
Diffstat (limited to 'src/responder/pam')
-rw-r--r--src/responder/pam/pamsrv.h11
-rw-r--r--src/responder/pam/pamsrv_cmd.c32
-rw-r--r--src/responder/pam/pamsrv_passkey.c73
-rw-r--r--src/responder/pam/pamsrv_passkey.h4
4 files changed, 89 insertions, 31 deletions
diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
index 7013a8e..2aa14ae 100644
--- a/src/responder/pam/pamsrv.h
+++ b/src/responder/pam/pamsrv.h
@@ -93,7 +93,17 @@ struct pam_auth_req {
struct ldb_message *user_obj;
struct cert_auth_info *cert_list;
struct cert_auth_info *current_cert;
+ /* Switched to 'true' if the backend indicates that it cannot handle
+ * Smartcard authentication, but Smartcard authentication is
+ * possible and local Smartcard authentication is allowed. */
bool cert_auth_local;
+ /* Switched to 'true' if authentication (not pre-authentication) was
+ * started without a login name and the name had to be lookup up with the
+ * certificate used for authentication. Since reading the certificate from
+ * the Smartcard already involves the PIN validation in this case there
+ * would be no need for an additional Smartcard interaction if only local
+ * Smartcard authentication is possible. */
+ bool initial_cert_auth_successful;
bool passkey_data_exists;
uint32_t client_id_num;
@@ -104,6 +114,7 @@ struct pam_resp_auth_type {
bool otp_auth;
bool cert_auth;
bool passkey_auth;
+ bool backend_returned_no_auth_type;
};
struct sss_cmd_table *get_pam_cmds(void);
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index c23ea7b..1394147 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -915,6 +915,7 @@ errno_t pam_get_auth_types(struct pam_data *pd,
/* If the backend cannot determine which authentication types are
* available the default would be to prompt for a password. */
types.password_auth = true;
+ types.backend_returned_no_auth_type = true;
}
DEBUG(SSSDBG_TRACE_ALL, "Authentication types for user [%s] and service "
@@ -1002,7 +1003,7 @@ static errno_t pam_eval_local_auth_policy(TALLOC_CTX *mem_ctx,
}
/* Store the local auth types, in case we go offline */
- if (!auth_types.password_auth) {
+ if (!auth_types.backend_returned_no_auth_type) {
ret = set_local_auth_type(preq, sc_allow, passkey_allow);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
@@ -1418,6 +1419,15 @@ void pam_reply(struct pam_auth_req *preq)
goto done;
}
+#ifdef BUILD_PASSKEY
+ if(pd->cmd == SSS_PAM_AUTHENTICATE &&
+ pd->pam_status == PAM_NEW_AUTHTOK_REQD &&
+ sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_PASSKEY_REPLY) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Passkey authentication reply, ignoring "
+ "new authtok required status\n");
+ pd->pam_status = PAM_SUCCESS;
+ }
+
/* Passkey auth user notification if no TGT is granted */
if (pd->cmd == SSS_PAM_AUTHENTICATE &&
pd->pam_status == PAM_SUCCESS &&
@@ -1429,6 +1439,7 @@ void pam_reply(struct pam_auth_req *preq)
"User [%s] logged in with local passkey authentication, single "
"sign on ticket is not obtained.\n", pd->user);
}
+#endif /* BUILD_PASSKEY */
/* Account expiration warning is printed for sshd. If pam_verbosity
* is equal or above PAM_VERBOSITY_INFO then all services are informed
@@ -1918,7 +1929,7 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
ret = pam_forwarder_parse_data(cctx, pd);
if (ret == EAGAIN) {
- req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true, pd->domain);
+ req = sss_dp_get_domains_send(cctx, cctx->rctx, true, pd->domain);
if (req == NULL) {
ret = ENOMEM;
} else {
@@ -2200,8 +2211,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
ret = ENOENT;
goto done;
}
-
- if (cert_count > 1) {
+ /* Multiple certificates are only expected during pre-auth */
+ if (cert_count > 1 && preq->pd->cmd == SSS_PAM_PREAUTH) {
for (preq->current_cert = preq->cert_list;
preq->current_cert != NULL;
preq->current_cert = sss_cai_get_next(preq->current_cert)) {
@@ -2285,7 +2296,9 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
}
/* If logon_name was not given during authentication add a
- * SSS_PAM_CERT_INFO message to send the name to the caller. */
+ * SSS_PAM_CERT_INFO message to send the name to the caller.
+ * Additionally initial_cert_auth_successful is set to
+ * indicate that the user is already authenticated. */
if (preq->pd->cmd == SSS_PAM_AUTHENTICATE
&& preq->pd->logon_name == NULL) {
ret = add_pam_cert_response(preq->pd,
@@ -2297,6 +2310,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
goto done;
}
+
+ preq->initial_cert_auth_successful = true;
}
/* cert_user will be returned to the PAM client as user name, so
@@ -2851,12 +2866,15 @@ static void pam_dom_forwarder(struct pam_auth_req *preq)
if (found) {
if (local_policy != NULL && strcasecmp(local_policy, "only") == 0) {
talloc_free(tmp_ctx);
- DEBUG(SSSDBG_IMPORTANT_INFO, "Local auth only set, skipping online auth\n");
+ DEBUG(SSSDBG_IMPORTANT_INFO,
+ "Local auth only set and matching certificate was found, "
+ "skipping online auth\n");
if (preq->pd->cmd == SSS_PAM_PREAUTH) {
preq->pd->pam_status = PAM_SUCCESS;
} else if (preq->pd->cmd == SSS_PAM_AUTHENTICATE
&& IS_SC_AUTHTOK(preq->pd->authtok)
- && preq->cert_auth_local) {
+ && (preq->cert_auth_local
+ || preq->initial_cert_auth_successful)) {
preq->pd->pam_status = PAM_SUCCESS;
preq->callback = pam_reply;
}
diff --git a/src/responder/pam/pamsrv_passkey.c b/src/responder/pam/pamsrv_passkey.c
index 1125840..4a6bf0d 100644
--- a/src/responder/pam/pamsrv_passkey.c
+++ b/src/responder/pam/pamsrv_passkey.c
@@ -463,6 +463,32 @@ done:
return ret;
}
+static bool mapping_is_passkey(TALLOC_CTX *tmp_ctx,
+ const char *mapping_str)
+{
+ int ret;
+ char **mappings;
+
+ if (mapping_str == NULL) {
+ return false;
+ }
+
+ ret = split_on_separator(tmp_ctx, (const char *) mapping_str, ':', true, true,
+ &mappings, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Incorrectly formatted passkey data [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return false;
+ }
+
+ if (strcasecmp(mappings[0], "passkey") != 0) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Mapping data found is not passkey related\n");
+ return false;
+ }
+
+ return true;
+}
+
errno_t process_passkey_data(TALLOC_CTX *mem_ctx,
struct ldb_message *user_mesg,
const char *domain,
@@ -471,6 +497,7 @@ errno_t process_passkey_data(TALLOC_CTX *mem_ctx,
struct ldb_message_element *el;
TALLOC_CTX *tmp_ctx;
int ret;
+ int num_creds = 0;
char **mappings;
const char **kh_mappings;
const char **public_keys;
@@ -489,22 +516,6 @@ errno_t process_passkey_data(TALLOC_CTX *mem_ctx,
goto done;
}
- /* This attribute may contain other mapping data unrelated to passkey. In that case
- * let's omit it. For example, AD user altSecurityIdentities may store ssh public key
- * or smart card mapping data */
- ret = split_on_separator(tmp_ctx, (const char *) el->values[0].data, ':', true, true,
- &mappings, NULL);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Incorrectly formatted passkey data [%d]: %s\n",
- ret, sss_strerror(ret));
- ret = ENOENT;
- goto done;
- } else if (strcasecmp(mappings[0], "passkey") != 0) {
- DEBUG(SSSDBG_TRACE_FUNC, "Mapping data found is not passkey related\n");
- ret = ENOENT;
- goto done;
- }
-
kh_mappings = talloc_zero_array(tmp_ctx, const char *, el->num_values + 1);
if (kh_mappings == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
@@ -520,6 +531,12 @@ errno_t process_passkey_data(TALLOC_CTX *mem_ctx,
}
for (int i = 0; i < el->num_values; i++) {
+ /* This attribute may contain other mapping data unrelated to passkey. In that case
+ * let's skip it. For example, AD user altSecurityIdentities may store ssh public key
+ * or smart card mapping data */
+ if ((mapping_is_passkey(tmp_ctx, (const char *)el->values[i].data)) == false) {
+ continue;
+ }
ret = split_on_separator(tmp_ctx, (const char *) el->values[i].data, ',', true, true,
&mappings, NULL);
if (ret != EOK) {
@@ -528,19 +545,26 @@ errno_t process_passkey_data(TALLOC_CTX *mem_ctx,
goto done;
}
- kh_mappings[i] = talloc_strdup(kh_mappings, mappings[0] + strlen(PASSKEY_PREFIX));
- if (kh_mappings[i] == NULL) {
+ kh_mappings[num_creds] = talloc_strdup(kh_mappings, mappings[0] + strlen(PASSKEY_PREFIX));
+ if (kh_mappings[num_creds] == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup key handle failed.\n");
ret = ENOMEM;
goto done;
}
- public_keys[i] = talloc_strdup(public_keys, mappings[1]);
- if (public_keys[i] == NULL) {
+ public_keys[num_creds] = talloc_strdup(public_keys, mappings[1]);
+ if (public_keys[num_creds] == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup public key failed.\n");
ret = ENOMEM;
goto done;
}
+
+ num_creds++;
+ }
+
+ if (num_creds == 0) {
+ ret = ENOENT;
+ goto done;
}
domain_name = talloc_strdup(tmp_ctx, domain);
@@ -553,7 +577,7 @@ errno_t process_passkey_data(TALLOC_CTX *mem_ctx,
_data->domain = talloc_steal(mem_ctx, domain_name);
_data->key_handles = talloc_steal(mem_ctx, kh_mappings);
_data->public_keys = talloc_steal(mem_ctx, public_keys);
- _data->num_credentials = el->num_values;
+ _data->num_credentials = num_creds;
ret = EOK;
done:
@@ -707,10 +731,11 @@ done:
pctx->preq->passkey_data_exists = false;
pam_check_user_search(pctx->preq);
} else if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Unexpected passkey error [%d]: %s."
- " Skipping passkey auth\n",
+ DEBUG(SSSDBG_OP_FAILURE, "Unexpected passkey error [%d]: %s.\n",
ret, sss_strerror(ret));
- pam_check_user_search(pctx->preq);
+ pctx->preq->passkey_data_exists = false;
+ pctx->preq->pd->pam_status = PAM_SYSTEM_ERR;
+ pam_reply(pctx->preq);
}
return;
diff --git a/src/responder/pam/pamsrv_passkey.h b/src/responder/pam/pamsrv_passkey.h
index 7c5a532..48074d0 100644
--- a/src/responder/pam/pamsrv_passkey.h
+++ b/src/responder/pam/pamsrv_passkey.h
@@ -77,6 +77,10 @@ errno_t pam_eval_passkey_response(struct pam_ctx *pctx,
struct pam_data *pd,
struct pam_auth_req *preq,
bool *_pk_preauth_done);
+errno_t process_passkey_data(TALLOC_CTX *mem_ctx,
+ struct ldb_message *user_mesg,
+ const char *domain,
+ struct pk_child_user_data *_data);
bool may_do_passkey_auth(struct pam_ctx *pctx,
struct pam_data *pd);