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