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

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