|
|
bb7cd1 |
From 19cb2e2d826dc4e3c938c5a6b51a03338e80fa9e Mon Sep 17 00:00:00 2001
|
|
|
bb7cd1 |
From: Sumit Bose <sbose@redhat.com>
|
|
|
bb7cd1 |
Date: Mon, 8 May 2017 16:01:26 +0200
|
|
|
bb7cd1 |
Subject: [PATCH 156/160] pam_sss: add support for SSS_PAM_CERT_INFO_WITH_HINT
|
|
|
bb7cd1 |
MIME-Version: 1.0
|
|
|
bb7cd1 |
Content-Type: text/plain; charset=UTF-8
|
|
|
bb7cd1 |
Content-Transfer-Encoding: 8bit
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
The new response type SSS_PAM_CERT_INFO_WITH_HINT is equivalent to
|
|
|
bb7cd1 |
SSS_PAM_CERT_INFO but tells pam_sss to prompt for an option user name as
|
|
|
bb7cd1 |
well.
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
Resolves:
|
|
|
bb7cd1 |
https://pagure.io/SSSD/sssd/issue/3395
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
Reviewed-by: Fabiano FidĂȘncio <fidencio@redhat.com>
|
|
|
bb7cd1 |
(cherry picked from commit a192a1d72e92dae3e71e062b333e51a5095a0395)
|
|
|
bb7cd1 |
---
|
|
|
bb7cd1 |
src/sss_client/pam_message.h | 1 +
|
|
|
bb7cd1 |
src/sss_client/pam_sss.c | 129 ++++++++++++++++++++++++++++++++++++++-----
|
|
|
bb7cd1 |
src/sss_client/sss_cli.h | 11 +++-
|
|
|
bb7cd1 |
3 files changed, 127 insertions(+), 14 deletions(-)
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h
|
|
|
bb7cd1 |
index 3f4a770ac08ee416ead2f215ab873e8eb277c9eb..f215392f6879f01a0ca12abc8807bac5fc1f1cbb 100644
|
|
|
bb7cd1 |
--- a/src/sss_client/pam_message.h
|
|
|
bb7cd1 |
+++ b/src/sss_client/pam_message.h
|
|
|
bb7cd1 |
@@ -63,6 +63,7 @@ struct pam_items {
|
|
|
bb7cd1 |
char *token_name;
|
|
|
bb7cd1 |
char *module_name;
|
|
|
bb7cd1 |
char *key_id;
|
|
|
bb7cd1 |
+ bool user_name_hint;
|
|
|
bb7cd1 |
};
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer);
|
|
|
bb7cd1 |
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
|
|
|
bb7cd1 |
index db0dcb9de7b893850bcea96a9cdf76dc0b36dcee..1c06079967e3d9076d537c3de8aba93e13f76d09 100644
|
|
|
bb7cd1 |
--- a/src/sss_client/pam_sss.c
|
|
|
bb7cd1 |
+++ b/src/sss_client/pam_sss.c
|
|
|
bb7cd1 |
@@ -982,6 +982,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
break;
|
|
|
bb7cd1 |
case SSS_PAM_CERT_INFO:
|
|
|
bb7cd1 |
+ case SSS_PAM_CERT_INFO_WITH_HINT:
|
|
|
bb7cd1 |
if (buf[p + (len - 1)] != '\0') {
|
|
|
bb7cd1 |
D(("cert info does not end with \\0."));
|
|
|
bb7cd1 |
break;
|
|
|
bb7cd1 |
@@ -994,7 +995,19 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
|
|
|
bb7cd1 |
break;
|
|
|
bb7cd1 |
}
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
- if (pi->pam_user == NULL || *(pi->pam_user) == '\0') {
|
|
|
bb7cd1 |
+ if (type == SSS_PAM_CERT_INFO && pi->cert_user == '\0') {
|
|
|
bb7cd1 |
+ D(("Invalid CERT message"));
|
|
|
bb7cd1 |
+ break;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ if (type == SSS_PAM_CERT_INFO_WITH_HINT) {
|
|
|
bb7cd1 |
+ pi->user_name_hint = true;
|
|
|
bb7cd1 |
+ } else {
|
|
|
bb7cd1 |
+ pi->user_name_hint = false;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ if ((pi->pam_user == NULL || *(pi->pam_user) == '\0')
|
|
|
bb7cd1 |
+ && pi->cert_user != '\0') {
|
|
|
bb7cd1 |
ret = pam_set_item(pamh, PAM_USER, pi->cert_user);
|
|
|
bb7cd1 |
if (ret != PAM_SUCCESS) {
|
|
|
bb7cd1 |
D(("Failed to set PAM_USER during "
|
|
|
bb7cd1 |
@@ -1469,7 +1482,7 @@ done:
|
|
|
bb7cd1 |
return ret;
|
|
|
bb7cd1 |
}
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
-#define SC_PROMPT_FMT "PIN for %s for user %s"
|
|
|
bb7cd1 |
+#define SC_PROMPT_FMT "PIN for %s"
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
|
|
|
bb7cd1 |
{
|
|
|
bb7cd1 |
@@ -1478,32 +1491,108 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
|
|
|
bb7cd1 |
char *prompt;
|
|
|
bb7cd1 |
size_t size;
|
|
|
bb7cd1 |
size_t needed_size;
|
|
|
bb7cd1 |
+ const struct pam_conv *conv;
|
|
|
bb7cd1 |
+ const struct pam_message *mesg[2] = { NULL, NULL };
|
|
|
bb7cd1 |
+ struct pam_message m[2] = { { 0 }, { 0 } };
|
|
|
bb7cd1 |
+ struct pam_response *resp = NULL;
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
- if (pi->token_name == NULL || *pi->token_name == '\0'
|
|
|
bb7cd1 |
- || pi->cert_user == NULL || *pi->cert_user == '\0') {
|
|
|
bb7cd1 |
+ if (pi->token_name == NULL || *pi->token_name == '\0') {
|
|
|
bb7cd1 |
return EINVAL;
|
|
|
bb7cd1 |
}
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
- size = sizeof(SC_PROMPT_FMT) + strlen(pi->token_name) +
|
|
|
bb7cd1 |
- strlen(pi->cert_user);
|
|
|
bb7cd1 |
+ size = sizeof(SC_PROMPT_FMT) + strlen(pi->token_name);
|
|
|
bb7cd1 |
prompt = malloc(size);
|
|
|
bb7cd1 |
if (prompt == NULL) {
|
|
|
bb7cd1 |
D(("malloc failed."));
|
|
|
bb7cd1 |
return ENOMEM;
|
|
|
bb7cd1 |
}
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
- ret = snprintf(prompt, size, SC_PROMPT_FMT, pi->token_name, pi->cert_user);
|
|
|
bb7cd1 |
+ ret = snprintf(prompt, size, SC_PROMPT_FMT, pi->token_name);
|
|
|
bb7cd1 |
if (ret < 0 || ret >= size) {
|
|
|
bb7cd1 |
D(("snprintf failed."));
|
|
|
bb7cd1 |
free(prompt);
|
|
|
bb7cd1 |
return EFAULT;
|
|
|
bb7cd1 |
}
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
- ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, &answer);
|
|
|
bb7cd1 |
- free(prompt);
|
|
|
bb7cd1 |
- if (ret != PAM_SUCCESS) {
|
|
|
bb7cd1 |
- D(("do_pam_conversation failed."));
|
|
|
bb7cd1 |
- return ret;
|
|
|
bb7cd1 |
+ if (pi->user_name_hint) {
|
|
|
bb7cd1 |
+ ret = pam_get_item(pamh, PAM_CONV, (const void **)&conv;;
|
|
|
bb7cd1 |
+ if (ret != PAM_SUCCESS) {
|
|
|
bb7cd1 |
+ return ret;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+ if (conv == NULL || conv->conv == NULL) {
|
|
|
bb7cd1 |
+ logger(pamh, LOG_ERR, "No conversation function");
|
|
|
bb7cd1 |
+ return PAM_SYSTEM_ERR;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ m[0].msg_style = PAM_PROMPT_ECHO_OFF;
|
|
|
bb7cd1 |
+ m[0].msg = prompt;
|
|
|
bb7cd1 |
+ m[1].msg_style = PAM_PROMPT_ECHO_ON;
|
|
|
bb7cd1 |
+ m[1].msg = "User name hint: ";
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ mesg[0] = (const struct pam_message *)m;
|
|
|
bb7cd1 |
+ /* The following assignment might look a bit odd but is recommended in the
|
|
|
bb7cd1 |
+ * pam_conv man page to make sure that the second argument of the PAM
|
|
|
bb7cd1 |
+ * conversation function can be interpreted in two different ways.
|
|
|
bb7cd1 |
+ * Basically it is important that both the actual struct pam_message and
|
|
|
bb7cd1 |
+ * the pointers to the struct pam_message are arrays. Since the assignment
|
|
|
bb7cd1 |
+ * makes clear that mesg[] and (*mesg)[] are arrays it should be kept this
|
|
|
bb7cd1 |
+ * way and not be replaced by other equivalent assignments. */
|
|
|
bb7cd1 |
+ mesg[1] = &((*mesg)[1]);
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ ret = conv->conv(2, mesg, &resp, conv->appdata_ptr);
|
|
|
bb7cd1 |
+ if (ret != PAM_SUCCESS) {
|
|
|
bb7cd1 |
+ D(("Conversation failure: %s.", pam_strerror(pamh, ret)));
|
|
|
bb7cd1 |
+ return ret;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ if (resp == NULL) {
|
|
|
bb7cd1 |
+ D(("response expected, but resp==NULL"));
|
|
|
bb7cd1 |
+ return PAM_SYSTEM_ERR;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ if (resp[0].resp == NULL || *(resp[0].resp) == '\0') {
|
|
|
bb7cd1 |
+ D(("Missing PIN."));
|
|
|
bb7cd1 |
+ ret = PAM_CRED_INSUFFICIENT;
|
|
|
bb7cd1 |
+ goto done;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ answer = strndup(resp[0].resp, MAX_AUTHTOK_SIZE);
|
|
|
bb7cd1 |
+ _pam_overwrite((void *)resp[0].resp);
|
|
|
bb7cd1 |
+ free(resp[0].resp);
|
|
|
bb7cd1 |
+ resp[0].resp = NULL;
|
|
|
bb7cd1 |
+ if (answer == NULL) {
|
|
|
bb7cd1 |
+ D(("strndup failed"));
|
|
|
bb7cd1 |
+ ret = PAM_BUF_ERR;
|
|
|
bb7cd1 |
+ goto done;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ if (resp[1].resp != NULL && *(resp[1].resp) != '\0') {
|
|
|
bb7cd1 |
+ ret = pam_set_item(pamh, PAM_USER, resp[1].resp);
|
|
|
bb7cd1 |
+ free(resp[1].resp);
|
|
|
bb7cd1 |
+ resp[1].resp = NULL;
|
|
|
bb7cd1 |
+ if (ret != PAM_SUCCESS) {
|
|
|
bb7cd1 |
+ D(("Failed to set PAM_USER with user name hint [%s]",
|
|
|
bb7cd1 |
+ pam_strerror(pamh, ret)));
|
|
|
bb7cd1 |
+ goto done;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ ret = pam_get_item(pamh, PAM_USER, (const void **)&(pi->pam_user));
|
|
|
bb7cd1 |
+ if (ret != PAM_SUCCESS) {
|
|
|
bb7cd1 |
+ D(("Failed to get PAM_USER with user name hint [%s]",
|
|
|
bb7cd1 |
+ pam_strerror(pamh, ret)));
|
|
|
bb7cd1 |
+ goto done;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ pi->pam_user_size = strlen(pi->pam_user) + 1;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+ } else {
|
|
|
bb7cd1 |
+ ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL,
|
|
|
bb7cd1 |
+ &answer);
|
|
|
bb7cd1 |
+ free(prompt);
|
|
|
bb7cd1 |
+ if (ret != PAM_SUCCESS) {
|
|
|
bb7cd1 |
+ D(("do_pam_conversation failed."));
|
|
|
bb7cd1 |
+ return ret;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
}
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
if (answer == NULL) {
|
|
|
bb7cd1 |
@@ -1552,6 +1641,20 @@ done:
|
|
|
bb7cd1 |
free(answer);
|
|
|
bb7cd1 |
answer=NULL;
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
+ if (resp != NULL) {
|
|
|
bb7cd1 |
+ if (resp[0].resp != NULL) {
|
|
|
bb7cd1 |
+ _pam_overwrite((void *)resp[0].resp);
|
|
|
bb7cd1 |
+ free(resp[0].resp);
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+ if (resp[1].resp != NULL) {
|
|
|
bb7cd1 |
+ _pam_overwrite((void *)resp[1].resp);
|
|
|
bb7cd1 |
+ free(resp[1].resp);
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
+ free(resp);
|
|
|
bb7cd1 |
+ resp = NULL;
|
|
|
bb7cd1 |
+ }
|
|
|
bb7cd1 |
+
|
|
|
bb7cd1 |
return ret;
|
|
|
bb7cd1 |
}
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
@@ -1680,7 +1783,7 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
|
|
|
bb7cd1 |
ret = prompt_2fa(pamh, pi, _("First Factor: "),
|
|
|
bb7cd1 |
_("Second Factor: "));
|
|
|
bb7cd1 |
}
|
|
|
bb7cd1 |
- } else if (pi->cert_user != NULL) {
|
|
|
bb7cd1 |
+ } else if (pi->token_name != NULL && *(pi->token_name) != '\0') {
|
|
|
bb7cd1 |
ret = prompt_sc_pin(pamh, pi);
|
|
|
bb7cd1 |
} else {
|
|
|
bb7cd1 |
ret = prompt_password(pamh, pi, _("Password: "));
|
|
|
bb7cd1 |
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
|
|
|
bb7cd1 |
index 59fee7a4eceb2c185e156e812af7f2f4c6b2a0dd..d4198407f2f86c6594aee6a2a43775e429692df0 100644
|
|
|
bb7cd1 |
--- a/src/sss_client/sss_cli.h
|
|
|
bb7cd1 |
+++ b/src/sss_client/sss_cli.h
|
|
|
bb7cd1 |
@@ -427,7 +427,13 @@ enum response_type {
|
|
|
bb7cd1 |
* @param Three zero terminated strings, if one of the
|
|
|
bb7cd1 |
* strings is missing the message will contain only
|
|
|
bb7cd1 |
* an empty string (\0) for that component. */
|
|
|
bb7cd1 |
- SSS_PAM_CERT_INFO,
|
|
|
bb7cd1 |
+ SSS_PAM_CERT_INFO, /**< A message indicating that Smartcard/certificate
|
|
|
bb7cd1 |
+ * based authentication is available and contains
|
|
|
bb7cd1 |
+ * details about the found Smartcard.
|
|
|
bb7cd1 |
+ * @param user name, zero terminated
|
|
|
bb7cd1 |
+ * @param token name, zero terminated
|
|
|
bb7cd1 |
+ * @param PKCS#11 module name, zero terminated
|
|
|
bb7cd1 |
+ * @param key id, zero terminated */
|
|
|
bb7cd1 |
SSS_OTP, /**< Indicates that the autotok was a OTP, so don't
|
|
|
bb7cd1 |
* cache it. There is no message.
|
|
|
bb7cd1 |
* @param None. */
|
|
|
bb7cd1 |
@@ -442,6 +448,9 @@ enum response_type {
|
|
|
bb7cd1 |
* be used together with other prompting options
|
|
|
bb7cd1 |
* to determine the type of prompting.
|
|
|
bb7cd1 |
* @param None. */
|
|
|
bb7cd1 |
+ SSS_PAM_CERT_INFO_WITH_HINT, /**< Same as SSS_PAM_CERT_INFO but user name
|
|
|
bb7cd1 |
+ * might be missing and should be prompted
|
|
|
bb7cd1 |
+ * for. */
|
|
|
bb7cd1 |
};
|
|
|
bb7cd1 |
|
|
|
bb7cd1 |
/**
|
|
|
bb7cd1 |
--
|
|
|
bb7cd1 |
2.9.4
|
|
|
bb7cd1 |
|