Blame SOURCES/0018-pam_sss-use-configured-prompting.patch

841ac7
From 6b7ce87976ebba7b3c1aea24dbf91486ec5de2ed Mon Sep 17 00:00:00 2001
841ac7
From: Sumit Bose <sbose@redhat.com>
841ac7
Date: Wed, 27 Mar 2019 09:48:42 +0100
841ac7
Subject: [PATCH 18/21] pam_sss: use configured prompting
841ac7
841ac7
If the responds of SSSD's PAM responder contains a prompt_config
841ac7
structure use the content to prompt the user for credentials.
841ac7
841ac7
Related to https://pagure.io/SSSD/sssd/issue/3264
841ac7
841ac7
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
841ac7
(cherry picked with fixes from commit fc26b4a82d4a92b29cf321fba8dbec52c3bff8d6)
841ac7
---
841ac7
 src/sss_client/pam_message.h |   2 +
841ac7
 src/sss_client/pam_sss.c     | 136 +++++++++++++++++++++++++++++------
841ac7
 src/sss_client/sss_cli.h     |   3 +
841ac7
 3 files changed, 119 insertions(+), 22 deletions(-)
841ac7
841ac7
diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h
841ac7
index 11526a80a..c87162479 100644
841ac7
--- a/src/sss_client/pam_message.h
841ac7
+++ b/src/sss_client/pam_message.h
841ac7
@@ -64,6 +64,8 @@ struct pam_items {
841ac7
     bool user_name_hint;
841ac7
     struct cert_auth_info *cert_list;
841ac7
     struct cert_auth_info *selected_cert;
841ac7
+
841ac7
+    struct prompt_config **pc;
841ac7
 };
841ac7
 
841ac7
 int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer);
841ac7
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
841ac7
index 59081cc67..ab9b7478e 100644
841ac7
--- a/src/sss_client/pam_sss.c
841ac7
+++ b/src/sss_client/pam_sss.c
841ac7
@@ -205,6 +205,9 @@ static void overwrite_and_free_pam_items(struct pam_items *pi)
841ac7
     free_cert_list(pi->cert_list);
841ac7
     pi->cert_list = NULL;
841ac7
     pi->selected_cert = NULL;
841ac7
+
841ac7
+    pc_list_free(pi->pc);
841ac7
+    pi->pc = NULL;
841ac7
 }
841ac7
 
841ac7
 static int null_strcmp(const char *s1, const char *s2) {
841ac7
@@ -1163,6 +1166,16 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
841ac7
                 D(("Password prompting available."));
841ac7
                 pi->password_prompting = true;
841ac7
                 break;
841ac7
+            case SSS_PAM_PROMPT_CONFIG:
841ac7
+                if (pi->pc == NULL) {
841ac7
+                    ret = pc_list_from_response(len, &buf[p], &pi->pc);
841ac7
+                    if (ret != EOK) {
841ac7
+                        D(("Failed to parse prompting data, using defaults"));
841ac7
+                        pc_list_free(pi->pc);
841ac7
+                        pi->pc = NULL;
841ac7
+                    }
841ac7
+                }
841ac7
+                break;
841ac7
             default:
841ac7
                 D(("Unknown response type [%d]", type));
841ac7
         }
841ac7
@@ -1256,6 +1269,8 @@ static int get_pam_items(pam_handle_t *pamh, uint32_t flags,
841ac7
     pi->cert_list = NULL;
841ac7
     pi->selected_cert = NULL;
841ac7
 
841ac7
+    pi->pc = NULL;
841ac7
+
841ac7
     return PAM_SUCCESS;
841ac7
 }
841ac7
 
841ac7
@@ -1558,6 +1573,37 @@ done:
841ac7
     return ret;
841ac7
 }
841ac7
 
841ac7
+static int prompt_2fa_single(pam_handle_t *pamh, struct pam_items *pi,
841ac7
+                             const char *prompt)
841ac7
+{
841ac7
+    int ret;
841ac7
+    char *answer = NULL;
841ac7
+
841ac7
+    ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, &answer);
841ac7
+    if (ret != PAM_SUCCESS) {
841ac7
+        D(("do_pam_conversation failed."));
841ac7
+        return ret;
841ac7
+    }
841ac7
+
841ac7
+    if (answer == NULL) {
841ac7
+        pi->pam_authtok = NULL;
841ac7
+        pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
841ac7
+        pi->pam_authtok_size=0;
841ac7
+    } else {
841ac7
+        pi->pam_authtok = strdup(answer);
841ac7
+        _pam_overwrite((void *)answer);
841ac7
+        free(answer);
841ac7
+        answer=NULL;
841ac7
+        if (pi->pam_authtok == NULL) {
841ac7
+            return PAM_BUF_ERR;
841ac7
+        }
841ac7
+        pi->pam_authtok_type = SSS_AUTHTOK_TYPE_2FA_SINGLE;
841ac7
+        pi->pam_authtok_size=strlen(pi->pam_authtok);
841ac7
+    }
841ac7
+
841ac7
+    return PAM_SUCCESS;
841ac7
+}
841ac7
+
841ac7
 #define SC_PROMPT_FMT "PIN for %s"
841ac7
 
841ac7
 #ifndef discard_const
841ac7
@@ -2014,6 +2060,48 @@ static void eval_argv(pam_handle_t *pamh, int argc, const char **argv,
841ac7
     return;
841ac7
 }
841ac7
 
841ac7
+static int prompt_by_config(pam_handle_t *pamh, struct pam_items *pi)
841ac7
+{
841ac7
+    size_t c;
841ac7
+    int ret;
841ac7
+
841ac7
+    if (pi->pc == NULL || *pi->pc == NULL) {
841ac7
+        return EINVAL;
841ac7
+    }
841ac7
+
841ac7
+    for (c = 0; pi->pc[c] != NULL; c++) {
841ac7
+        switch (pc_get_type(pi->pc[c])) {
841ac7
+        case PC_TYPE_PASSWORD:
841ac7
+            ret = prompt_password(pamh, pi, pc_get_password_prompt(pi->pc[c]));
841ac7
+            break;
841ac7
+        case PC_TYPE_2FA:
841ac7
+            ret = prompt_2fa(pamh, pi, pc_get_2fa_1st_prompt(pi->pc[c]),
841ac7
+                             pc_get_2fa_2nd_prompt(pi->pc[c]));
841ac7
+            break;
841ac7
+        case PC_TYPE_2FA_SINGLE:
841ac7
+            ret = prompt_2fa_single(pamh, pi,
841ac7
+                                    pc_get_2fa_single_prompt(pi->pc[c]));
841ac7
+            break;
841ac7
+        case PC_TYPE_SC_PIN:
841ac7
+            ret = prompt_sc_pin(pamh, pi);
841ac7
+            /* Todo: add extra string option */
841ac7
+            break;
841ac7
+        default:
841ac7
+            ret = EINVAL;
841ac7
+        }
841ac7
+
841ac7
+        /* If not credential where given try the next type otherwise we are
841ac7
+         * done. */
841ac7
+        if (ret == PAM_SUCCESS && pi->pam_authtok_size == 0) {
841ac7
+            continue;
841ac7
+        }
841ac7
+
841ac7
+        break;
841ac7
+    }
841ac7
+
841ac7
+    return ret;
841ac7
+}
841ac7
+
841ac7
 static int get_authtok_for_authentication(pam_handle_t *pamh,
841ac7
                                           struct pam_items *pi,
841ac7
                                           uint32_t flags)
841ac7
@@ -2032,30 +2120,34 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
841ac7
         }
841ac7
         pi->pam_authtok_size = strlen(pi->pam_authtok);
841ac7
     } else {
841ac7
-        if (flags & FLAGS_USE_2FA
841ac7
-                || (pi->otp_vendor != NULL && pi->otp_token_id != NULL
841ac7
-                        && pi->otp_challenge != NULL)) {
841ac7
-            if (pi->password_prompting) {
841ac7
-                ret = prompt_2fa(pamh, pi, _("First Factor: "),
841ac7
-                                 _("Second Factor (optional): "));
841ac7
-            } else {
841ac7
-                ret = prompt_2fa(pamh, pi, _("First Factor: "),
841ac7
-                                 _("Second Factor: "));
841ac7
-            }
841ac7
-        } else if (pi->cert_list != NULL) {
841ac7
-            if (pi->cert_list->next == NULL) {
841ac7
-                /* Only one certificate */
841ac7
-                pi->selected_cert = pi->cert_list;
841ac7
-            } else {
841ac7
-                ret = prompt_multi_cert(pamh, pi);
841ac7
-                if (ret != 0) {
841ac7
-                    D(("Failed to select certificate"));
841ac7
-                    return PAM_AUTHTOK_ERR;
841ac7
+        if (pi->pc != NULL) {
841ac7
+            ret = prompt_by_config(pamh, pi);
841ac7
+        } else {
841ac7
+            if (flags & FLAGS_USE_2FA
841ac7
+                    || (pi->otp_vendor != NULL && pi->otp_token_id != NULL
841ac7
+                            && pi->otp_challenge != NULL)) {
841ac7
+                if (pi->password_prompting) {
841ac7
+                    ret = prompt_2fa(pamh, pi, _("First Factor: "),
841ac7
+                                     _("Second Factor (optional): "));
841ac7
+                } else {
841ac7
+                    ret = prompt_2fa(pamh, pi, _("First Factor: "),
841ac7
+                                     _("Second Factor: "));
841ac7
                 }
841ac7
+            } else if (pi->cert_list != NULL) {
841ac7
+                if (pi->cert_list->next == NULL) {
841ac7
+                    /* Only one certificate */
841ac7
+                    pi->selected_cert = pi->cert_list;
841ac7
+                } else {
841ac7
+                    ret = prompt_multi_cert(pamh, pi);
841ac7
+                    if (ret != 0) {
841ac7
+                        D(("Failed to select certificate"));
841ac7
+                        return PAM_AUTHTOK_ERR;
841ac7
+                    }
841ac7
+                }
841ac7
+                ret = prompt_sc_pin(pamh, pi);
841ac7
+            } else {
841ac7
+                ret = prompt_password(pamh, pi, _("Password: "));
841ac7
             }
841ac7
-            ret = prompt_sc_pin(pamh, pi);
841ac7
-        } else {
841ac7
-            ret = prompt_password(pamh, pi, _("Password: "));
841ac7
         }
841ac7
         if (ret != PAM_SUCCESS) {
841ac7
             D(("failed to get password from user"));
841ac7
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
841ac7
index 23ef21608..24b24a91b 100644
841ac7
--- a/src/sss_client/sss_cli.h
841ac7
+++ b/src/sss_client/sss_cli.h
841ac7
@@ -469,6 +469,9 @@ enum response_type {
841ac7
     SSS_PAM_CERT_INFO_WITH_HINT, /**< Same as SSS_PAM_CERT_INFO but user name
841ac7
                                   * might be missing and should be prompted
841ac7
                                   * for. */
841ac7
+    SSS_PAM_PROMPT_CONFIG, /**< Contains data which controls which credentials
841ac7
+                            * are expected and how the user is prompted for
841ac7
+                            * them. */
841ac7
 };
841ac7
 
841ac7
 /**
841ac7
-- 
841ac7
2.19.1
841ac7