dpward / rpms / sssd

Forked from rpms/sssd 3 years ago
Clone
Blob Blame History Raw
From f724123e20f8d4a1c85473d917da6c65a10d6d62 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 18 Sep 2018 09:53:37 +0200
Subject: [PATCH 41/47] pam_sss: add option require_cert_auth

With this new option pam_sss will wait until a Smartcard is available
and then try to authenticate with the help of the Smartcard.

Related https://pagure.io/SSSD/sssd/issue/3650

Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
(cherry picked from commit 49be8974b490c368d349752f3196af0c9ed28dd5)
---
 src/man/pam_sss.8.xml          | 25 ++++++++++++
 src/responder/pam/pamsrv_cmd.c | 12 ++++++
 src/responder/pam/pamsrv_p11.c |  5 ++-
 src/sss_client/pam_message.c   |  4 ++
 src/sss_client/pam_message.h   |  1 +
 src/sss_client/pam_sss.c       | 92 ++++++++++++++++++++++++++----------------
 src/sss_client/sss_cli.h       |  2 +
 src/util/sss_pam_data.c        |  1 +
 src/util/sss_pam_data.h        |  1 +
 9 files changed, 107 insertions(+), 36 deletions(-)

diff --git a/src/man/pam_sss.8.xml b/src/man/pam_sss.8.xml
index ca2e8e20678d102525a9252678dd83459c3338ac..9998519f16c934e0d578760a57cc0908db760bfb 100644
--- a/src/man/pam_sss.8.xml
+++ b/src/man/pam_sss.8.xml
@@ -53,6 +53,9 @@
             <arg choice='opt'>
                 <replaceable>try_cert_auth</replaceable>
             </arg>
+            <arg choice='opt'>
+                <replaceable>require_cert_auth</replaceable>
+            </arg>
         </cmdsynopsis>
     </refsynopsisdiv>
 
@@ -223,6 +226,28 @@ auth sufficient pam_sss.so allow_missing_name
                     </para>
                 </listitem>
             </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>require_cert_auth</option>
+                </term>
+                <listitem>
+                    <para>
+                        Do certificate based authentication, i.e.
+                        authentication with a Smartcard or similar devices. If a
+                        Smartcard is not available the user will be prompted to
+                        insert one. SSSD will wait for a Smartcard until the
+                        timeout defined by p11_wait_for_card_timeout passed,
+                        please see
+                        <citerefentry><refentrytitle>sssd.conf</refentrytitle>
+                        <manvolnum>5</manvolnum></citerefentry> for details.
+                    </para>
+                    <para>
+                        If no Smartcard is available after the timeout or
+                        certificate based authentication is not allowed for the
+                        current service PAM_AUTHINFO_UNAVAIL is returned.
+                    </para>
+                </listitem>
+            </varlistentry>
         </variablelist>
     </refsect1>
 
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index c8df32de9e72e9f5ce33e26f0a13101a99f01d5f..6e37f831602e4c367176cc14126dbbec72c858cd 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -317,6 +317,11 @@ static int pam_parse_in_data_v2(struct pam_data *pd,
                                              size, body, blen, &c);
                     if (ret != EOK) return ret;
                     break;
+                case SSS_PAM_ITEM_FLAGS:
+                    ret = extract_uint32_t(&pd->cli_flags, size,
+                                           body, blen, &c);
+                    if (ret != EOK) return ret;
+                    break;
                 default:
                     DEBUG(SSSDBG_CRIT_FAILURE,
                           "Ignoring unknown data type [%d].\n", type);
@@ -1447,6 +1452,13 @@ static void pam_forwarder_cert_cb(struct tevent_req *req)
                   "No certificate found and no logon name given, " \
                   "authentication not possible.\n");
             ret = ENOENT;
+        } else if (pd->cli_flags & PAM_CLI_FLAGS_TRY_CERT_AUTH) {
+            DEBUG(SSSDBG_TRACE_ALL,
+                  "try_cert_auth flag set but no certificate available, "
+                  "request finished.\n");
+            preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
+            pam_reply(preq);
+            return;
         } else {
             if (pd->cmd == SSS_PAM_AUTHENTICATE) {
                 DEBUG(SSSDBG_CRIT_FAILURE,
diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
index ffa6787e967488ac408ce0f0a11b96066c29b630..8b8859d9d335aec6d310201256522fa8afdd3694 100644
--- a/src/responder/pam/pamsrv_p11.c
+++ b/src/responder/pam/pamsrv_p11.c
@@ -721,7 +721,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
     struct timeval tv;
     int pipefd_to_child[2] = PIPE_INIT;
     int pipefd_from_child[2] = PIPE_INIT;
-    const char *extra_args[13] = { NULL };
+    const char *extra_args[14] = { NULL };
     uint8_t *write_buf = NULL;
     size_t write_buf_len = 0;
     size_t arg_c;
@@ -748,6 +748,9 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
 
     /* extra_args are added in revers order */
     arg_c = 0;
+    if ((pd->cli_flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH) && pd->priv == 1) {
+        extra_args[arg_c++] = "--wait_for_card";
+    }
     extra_args[arg_c++] = nss_db;
     extra_args[arg_c++] = "--nssdb";
     if (verify_opts != NULL) {
diff --git a/src/sss_client/pam_message.c b/src/sss_client/pam_message.c
index b239f6f53da54054c52e484bdd076193709cb003..036ae2ad17742c123ba59e39a122ea605b7b95a6 100644
--- a/src/sss_client/pam_message.c
+++ b/src/sss_client/pam_message.c
@@ -126,6 +126,7 @@ int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer)
     len += 3*sizeof(uint32_t); /* cli_pid */
     len += *pi->requested_domains != '\0' ?
                 2*sizeof(uint32_t) + pi->requested_domains_size : 0;
+    len += 3*sizeof(uint32_t); /* flags */
 
     buf = malloc(len);
     if (buf == NULL) {
@@ -164,6 +165,9 @@ int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer)
                            pi->pam_newauthtok, pi->pam_newauthtok_size,
                            &buf[rp]);
 
+    rp += add_uint32_t_item(SSS_PAM_ITEM_FLAGS, (uint32_t) pi->flags,
+                            &buf[rp]);
+
     SAFEALIGN_SETMEM_UINT32(buf + rp, SSS_END_OF_PAM_REQUEST, &rp);
 
     if (rp != len) {
diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h
index 11526a80a767ff5602b194d14765ff261e8f9707..50fedcd82d8ace520d0360d85d163f91df0cb100 100644
--- a/src/sss_client/pam_message.h
+++ b/src/sss_client/pam_message.h
@@ -51,6 +51,7 @@ struct pam_items {
     enum sss_authtok_type pam_newauthtok_type;
     size_t pam_newauthtok_size;
     pid_t cli_pid;
+    uint32_t flags;
     const char *login_name;
     char *domain_name;
     const char *requested_domains;
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
index 96ff15adad867aceae17431cd5256ae52e4b9306..b4c1036ad68a97821f5d0aee873fa18fe5e72683 100644
--- a/src/sss_client/pam_sss.c
+++ b/src/sss_client/pam_sss.c
@@ -134,6 +134,7 @@ static void free_cai(struct cert_auth_info *cai)
         free(cai->cert_user);
         free(cai->cert);
         free(cai->token_name);
+        free(cai->module_name);
         free(cai->key_id);
         free(cai->prompt_str);
         free(cai);
@@ -1247,6 +1248,8 @@ static int get_pam_items(pam_handle_t *pamh, uint32_t flags,
     pi->cert_list = NULL;
     pi->selected_cert = NULL;
 
+    pi->flags = flags;
+
     return PAM_SUCCESS;
 }
 
@@ -1267,6 +1270,7 @@ static void print_pam_items(struct pam_items *pi)
     D(("Newauthtok: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_newauthtok)));
     D(("Cli_PID: %d", pi->cli_pid));
     D(("Requested domains: %s", pi->requested_domains));
+    D(("Flags: %d", pi->flags));
 }
 
 static int send_and_receive(pam_handle_t *pamh, struct pam_items *pi,
@@ -1999,6 +2003,8 @@ static void eval_argv(pam_handle_t *pamh, int argc, const char **argv,
             *flags |= PAM_CLI_FLAGS_PROMPT_ALWAYS;
         } else if (strcmp(*argv, "try_cert_auth") == 0) {
             *flags |= PAM_CLI_FLAGS_TRY_CERT_AUTH;
+        } else if (strcmp(*argv, "require_cert_auth") == 0) {
+            *flags |= PAM_CLI_FLAGS_REQUIRE_CERT_AUTH;
         } else {
             logger(pamh, LOG_WARNING, "unknown option: %s", *argv);
         }
@@ -2274,55 +2280,51 @@ static int get_authtok_for_password_change(pam_handle_t *pamh,
     return PAM_SUCCESS;
 }
 
-#define SC_ENTER_FMT "Please enter smart card labeled\n %s\nand press enter"
+#define SC_ENTER_LABEL_FMT "Please enter smart card labeled\n %s"
+#define SC_ENTER_FMT "Please enter smart card"
 
 static int check_login_token_name(pam_handle_t *pamh, struct pam_items *pi,
-                                  bool quiet_mode)
+                                  int retries, bool quiet_mode)
 {
     int ret;
     int pam_status;
     char *login_token_name;
     char *prompt = NULL;
-    size_t size;
-    char *answer = NULL;
-    /* TODO: check multiple cert case */
-    struct cert_auth_info *cai = pi->cert_list;
-
-    if (cai == NULL) {
-        D(("No certificate information available"));
-        return EINVAL;
-    }
+    uint32_t orig_flags = pi->flags;
 
     login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME");
+    if (login_token_name == NULL
+            && !(pi->flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH)) {
+        return PAM_SUCCESS;
+    }
+
     if (login_token_name == NULL) {
-        return PAM_SUCCESS;
+        ret = asprintf(&prompt, SC_ENTER_FMT);
+    } else {
+        ret = asprintf(&prompt, SC_ENTER_LABEL_FMT, login_token_name);
+    }
+    if (ret == -1) {
+        return ENOMEM;
     }
 
-    while (cai->token_name == NULL
-               || strcmp(login_token_name, cai->token_name) != 0) {
-        size = sizeof(SC_ENTER_FMT) + strlen(login_token_name);
-        prompt = malloc(size);
-        if (prompt == NULL) {
-            D(("malloc failed."));
-            return ENOMEM;
-        }
+    pi->flags |= PAM_CLI_FLAGS_REQUIRE_CERT_AUTH;
+
+    /* TODO: check multiple cert case */
+    while (pi->cert_list == NULL || pi->cert_list->token_name == NULL
+                || (login_token_name != NULL
+                        && strcmp(login_token_name,
+                                  pi->cert_list->token_name) != 0)) {
 
-        ret = snprintf(prompt, size, SC_ENTER_FMT,
-                       login_token_name);
-        if (ret < 0 || ret >= size) {
-            D(("snprintf failed."));
-            free(prompt);
-            return EFAULT;
+        if (retries < 0) {
+            ret = PAM_AUTHINFO_UNAVAIL;
+            goto done;
         }
+        retries--;
 
-        ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt,
-                                  NULL, &answer);
-        free(prompt);
+        ret = do_pam_conversation(pamh, PAM_TEXT_INFO, prompt, NULL, NULL);
         if (ret != PAM_SUCCESS) {
             D(("do_pam_conversation failed."));
-            return ret;
-        } else {
-            free(answer);
+            goto done;
         }
 
         pam_status = send_and_receive(pamh, pi, SSS_PAM_PREAUTH, quiet_mode);
@@ -2335,7 +2337,14 @@ static int check_login_token_name(pam_handle_t *pamh, struct pam_items *pi,
         }
     }
 
-    return PAM_SUCCESS;
+    ret = PAM_SUCCESS;
+
+done:
+
+    pi->flags = orig_flags;
+    free(prompt);
+
+    return ret;
 }
 
 static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
@@ -2394,8 +2403,19 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
                         && (pi.pam_authtok == NULL
                                 || (flags & PAM_CLI_FLAGS_PROMPT_ALWAYS))
                         && access(PAM_PREAUTH_INDICATOR, F_OK) == 0) {
+
+                    if (flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH) {
+                        /* Do not use PAM_CLI_FLAGS_REQUIRE_CERT_AUTH in the first
+                         * SSS_PAM_PREAUTH run. In case a card is already inserted
+                         * we do not have to prompt to insert a card. */
+                        pi.flags &= ~PAM_CLI_FLAGS_REQUIRE_CERT_AUTH;
+                        pi.flags |= PAM_CLI_FLAGS_TRY_CERT_AUTH;
+                    }
+
                     pam_status = send_and_receive(pamh, &pi, SSS_PAM_PREAUTH,
                                                   quiet_mode);
+
+                    pi.flags = flags;
                     if (pam_status != PAM_SUCCESS) {
                         D(("send_and_receive returned [%d] during pre-auth",
                            pam_status));
@@ -2414,8 +2434,10 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
                     return PAM_AUTHINFO_UNAVAIL;
                 }
 
-                if (strcmp(pi.pam_service, "gdm-smartcard") == 0) {
-                    ret = check_login_token_name(pamh, &pi, quiet_mode);
+                if (strcmp(pi.pam_service, "gdm-smartcard") == 0
+                        || (flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH)) {
+                    ret = check_login_token_name(pamh, &pi, retries,
+                                                 quiet_mode);
                     if (ret != PAM_SUCCESS) {
                         D(("check_login_token_name failed.\n"));
                         return ret;
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index 38e3f999d799556a56ac08f0f3a6b538b8cde9f3..af8a43916d43b631092941fed13c520273a1acc5 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -363,6 +363,7 @@ enum pam_item_type {
     SSS_PAM_ITEM_CLI_LOCALE,
     SSS_PAM_ITEM_CLI_PID,
     SSS_PAM_ITEM_REQUESTED_DOMAINS,
+    SSS_PAM_ITEM_FLAGS,
 };
 
 #define PAM_CLI_FLAGS_USE_FIRST_PASS (1 << 0)
@@ -374,6 +375,7 @@ enum pam_item_type {
 #define PAM_CLI_FLAGS_ALLOW_MISSING_NAME (1 << 6)
 #define PAM_CLI_FLAGS_PROMPT_ALWAYS (1 << 7)
 #define PAM_CLI_FLAGS_TRY_CERT_AUTH (1 << 8)
+#define PAM_CLI_FLAGS_REQUIRE_CERT_AUTH (1 << 9)
 
 #define SSS_NSS_MAX_ENTRIES 256
 #define SSS_NSS_HEADER_SIZE (sizeof(uint32_t) * 4)
diff --git a/src/util/sss_pam_data.c b/src/util/sss_pam_data.c
index 5e41349b9e98974563bf55c41ce36c26b897ac99..cb8779c1dff04832f623eb518d2b010107d4b045 100644
--- a/src/util/sss_pam_data.c
+++ b/src/util/sss_pam_data.c
@@ -176,6 +176,7 @@ void pam_print_data(int l, struct pam_data *pd)
     DEBUG(l, "priv: %d\n", pd->priv);
     DEBUG(l, "cli_pid: %d\n", pd->cli_pid);
     DEBUG(l, "logon name: %s\n", PAM_SAFE_ITEM(pd->logon_name));
+    DEBUG(l, "flags: %d\n", pd->cli_flags);
 }
 
 int pam_add_response(struct pam_data *pd, enum response_type type,
diff --git a/src/util/sss_pam_data.h b/src/util/sss_pam_data.h
index 7d74fa6a0026d3964f33c8529063b1dceae45688..c9898105418fc76b45d78883a0520f37d0ae1c05 100644
--- a/src/util/sss_pam_data.h
+++ b/src/util/sss_pam_data.h
@@ -58,6 +58,7 @@ struct pam_data {
     struct sss_auth_token *newauthtok;
     uint32_t cli_pid;
     char *logon_name;
+    uint32_t cli_flags;
 
     int pam_status;
     int response_delay;
-- 
2.14.4