Blame SOURCES/0043-pam-filter-certificates-in-the-responder-not-in-the-.patch

9f2ebf
From 69c820abacd963a3699fc9ea84a17bb99f9eaf3a Mon Sep 17 00:00:00 2001
9f2ebf
From: Sumit Bose <sbose@redhat.com>
9f2ebf
Date: Mon, 6 Nov 2017 15:26:38 +0100
9f2ebf
Subject: [PATCH 43/46] pam: filter certificates in the responder not in the
9f2ebf
 child
9f2ebf
MIME-Version: 1.0
9f2ebf
Content-Type: text/plain; charset=UTF-8
9f2ebf
Content-Transfer-Encoding: 8bit
9f2ebf
9f2ebf
With the new selection option and the handling of multiple certificates
9f2ebf
in the PAM responder it is not needed anymore to filter the certificates
9f2ebf
in p11_child but the matching rules can be applied by the PAM responder
9f2ebf
directly.
9f2ebf
9f2ebf
Related to https://pagure.io/SSSD/sssd/issue/3560
9f2ebf
9f2ebf
Reviewed-by: Fabiano FidĂȘncio <fidencio@redhat.com>
9f2ebf
Tested-by: Scott Poore <spoore@redhat.com>
9f2ebf
(cherry picked from commit 177ab84f0e336b75289a3ac0b2df25bd5ab5198b)
9f2ebf
---
9f2ebf
 src/p11_child/p11_child_nss.c   |  18 +-----
9f2ebf
 src/responder/pam/pamsrv.h      |   6 ++
9f2ebf
 src/responder/pam/pamsrv_cmd.c  |  10 ++-
9f2ebf
 src/responder/pam/pamsrv_p11.c  | 135 +++++++++++++++++++++++++++++++++++++++-
9f2ebf
 src/tests/cmocka/test_pam_srv.c |   3 +
9f2ebf
 5 files changed, 152 insertions(+), 20 deletions(-)
9f2ebf
9f2ebf
diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
9f2ebf
index 5f289688e41f4ea610292b907036e05cf95eb29d..e59aba0d1561f58206252f7251ecd88315836b1b 100644
9f2ebf
--- a/src/p11_child/p11_child_nss.c
9f2ebf
+++ b/src/p11_child/p11_child_nss.c
9f2ebf
@@ -264,22 +264,6 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
9f2ebf
         }
9f2ebf
     }
9f2ebf
 
9f2ebf
-    rv = CERT_FilterCertListByUsage(cert_list, certUsageSSLClient, PR_FALSE);
9f2ebf
-    if (rv != SECSuccess) {
9f2ebf
-        DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d][%s].\n",
9f2ebf
-              PR_GetError(), PORT_ErrorToString(PR_GetError()));
9f2ebf
-        return EIO;
9f2ebf
-    }
9f2ebf
-
9f2ebf
-    rv = CERT_FilterCertListForUserCerts(cert_list);
9f2ebf
-    if (rv != SECSuccess) {
9f2ebf
-        DEBUG(SSSDBG_OP_FAILURE,
9f2ebf
-              "CERT_FilterCertListForUserCerts failed: [%d][%s].\n",
9f2ebf
-              PR_GetError(), PORT_ErrorToString(PR_GetError()));
9f2ebf
-        return EIO;
9f2ebf
-    }
9f2ebf
-
9f2ebf
-
9f2ebf
     handle = CERT_GetDefaultCertDB();
9f2ebf
     if (handle == NULL) {
9f2ebf
         DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d][%s].\n",
9f2ebf
@@ -344,7 +328,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
9f2ebf
         if (cert_verify_opts->do_verification) {
9f2ebf
             rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert,
9f2ebf
                                            PR_TRUE,
9f2ebf
-                                           certificateUsageSSLClient,
9f2ebf
+                                           certificateUsageCheckAllUsages,
9f2ebf
                                            NULL, NULL);
9f2ebf
             if (rv != SECSuccess) {
9f2ebf
                 DEBUG(SSSDBG_OP_FAILURE,
9f2ebf
diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
9f2ebf
index f15f7f19f1f38626288416c9f2038371c6f58b47..0bc229212844602ed461d1c7db48bf51ac2e2194 100644
9f2ebf
--- a/src/responder/pam/pamsrv.h
9f2ebf
+++ b/src/responder/pam/pamsrv.h
9f2ebf
@@ -27,6 +27,7 @@
9f2ebf
 #include "sbus/sssd_dbus.h"
9f2ebf
 #include "responder/common/responder.h"
9f2ebf
 #include "responder/common/cache_req/cache_req.h"
9f2ebf
+#include "lib/certmap/sss_certmap.h"
9f2ebf
 
9f2ebf
 struct pam_auth_req;
9f2ebf
 
9f2ebf
@@ -49,6 +50,7 @@ struct pam_ctx {
9f2ebf
     bool cert_auth;
9f2ebf
     int p11_child_debug_fd;
9f2ebf
     char *nss_db;
9f2ebf
+    struct sss_certmap_ctx *sss_certmap_ctx;
9f2ebf
 };
9f2ebf
 
9f2ebf
 struct pam_auth_dp_req {
9f2ebf
@@ -104,6 +106,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
9f2ebf
                                        const char *nss_db,
9f2ebf
                                        time_t timeout,
9f2ebf
                                        const char *verify_opts,
9f2ebf
+                                       struct sss_certmap_ctx *sss_certmap_ctx,
9f2ebf
                                        struct pam_data *pd);
9f2ebf
 errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
9f2ebf
                             struct cert_auth_info **cert_list);
9f2ebf
@@ -114,6 +117,9 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
9f2ebf
 
9f2ebf
 bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd);
9f2ebf
 
9f2ebf
+errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx,
9f2ebf
+                                struct certmap_info **certmap_list);
9f2ebf
+
9f2ebf
 errno_t
9f2ebf
 pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain,
9f2ebf
                                          const char *username,
9f2ebf
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
9f2ebf
index caf6c99489b8378d2e850473191223709920cd79..0e76c9e772f1775635677f35b870e9613b2faf64 100644
9f2ebf
--- a/src/responder/pam/pamsrv_cmd.c
9f2ebf
+++ b/src/responder/pam/pamsrv_cmd.c
9f2ebf
@@ -1336,7 +1336,8 @@ static errno_t check_cert(TALLOC_CTX *mctx,
9f2ebf
 
9f2ebf
     req = pam_check_cert_send(mctx, ev, pctx->p11_child_debug_fd,
9f2ebf
                               pctx->nss_db, p11_child_timeout,
9f2ebf
-                              cert_verification_opts, pd);
9f2ebf
+                              cert_verification_opts, pctx->sss_certmap_ctx,
9f2ebf
+                              pd);
9f2ebf
     if (req == NULL) {
9f2ebf
         DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
9f2ebf
         return ENOMEM;
9f2ebf
@@ -1749,6 +1750,13 @@ static void pam_forwarder_cb(struct tevent_req *req)
9f2ebf
         goto done;
9f2ebf
     }
9f2ebf
 
9f2ebf
+    ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains->certmaps);
9f2ebf
+    if (ret != EOK) {
9f2ebf
+        DEBUG(SSSDBG_OP_FAILURE,
9f2ebf
+              "p11_refresh_certmap_ctx failed, "
9f2ebf
+              "certificate matching might not work as expected");
9f2ebf
+    }
9f2ebf
+
9f2ebf
     pd = preq->pd;
9f2ebf
 
9f2ebf
     ret = pam_forwarder_parse_data(cctx, pd);
9f2ebf
diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
9f2ebf
index 5a3eeff0ec977829a9ad8c80b4fc6b2e06857097..ec52c5ae7163d41144fe082643a201b766a1e201 100644
9f2ebf
--- a/src/responder/pam/pamsrv_p11.c
9f2ebf
+++ b/src/responder/pam/pamsrv_p11.c
9f2ebf
@@ -36,6 +36,7 @@
9f2ebf
 
9f2ebf
 #define P11_CHILD_LOG_FILE "p11_child"
9f2ebf
 #define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child"
9f2ebf
+#define CERT_AUTH_DEFAULT_MATCHING_RULE "KRB5:<EKU>clientAuth"
9f2ebf
 
9f2ebf
 struct cert_auth_info {
9f2ebf
     char *cert;
9f2ebf
@@ -116,8 +117,110 @@ void sss_cai_check_users(struct cert_auth_info **list, size_t *_cert_count,
9f2ebf
     return;
9f2ebf
 }
9f2ebf
 
9f2ebf
+struct priv_sss_debug {
9f2ebf
+    int level;
9f2ebf
+};
9f2ebf
+
9f2ebf
+static void ext_debug(void *private, const char *file, long line,
9f2ebf
+                      const char *function, const char *format, ...)
9f2ebf
+{
9f2ebf
+    va_list ap;
9f2ebf
+    struct priv_sss_debug *data = private;
9f2ebf
+    int level = SSSDBG_OP_FAILURE;
9f2ebf
+
9f2ebf
+    if (data != NULL) {
9f2ebf
+        level = data->level;
9f2ebf
+    }
9f2ebf
+
9f2ebf
+    if (DEBUG_IS_SET(level)) {
9f2ebf
+        va_start(ap, format);
9f2ebf
+        sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
9f2ebf
+                      format, ap);
9f2ebf
+        va_end(ap);
9f2ebf
+    }
9f2ebf
+}
9f2ebf
+
9f2ebf
+errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx,
9f2ebf
+                                struct certmap_info **certmap_list)
9f2ebf
+{
9f2ebf
+    int ret;
9f2ebf
+    struct sss_certmap_ctx *sss_certmap_ctx = NULL;
9f2ebf
+    size_t c;
9f2ebf
+
9f2ebf
+    ret = sss_certmap_init(pctx, ext_debug, NULL, &sss_certmap_ctx);
9f2ebf
+    if (ret != EOK) {
9f2ebf
+        DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n");
9f2ebf
+        goto done;
9f2ebf
+    }
9f2ebf
+
9f2ebf
+    if (certmap_list == NULL || *certmap_list == NULL) {
9f2ebf
+        /* Try to add default matching rule */
9f2ebf
+        ret = sss_certmap_add_rule(sss_certmap_ctx, SSS_CERTMAP_MIN_PRIO,
9f2ebf
+                                   CERT_AUTH_DEFAULT_MATCHING_RULE, NULL, NULL);
9f2ebf
+        if (ret != 0) {
9f2ebf
+            DEBUG(SSSDBG_CRIT_FAILURE,
9f2ebf
+                  "Failed to add default matching rule.\n");
9f2ebf
+        }
9f2ebf
+
9f2ebf
+        goto done;
9f2ebf
+    }
9f2ebf
+
9f2ebf
+    for (c = 0; certmap_list[c] != NULL; c++) {
9f2ebf
+        DEBUG(SSSDBG_TRACE_ALL,
9f2ebf
+              "Trying to add rule [%s][%d][%s][%s].\n",
9f2ebf
+              certmap_list[c]->name, certmap_list[c]->priority,
9f2ebf
+              certmap_list[c]->match_rule, certmap_list[c]->map_rule);
9f2ebf
+
9f2ebf
+        ret = sss_certmap_add_rule(sss_certmap_ctx, certmap_list[c]->priority,
9f2ebf
+                                   certmap_list[c]->match_rule,
9f2ebf
+                                   certmap_list[c]->map_rule,
9f2ebf
+                                   certmap_list[c]->domains);
9f2ebf
+        if (ret != 0) {
9f2ebf
+            DEBUG(SSSDBG_CRIT_FAILURE,
9f2ebf
+                  "sss_certmap_add_rule failed for rule [%s] "
9f2ebf
+                  "with error [%d][%s], skipping. "
9f2ebf
+                  "Please check for typos and if rule syntax is supported.\n",
9f2ebf
+                  certmap_list[c]->name, ret, sss_strerror(ret));
9f2ebf
+            continue;
9f2ebf
+        }
9f2ebf
+    }
9f2ebf
+
9f2ebf
+    ret = EOK;
9f2ebf
+
9f2ebf
+done:
9f2ebf
+    if (ret == EOK) {
9f2ebf
+        sss_certmap_free_ctx(pctx->sss_certmap_ctx);
9f2ebf
+        pctx->sss_certmap_ctx = sss_certmap_ctx;
9f2ebf
+    } else {
9f2ebf
+        sss_certmap_free_ctx(sss_certmap_ctx);
9f2ebf
+    }
9f2ebf
+
9f2ebf
+    return ret;
9f2ebf
+}
9f2ebf
+
9f2ebf
 errno_t p11_child_init(struct pam_ctx *pctx)
9f2ebf
 {
9f2ebf
+    int ret;
9f2ebf
+    struct certmap_info **certmaps;
9f2ebf
+    bool user_name_hint;
9f2ebf
+    struct sss_domain_info *dom = pctx->rctx->domains;
9f2ebf
+
9f2ebf
+    ret = sysdb_get_certmap(dom, dom->sysdb, &certmaps, &user_name_hint);
9f2ebf
+    if (ret != EOK) {
9f2ebf
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_certmap failed.\n");
9f2ebf
+        return ret;
9f2ebf
+    }
9f2ebf
+
9f2ebf
+    dom->user_name_hint = user_name_hint;
9f2ebf
+    talloc_free(dom->certmaps);
9f2ebf
+    dom->certmaps = certmaps;
9f2ebf
+
9f2ebf
+    ret = p11_refresh_certmap_ctx(pctx, dom->certmaps);
9f2ebf
+    if (ret != EOK) {
9f2ebf
+        DEBUG(SSSDBG_OP_FAILURE, "p11_refresh_certmap_ctx failed.\n");
9f2ebf
+        return ret;
9f2ebf
+    }
9f2ebf
+
9f2ebf
     return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd);
9f2ebf
 }
9f2ebf
 
9f2ebf
@@ -214,6 +317,7 @@ static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx,
9f2ebf
 
9f2ebf
 static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
9f2ebf
                                         ssize_t buf_len,
9f2ebf
+                                        struct sss_certmap_ctx *sss_certmap_ctx,
9f2ebf
                                         struct cert_auth_info **_cert_list)
9f2ebf
 {
9f2ebf
     int ret;
9f2ebf
@@ -222,6 +326,8 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
9f2ebf
     uint8_t *pn;
9f2ebf
     struct cert_auth_info *cert_list = NULL;
9f2ebf
     struct cert_auth_info *cert_auth_info;
9f2ebf
+    unsigned char *der = NULL;
9f2ebf
+    size_t der_size;
9f2ebf
 
9f2ebf
     if (buf_len < 0) {
9f2ebf
         DEBUG(SSSDBG_CRIT_FAILURE,
9f2ebf
@@ -347,7 +453,22 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
9f2ebf
         }
9f2ebf
         DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert_auth_info->cert);
9f2ebf
 
9f2ebf
-        DLIST_ADD(cert_list, cert_auth_info);
9f2ebf
+        der = sss_base64_decode(tmp_ctx, cert_auth_info->cert, &der_size);
9f2ebf
+        if (der == NULL) {
9f2ebf
+            DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
9f2ebf
+            ret = EIO;
9f2ebf
+            goto done;
9f2ebf
+        }
9f2ebf
+
9f2ebf
+        ret = sss_certmap_match_cert(sss_certmap_ctx, der, der_size);
9f2ebf
+        if (ret == 0) {
9f2ebf
+            DLIST_ADD(cert_list, cert_auth_info);
9f2ebf
+        } else {
9f2ebf
+            DEBUG(SSSDBG_TRACE_LIBS,
9f2ebf
+                  "Cert [%s] does not match matching rules and is ignored.\n",
9f2ebf
+                  cert_auth_info->cert);
9f2ebf
+            talloc_free(cert_auth_info);
9f2ebf
+        }
9f2ebf
 
9f2ebf
         p = ++pn;
9f2ebf
     } while ((pn - buf) < buf_len);
9f2ebf
@@ -373,6 +494,7 @@ struct pam_check_cert_state {
9f2ebf
     struct sss_child_ctx_old *child_ctx;
9f2ebf
     struct tevent_timer *timeout_handler;
9f2ebf
     struct tevent_context *ev;
9f2ebf
+    struct sss_certmap_ctx *sss_certmap_ctx;
9f2ebf
 
9f2ebf
     struct child_io_fds *io;
9f2ebf
 
9f2ebf
@@ -391,6 +513,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
9f2ebf
                                        const char *nss_db,
9f2ebf
                                        time_t timeout,
9f2ebf
                                        const char *verify_opts,
9f2ebf
+                                       struct sss_certmap_ctx *sss_certmap_ctx,
9f2ebf
                                        struct pam_data *pd)
9f2ebf
 {
9f2ebf
     errno_t ret;
9f2ebf
@@ -420,6 +543,12 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
9f2ebf
         goto done;
9f2ebf
     }
9f2ebf
 
9f2ebf
+    if (sss_certmap_ctx == NULL) {
9f2ebf
+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing certificate matching context.\n");
9f2ebf
+        ret = EINVAL;
9f2ebf
+        goto done;
9f2ebf
+    }
9f2ebf
+
9f2ebf
     /* extra_args are added in revers order */
9f2ebf
     arg_c = 0;
9f2ebf
     extra_args[arg_c++] = nss_db;
9f2ebf
@@ -476,6 +605,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
9f2ebf
     }
9f2ebf
 
9f2ebf
     state->ev = ev;
9f2ebf
+    state->sss_certmap_ctx = sss_certmap_ctx;
9f2ebf
     state->child_status = EFAULT;
9f2ebf
     state->io = talloc(state, struct child_io_fds);
9f2ebf
     if (state->io == NULL) {
9f2ebf
@@ -639,7 +769,8 @@ static void p11_child_done(struct tevent_req *subreq)
9f2ebf
 
9f2ebf
     PIPE_FD_CLOSE(state->io->read_from_child_fd);
9f2ebf
 
9f2ebf
-    ret = parse_p11_child_response(state, buf, buf_len, &state->cert_list);
9f2ebf
+    ret = parse_p11_child_response(state, buf, buf_len, state->sss_certmap_ctx,
9f2ebf
+                                   &state->cert_list);
9f2ebf
     if (ret != EOK) {
9f2ebf
         DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_response failed.\n");
9f2ebf
         tevent_req_error(req, ret);
9f2ebf
diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
9f2ebf
index b6845320ca41d6933280aa2836a3d984dacfcc5e..bccf9972dacbb414076904a783772198620fd73c 100644
9f2ebf
--- a/src/tests/cmocka/test_pam_srv.c
9f2ebf
+++ b/src/tests/cmocka/test_pam_srv.c
9f2ebf
@@ -287,6 +287,9 @@ struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx)
9f2ebf
         return NULL;
9f2ebf
     }
9f2ebf
 
9f2ebf
+    ret = p11_refresh_certmap_ctx(pctx, NULL);
9f2ebf
+    assert_int_equal(ret, 0);
9f2ebf
+
9f2ebf
     return pctx;
9f2ebf
 }
9f2ebf
 
9f2ebf
-- 
9f2ebf
2.13.6
9f2ebf