74fd62
From e13d8a12513bfba1531cc867fbf687ff8673241f Mon Sep 17 00:00:00 2001
74fd62
From: Alexey Tikhonov <atikhono@redhat.com>
74fd62
Date: Thu, 10 Dec 2020 19:45:08 +0100
74fd62
Subject: [PATCH] Squashed commit of the following:
74fd62
MIME-Version: 1.0
74fd62
Content-Type: text/plain; charset=UTF-8
74fd62
Content-Transfer-Encoding: 8bit
74fd62
74fd62
commit 6b3b4b0bf945814e8886b900dcda18de25f38bb4
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Thu Dec 12 13:10:16 2019 +0100
74fd62
74fd62
    certmap: mention special regex characters in man page
74fd62
74fd62
    Since some of the matching rules use regular expressions some characters
74fd62
    must be escaped so that they can be used a ordinary characters in the
74fd62
    rules.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/4127
74fd62
74fd62
    Reviewed-by: Michal Židek <mzidek@redhat.com>
74fd62
    (cherry picked from commit 21cb9fb28db1f2eb4ee770eb029bfe20233e4392)
74fd62
74fd62
commit 451410e72514bd68e4b56b1a42c97ade6783e74b
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Tue Nov 27 16:42:38 2018 +0100
74fd62
74fd62
    test: add certificate without KU to certmap tests
74fd62
74fd62
    Make sure there is a test for a certificate without key-usage (KU)
74fd62
74fd62
    Related to https://bugzilla.redhat.com/show_bug.cgi?id=1660899
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit e1734ba828470d00370c44c95da56822fdcc104d)
74fd62
74fd62
commit e7966dfa40b9a7fcde79a07f146ae5283a7bc8e5
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Mon Nov 26 12:03:13 2018 +0100
74fd62
74fd62
    certmap: allow missing KU in OpenSSL version
74fd62
74fd62
    Make sure a missing key-usage (KU) is not treated as an error and is
74fd62
    handled equally in the NSS and OpenSSL implementation
74fd62
74fd62
    Related to https://bugzilla.redhat.com/show_bug.cgi?id=1660899
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit aef8e49b7ee2e7743d6981070d61bc89b7c8fcfb)
74fd62
74fd62
commit 6e9e6673916b61197df8a809f56c73d8bdbb868c
74fd62
Author: Alexey Tikhonov <atikhono@redhat.com>
74fd62
Date:   Mon Jan 7 17:04:34 2019 +0100
74fd62
74fd62
    CONFIG: validator rules & test
74fd62
74fd62
    Add support of 'certmap' config section to validator rules
74fd62
74fd62
    Resolves:
74fd62
    https://pagure.io/SSSD/sssd/issue/3845
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit 8e9e8011ce17860bec67a572e4c11a9178c03b8e)
74fd62
74fd62
commit eec9d72a242b2b05369f0eb89c4ebcda26d59802
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Fri Sep 7 22:26:21 2018 +0200
74fd62
74fd62
    intg: add Smartcard authentication tests
74fd62
74fd62
    Two test for Smartcard authentication of a local user, i.e. a user
74fd62
    managed by the files provider, are added. One for a successful
74fd62
    authentication, the other for a failed authentication with a wrong PIN.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked with fixes from commit 657f3b89bca9adfb13f0867c91f1d76845d2d6dd)
74fd62
74fd62
commit cc2840fbb494ac686e9a3ae0016827a44d14769f
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Fri Sep 7 22:17:47 2018 +0200
74fd62
74fd62
    test_ca: set a password/PIN to nss databases
74fd62
74fd62
    To make sure the PIN is properly checked during tests the NSS databases
74fd62
    need a password.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit a45a410dc7fa7cf84bcac541e693ee8781e25431)
74fd62
74fd62
commit 0a989c62b4a3b73f23d9b6956ac81afaed9901f7
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Mon Sep 10 22:03:55 2018 +0200
74fd62
74fd62
    test_ca: test library only for readable
74fd62
74fd62
    On Debian libraries typically do not have the execute-bit set so it is
74fd62
    better to only check for readability.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit 91aea762d02731193eb66a00b930ff1fe8bc5ab8)
74fd62
74fd62
commit 5a47b213b11cbf74dad47594d1826985f6b68f22
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Fri Sep 7 22:16:50 2018 +0200
74fd62
74fd62
    PAM: use better PAM error code for failed Smartcard authentication
74fd62
74fd62
    If the user enters a wrong PIN the PAM responder currently returns
74fd62
    PAM_USER_UNKNOWN better is PAM_AUTH_ERR.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit 442ae7b1d0704cdd667d4f1ba4c165ce3f3ffed4)
74fd62
74fd62
commit b6907d7cd5ab7568971ddb48f3932f106e86fe06
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Mon Sep 3 18:38:42 2018 +0200
74fd62
74fd62
    doc: add certificate mapping section to man page
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked with fixes from commit 0c739e969a617bdb4c06cdfd63772bf6d283c518)
74fd62
74fd62
commit d75b196312c4cec767c196c663ff969b6aebcd6b
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Mon Jul 9 18:56:26 2018 +0200
74fd62
74fd62
    PAM: add certificate matching rules from all domains
74fd62
74fd62
    Currently the PAM responder only reads the certificate mapping and
74fd62
    matching rules from the first domain. To support Smartcard
74fd62
    authentication for local and remote users all configured domains must be
74fd62
    taken into account.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit d42f44d54453d3ddb54875374c1b61dc1e7cd821)
74fd62
74fd62
commit 167ab7206913c17617a8e5ada7567d91f8ed6e11
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Mon Jul 9 18:45:21 2018 +0200
74fd62
74fd62
    responder: make sure SSS_DP_CERT is passed to files provider
74fd62
74fd62
    Currently the files provider is only contacted once in a while to update
74fd62
    the full cache with fresh data from the passwd file. To allow rule based
74fd62
    certificate mapping the lookup by certificate request must be always
74fd62
    send to the file provider so that it can evaluate the rules and add the
74fd62
    certificate to cached entry of the matching user.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit 9fdc5f1d87a133885e6a22810a7eb980c60dcb55)
74fd62
74fd62
commit 69def7a3e81313a30ceae937f9cde5d62e999c3d
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Mon Jul 9 18:37:46 2018 +0200
74fd62
74fd62
    files: add support for Smartcard authentication
74fd62
74fd62
    To support certificate based authentication the files provider must be
74fd62
    able to map a certificate to a user during a BE_REQ_BY_CERT request.
74fd62
74fd62
    Additionally the authentication request should be handled by the PAM
74fd62
    responder code which is responsible for the local Smartcard
74fd62
    authentication. To be consistent with the other backend an authentication
74fd62
    handler is added to the files provider which unconditionally returns the
74fd62
    offline error code telling the PAM responder to handle the
74fd62
    authentication if it has access to the needed credentials.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit 275eeed24adc31f3df51cf278f509a4be76a3a3c)
74fd62
74fd62
commit e96ba56ea8037d58e1335f7dacd3b19919bc4135
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Fri Jul 6 15:17:10 2018 +0200
74fd62
74fd62
    confdb: add special handling for rules for the files provider
74fd62
74fd62
    To make the configuration more simple there are some special assumption
74fd62
    for local users, i.e. user managed by the files provider.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit 9386ef605ffbc03abe2bc273efddbc099441fe3b)
74fd62
74fd62
commit d304f5a9e60f7f6eb915a10067ee2e5e5f14c369
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Tue Jul 3 11:31:12 2018 +0200
74fd62
74fd62
    sysdb: sysdb_certmap_add() handle domains more flexible
74fd62
74fd62
    sysdb_ldb_msg_attr_to_certmap_info() creates an empty list if there are
74fd62
    no domains defined, sysdb_certmap_add() should be able to handle both a
74fd62
    missing or an empty domains list.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit 06f7005d38d164879b727708feff80004b422f91)
74fd62
74fd62
commit 53befb320c2b60a420a2588425fd5004ceec791a
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Mon Jul 2 12:20:53 2018 +0200
74fd62
74fd62
    AD/LDAP: read certificate mapping rules from config file
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit 15301db1dc1e5e2aafc1805a30e3b28756218c9b)
74fd62
74fd62
commit 670a1ca6b7b22bb3a1079111528ee7e4aafd97e5
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Mon Jul 2 10:38:54 2018 +0200
74fd62
74fd62
    confdb: add confdb_certmap_to_sysdb()
74fd62
74fd62
    Add a function to write certificate mapping and matching rules from the
74fd62
    config database to the cache of a domain.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked with fixes from commit d9cc38008a51a8a5189904f175e4d10cbde4a974)
74fd62
74fd62
commit 14c15cc6db16726419fbf6df76b5c83aec49192a
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Fri Jun 29 18:13:59 2018 +0200
74fd62
74fd62
    sysdb: add attr_map attribute to sysdb_ldb_msg_attr_to_certmap_info()
74fd62
74fd62
    Allow more flexible attribute mapping in
74fd62
    sysdb_ldb_msg_attr_to_certmap_info()
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit 0bf709ad348ca115443bd21e4e369abd5d7698c4)
74fd62
74fd62
commit f867c2a293651043072afe1dd7a8a78a05e5fe4d
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Tue Jul 3 11:30:07 2018 +0200
74fd62
74fd62
    sysdb_ldb_msg_attr_to_certmap_info: set SSS_CERTMAP_MIN_PRIO
74fd62
74fd62
    Make sure that priority is always set.
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit d1dd7f7703b4f40d2fbb830e28969b31b8a1673e)
74fd62
74fd62
commit 8ef2cc11008ef86f4dfcbc267c797bf8ee265455
74fd62
Author: Sumit Bose <sbose@redhat.com>
74fd62
Date:   Fri Jun 29 17:49:50 2018 +0200
74fd62
74fd62
    sysdb: extract sysdb_ldb_msg_attr_to_certmap_info() call
74fd62
74fd62
    Related to https://pagure.io/SSSD/sssd/issue/3500
74fd62
74fd62
    Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
74fd62
    (cherry picked from commit 7c619ae08f05a7595d15cf11b64461a7d19cfaa7)
74fd62
---
74fd62
 Makefile.am                                   |   2 +
74fd62
 configure.ac                                  |   1 +
74fd62
 contrib/sssd.spec.in                          |   1 +
74fd62
 src/confdb/confdb.c                           | 158 +++++++++++++
74fd62
 src/confdb/confdb.h                           |  23 ++
74fd62
 src/config/cfg_rules.ini                      |  10 +
74fd62
 src/db/sysdb.h                                |   5 +
74fd62
 src/db/sysdb_certmap.c                        | 223 +++++++++++-------
74fd62
 src/external/cwrap.m4                         |   5 +
74fd62
 src/external/intgcheck.m4                     |   1 +
74fd62
 src/external/test_ca.m4                       |   2 +-
74fd62
 src/lib/certmap/sss_cert_content_crypto.c     |  22 +-
74fd62
 src/lib/certmap/sss_cert_content_nss.c        |  21 +-
74fd62
 src/man/sss-certmap.5.xml                     |   9 +
74fd62
 src/man/sssd.conf.5.xml                       | 149 ++++++++++++
74fd62
 src/providers/ad/ad_init.c                    |  16 ++
74fd62
 src/providers/files/files_auth.c              |  69 ++++++
74fd62
 src/providers/files/files_certmap.c           | 186 +++++++++++++++
74fd62
 src/providers/files/files_id.c                |  20 ++
74fd62
 src/providers/files/files_init.c              |  29 +++
74fd62
 src/providers/files/files_private.h           |  17 ++
74fd62
 src/providers/ldap/ldap_init.c                |  16 ++
74fd62
 src/responder/common/responder_dp.c           |  20 +-
74fd62
 src/responder/pam/pamsrv.h                    |   2 +-
74fd62
 src/responder/pam/pamsrv_cmd.c                |   6 +-
74fd62
 src/responder/pam/pamsrv_p11.c                |  77 +++---
74fd62
 src/tests/cmocka/test_certmap.c               |  45 ++++
74fd62
 src/tests/cmocka/test_config_check.c          |  16 +-
74fd62
 src/tests/intg/test_pam_responder.py          | 109 ++++++++-
74fd62
 src/tests/test_CA/Makefile.am                 |  24 +-
74fd62
 src/tests/test_CA/SSSD_test_cert_0004.config  |  11 +
74fd62
 src/tests/test_CA/SSSD_test_cert_key_0004.pem |  28 +++
74fd62
 32 files changed, 1170 insertions(+), 153 deletions(-)
74fd62
 create mode 100644 src/providers/files/files_auth.c
74fd62
 create mode 100644 src/providers/files/files_certmap.c
74fd62
 create mode 100644 src/tests/test_CA/SSSD_test_cert_0004.config
74fd62
 create mode 100644 src/tests/test_CA/SSSD_test_cert_key_0004.pem
74fd62
74fd62
diff --git a/Makefile.am b/Makefile.am
74fd62
index 718041634..77f5faf6b 100644
74fd62
--- a/Makefile.am
74fd62
+++ b/Makefile.am
74fd62
@@ -4094,6 +4094,8 @@ libsss_proxy_la_LDFLAGS = \
74fd62
 libsss_files_la_SOURCES = \
74fd62
     src/providers/files/files_init.c \
74fd62
     src/providers/files/files_id.c \
74fd62
+    src/providers/files/files_auth.c \
74fd62
+    src/providers/files/files_certmap.c \
74fd62
     src/providers/files/files_ops.c \
74fd62
     src/util/inotify.c \
74fd62
     $(NULL)
74fd62
diff --git a/configure.ac b/configure.ac
74fd62
index 5154918b1..89abddef4 100644
74fd62
--- a/configure.ac
74fd62
+++ b/configure.ac
74fd62
@@ -488,6 +488,7 @@ AM_CONDITIONAL([HAVE_CHECK], [test x$have_check != x])
74fd62
 AM_CHECK_CMOCKA
74fd62
 AM_CHECK_UID_WRAPPER
74fd62
 AM_CHECK_NSS_WRAPPER
74fd62
+AM_CHECK_PAM_WRAPPER
74fd62
 AM_CHECK_TEST_CA
74fd62
 
74fd62
 # Check if the user wants SSSD to be compiled with systemtap probes
74fd62
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
74fd62
index 10b5bd56c..52a77ae7a 100644
74fd62
--- a/contrib/sssd.spec.in
74fd62
+++ b/contrib/sssd.spec.in
74fd62
@@ -236,6 +236,7 @@ BuildRequires: selinux-policy-targeted
74fd62
 BuildRequires: libcmocka-devel >= 1.0.0
74fd62
 BuildRequires: uid_wrapper
74fd62
 BuildRequires: nss_wrapper
74fd62
+BuildRequires: pam_wrapper
74fd62
 
74fd62
 # Test CA requires openssl independent if SSSD is build with NSS or openssl,
74fd62
 # openssh is needed for ssh-keygen and NSS builds need nss-tools for certutil.
74fd62
diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
74fd62
index e55f88e4e..97de6d3b1 100644
74fd62
--- a/src/confdb/confdb.c
74fd62
+++ b/src/confdb/confdb.c
74fd62
@@ -2209,3 +2209,161 @@ done:
74fd62
     talloc_free(tmp_ctx);
74fd62
     return ret;
74fd62
 }
74fd62
+
74fd62
+static errno_t certmap_local_check(struct ldb_message *msg)
74fd62
+{
74fd62
+    const char *rule_name;
74fd62
+    const char *tmp_str;
74fd62
+    int ret;
74fd62
+
74fd62
+    rule_name = ldb_msg_find_attr_as_string(msg, CONFDB_CERTMAP_NAME, NULL);
74fd62
+    if (rule_name == NULL) {
74fd62
+        DEBUG(SSSDBG_CRIT_FAILURE, "Certficate mapping rule [%s] has no name.",
74fd62
+                                   ldb_dn_get_linearized(msg->dn));
74fd62
+        return EINVAL;
74fd62
+    }
74fd62
+
74fd62
+    tmp_str = ldb_msg_find_attr_as_string(msg, CONFDB_CERTMAP_DOMAINS, NULL);
74fd62
+    if (tmp_str != NULL) {
74fd62
+        DEBUG(SSSDBG_CONF_SETTINGS,
74fd62
+              "Option [%s] is ignored for local certmap rules.\n",
74fd62
+              CONFDB_CERTMAP_DOMAINS);
74fd62
+    }
74fd62
+
74fd62
+    tmp_str = ldb_msg_find_attr_as_string(msg, CONFDB_CERTMAP_MAPRULE, NULL);
74fd62
+    if (tmp_str != NULL) {
74fd62
+        if (tmp_str[0] != '(' || tmp_str[strlen(tmp_str) - 1] != ')') {
74fd62
+            DEBUG(SSSDBG_CONF_SETTINGS,
74fd62
+                  "Mapping rule must be in braces (...).\n");
74fd62
+            return EINVAL;
74fd62
+        }
74fd62
+        DEBUG(SSSDBG_TRACE_ALL, "Using [%s] mapping rule of [%s].\n",
74fd62
+                                tmp_str, ldb_dn_get_linearized(msg->dn));
74fd62
+        return EOK;
74fd62
+    }
74fd62
+
74fd62
+    tmp_str = talloc_asprintf(msg, "(%s)", rule_name);
74fd62
+    if (tmp_str == NULL) {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
74fd62
+        return ENOMEM;
74fd62
+    }
74fd62
+    ret = ldb_msg_add_string(msg, CONFDB_CERTMAP_MAPRULE, tmp_str);
74fd62
+    if (ret != LDB_SUCCESS) {
74fd62
+        talloc_free(discard_const(tmp_str));
74fd62
+        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
74fd62
+        return EIO;
74fd62
+    }
74fd62
+
74fd62
+    DEBUG(SSSDBG_TRACE_ALL, "Using [%s] as mapping rule for [%s].\n",
74fd62
+                            tmp_str, ldb_dn_get_linearized(msg->dn));
74fd62
+
74fd62
+    return EOK;
74fd62
+}
74fd62
+
74fd62
+static errno_t confdb_get_all_certmaps(TALLOC_CTX *mem_ctx,
74fd62
+                                       struct confdb_ctx *cdb,
74fd62
+                                       struct sss_domain_info *dom,
74fd62
+                                       struct certmap_info ***_certmap_list)
74fd62
+{
74fd62
+    TALLOC_CTX *tmp_ctx = NULL;
74fd62
+    struct ldb_dn *dn = NULL;
74fd62
+    struct ldb_result *res = NULL;
74fd62
+    /* The attributte order is important, because it is used in
74fd62
+     * sysdb_ldb_msg_attr_to_certmap_info and must match
74fd62
+     * enum certmap_info_member. */
74fd62
+    static const char *attrs[] = { CONFDB_CERTMAP_NAME,
74fd62
+                                   CONFDB_CERTMAP_MAPRULE,
74fd62
+                                   CONFDB_CERTMAP_MATCHRULE,
74fd62
+                                   CONFDB_CERTMAP_PRIORITY,
74fd62
+                                   CONFDB_CERTMAP_DOMAINS,
74fd62
+                                   NULL};
74fd62
+    struct certmap_info **certmap_list = NULL;
74fd62
+    size_t c;
74fd62
+    int ret;
74fd62
+
74fd62
+    tmp_ctx = talloc_new(NULL);
74fd62
+    if (tmp_ctx == NULL) {
74fd62
+        return ENOMEM;
74fd62
+    }
74fd62
+
74fd62
+    dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb, "cn=%s,%s", dom->name,
74fd62
+                                                       CONFDB_CERTMAP_BASEDN);
74fd62
+    if (dn == NULL) {
74fd62
+        ret = ENOMEM;
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_ONELEVEL,
74fd62
+                     attrs, NULL);
74fd62
+    if (ret != LDB_SUCCESS) {
74fd62
+        ret = EIO;
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    certmap_list = talloc_zero_array(tmp_ctx, struct certmap_info *,
74fd62
+                                     res->count + 1);
74fd62
+    if (certmap_list == NULL) {
74fd62
+        ret = ENOMEM;
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    for (c = 0; c < res->count; c++) {
74fd62
+        if (is_files_provider(dom)) {
74fd62
+            ret = certmap_local_check(res->msgs[c]);
74fd62
+            if (ret != EOK) {
74fd62
+                DEBUG(SSSDBG_CONF_SETTINGS,
74fd62
+                      "Invalid certificate mapping [%s] for local user, "
74fd62
+                      "ignored.\n", ldb_dn_get_linearized(res->msgs[c]->dn));
74fd62
+                continue;
74fd62
+            }
74fd62
+        }
74fd62
+        ret = sysdb_ldb_msg_attr_to_certmap_info(certmap_list, res->msgs[c],
74fd62
+                                                 attrs, &certmap_list[c]);
74fd62
+        if (ret != EOK) {
74fd62
+            DEBUG(SSSDBG_OP_FAILURE,
74fd62
+                  "sysdb_ldb_msg_attr_to_certmap_info failed.\n");
74fd62
+            goto done;
74fd62
+        }
74fd62
+    }
74fd62
+
74fd62
+    *_certmap_list = talloc_steal(mem_ctx, certmap_list);
74fd62
+
74fd62
+    ret = EOK;
74fd62
+
74fd62
+done:
74fd62
+    talloc_free(tmp_ctx);
74fd62
+    return ret;
74fd62
+}
74fd62
+
74fd62
+int confdb_certmap_to_sysdb(struct confdb_ctx *cdb,
74fd62
+                            struct sss_domain_info *dom)
74fd62
+{
74fd62
+    int ret;
74fd62
+    TALLOC_CTX *tmp_ctx;
74fd62
+    struct certmap_info **certmap_list;
74fd62
+
74fd62
+    tmp_ctx = talloc_new(NULL);
74fd62
+    if (tmp_ctx == NULL) {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
74fd62
+        return ENOMEM;
74fd62
+    }
74fd62
+
74fd62
+    ret = confdb_get_all_certmaps(tmp_ctx, cdb, dom, &certmap_list);
74fd62
+    if (ret != EOK) {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE, "confdb_get_all_certmaps failed.\n");
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    ret = sysdb_update_certmap(dom->sysdb, certmap_list, false /* TODO */);
74fd62
+    if (ret != EOK) {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_certmap failed.\n");
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    ret = EOK;
74fd62
+
74fd62
+done:
74fd62
+    talloc_free(tmp_ctx);
74fd62
+
74fd62
+    return ret;
74fd62
+}
74fd62
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
74fd62
index d3e71be86..b0d52ba49 100644
74fd62
--- a/src/confdb/confdb.h
74fd62
+++ b/src/confdb/confdb.h
74fd62
@@ -267,6 +267,14 @@
74fd62
 #define CONFDB_KCM_SOCKET "socket_path"
74fd62
 #define CONFDB_KCM_DB "ccache_storage" /* Undocumented on purpose */
74fd62
 
74fd62
+/* Certificate mapping rules */
74fd62
+#define CONFDB_CERTMAP_BASEDN "cn=certmap,cn=config"
74fd62
+#define CONFDB_CERTMAP_NAME "cn"
74fd62
+#define CONFDB_CERTMAP_MAPRULE "maprule"
74fd62
+#define CONFDB_CERTMAP_MATCHRULE "matchrule"
74fd62
+#define CONFDB_CERTMAP_DOMAINS "domains"
74fd62
+#define CONFDB_CERTMAP_PRIORITY "priority"
74fd62
+
74fd62
 /* Prompting */
74fd62
 #define CONFDB_PC_CONF_ENTRY "config/prompting"
74fd62
 #define CONFDB_PC_TYPE_PASSWORD "password"
74fd62
@@ -681,6 +689,21 @@ int confdb_get_sub_sections(TALLOC_CTX *mem_ctx,
74fd62
                             const char *section,
74fd62
                             char ***sections,
74fd62
                             int *num_sections);
74fd62
+
74fd62
+/**
74fd62
+ * @brief Convenience function to write the certificate mapping and matching
74fd62
+ * rules from the configuration database to the cache of a domain
74fd62
+ *
74fd62
+ * @param[in] cdb The connection object to the confdb
74fd62
+ * @param[in] dom Target domain where to rules should be written to
74fd62
+ *
74fd62
+ * @return 0 - Successfully retrieved the entry (or used the default)
74fd62
+ * @return ENOMEM - There was insufficient memory to complete the operation
74fd62
+ * @return EINVAL - Typically internal processing error
74fd62
+ */
74fd62
+int confdb_certmap_to_sysdb(struct confdb_ctx *cdb,
74fd62
+                            struct sss_domain_info *dom);
74fd62
+
74fd62
 /**
74fd62
  * @}
74fd62
  */
74fd62
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
74fd62
index 997ba5aec..79e366875 100644
74fd62
--- a/src/config/cfg_rules.ini
74fd62
+++ b/src/config/cfg_rules.ini
74fd62
@@ -17,6 +17,7 @@ section_re = ^secrets/kcm$
74fd62
 section_re = ^domain/[^/\@]\+$
74fd62
 section_re = ^domain/[^/\@]\+/[^/\@]\+$
74fd62
 section_re = ^application/[^/\@]\+$
74fd62
+section_re = ^certmap/[^/\@]\+/[^/\@]\+$
74fd62
 
74fd62
 
74fd62
 [rule/allowed_sssd_options]
74fd62
@@ -765,3 +766,12 @@ option = use_fully_qualified_names
74fd62
 
74fd62
 [rule/sssd_checks]
74fd62
 validator = sssd_checks
74fd62
+
74fd62
+[rule/allowed_certmap_options]
74fd62
+validator = ini_allowed_options
74fd62
+section_re = ^certmap/[^/\@]\+/[^/\@]\+$
74fd62
+
74fd62
+option = matchrule
74fd62
+option = maprule
74fd62
+option = priority
74fd62
+option = domains
74fd62
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
74fd62
index 018ec22ab..a2bc8ed3b 100644
74fd62
--- a/src/db/sysdb.h
74fd62
+++ b/src/db/sysdb.h
74fd62
@@ -737,6 +737,11 @@ errno_t sysdb_update_certmap(struct sysdb_ctx *sysdb,
74fd62
                              struct certmap_info **certmaps,
74fd62
                              bool user_name_hint);
74fd62
 
74fd62
+errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
74fd62
+                                           struct ldb_message *msg,
74fd62
+                                           const char **attr_map,
74fd62
+                                           struct certmap_info **certmap);
74fd62
+
74fd62
 errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
74fd62
                           struct certmap_info ***certmaps,
74fd62
                           bool *user_name_hint);
74fd62
diff --git a/src/db/sysdb_certmap.c b/src/db/sysdb_certmap.c
74fd62
index eda20f5a7..4cc5b5b41 100644
74fd62
--- a/src/db/sysdb_certmap.c
74fd62
+++ b/src/db/sysdb_certmap.c
74fd62
@@ -22,6 +22,7 @@
74fd62
 
74fd62
 #include "util/util.h"
74fd62
 #include "db/sysdb_private.h"
74fd62
+#include "lib/certmap/sss_certmap.h"
74fd62
 
74fd62
 static errno_t sysdb_create_certmap_container(struct sysdb_ctx *sysdb,
74fd62
                                               bool user_name_hint)
74fd62
@@ -153,7 +154,7 @@ static errno_t sysdb_certmap_add(struct sysdb_ctx *sysdb,
74fd62
         }
74fd62
     }
74fd62
 
74fd62
-    if (certmap->domains != NULL) {
74fd62
+    if (certmap->domains != NULL && certmap->domains[0] != NULL) {
74fd62
         for (c = 0; certmap->domains[c] != NULL; c++);
74fd62
         el = talloc_zero(tmp_ctx, struct ldb_message_element);
74fd62
         if (el == NULL) {
74fd62
@@ -285,28 +286,151 @@ done:
74fd62
     return ret;
74fd62
 }
74fd62
 
74fd62
+enum certmap_info_member {
74fd62
+    SSS_CMIM_NAME = 0,
74fd62
+    SSS_CMIM_MAPPING_RULE,
74fd62
+    SSS_CMIM_MATCHING_RULE,
74fd62
+    SSS_CMIM_PRIORITY,
74fd62
+    SSS_CMIM_DOMAINS,
74fd62
+
74fd62
+    SSS_CMIM_SENTINEL
74fd62
+};
74fd62
+
74fd62
+errno_t sysdb_ldb_msg_attr_to_certmap_info(TALLOC_CTX *mem_ctx,
74fd62
+                                           struct ldb_message *msg,
74fd62
+                                           const char **attr_map,
74fd62
+                                           struct certmap_info **certmap)
74fd62
+{
74fd62
+    int ret;
74fd62
+    size_t d;
74fd62
+    size_t num_values;
74fd62
+    struct certmap_info *map = NULL;
74fd62
+    const char *tmp_str;
74fd62
+    uint64_t tmp_uint;
74fd62
+    struct ldb_message_element *tmp_el;
74fd62
+
74fd62
+    if (msg == NULL || attr_map == NULL || certmap == NULL) {
74fd62
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid input.\n");
74fd62
+        return EINVAL;
74fd62
+    }
74fd62
+
74fd62
+    for (d = 0; d < SSS_CMIM_SENTINEL; d++) {
74fd62
+        if (attr_map[d] == NULL) {
74fd62
+            DEBUG(SSSDBG_CRIT_FAILURE, "Invalid attribute map");
74fd62
+            return EINVAL;
74fd62
+        }
74fd62
+    }
74fd62
+
74fd62
+    map = talloc_zero(mem_ctx, struct certmap_info);
74fd62
+    if (map == NULL) {
74fd62
+        return ENOMEM;
74fd62
+    }
74fd62
+
74fd62
+    tmp_str = ldb_msg_find_attr_as_string(msg, attr_map[SSS_CMIM_NAME], NULL);
74fd62
+    if (tmp_str == NULL) {
74fd62
+        DEBUG(SSSDBG_MINOR_FAILURE, "The object [%s] doesn't have a name.\n",
74fd62
+                                    ldb_dn_get_linearized(msg->dn));
74fd62
+        ret = EINVAL;
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    map->name = talloc_strdup(map, tmp_str);
74fd62
+    if (map->name == NULL) {
74fd62
+        ret = ENOMEM;
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    tmp_str = ldb_msg_find_attr_as_string(msg, attr_map[SSS_CMIM_MAPPING_RULE],
74fd62
+                                          NULL);
74fd62
+    if (tmp_str != NULL) {
74fd62
+        map->map_rule = talloc_strdup(map, tmp_str);
74fd62
+        if (map->map_rule == NULL) {
74fd62
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
74fd62
+            ret = ENOMEM;
74fd62
+            goto done;
74fd62
+        }
74fd62
+    }
74fd62
+
74fd62
+    tmp_str = ldb_msg_find_attr_as_string(msg, attr_map[SSS_CMIM_MATCHING_RULE],
74fd62
+                                          NULL);
74fd62
+    if (tmp_str != NULL) {
74fd62
+        map->match_rule = talloc_strdup(map, tmp_str);
74fd62
+        if (map->match_rule == NULL) {
74fd62
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
74fd62
+            ret = ENOMEM;
74fd62
+            goto done;
74fd62
+        }
74fd62
+    }
74fd62
+
74fd62
+    tmp_uint = ldb_msg_find_attr_as_uint64(msg, attr_map[SSS_CMIM_PRIORITY],
74fd62
+                                           (uint64_t) -1);
74fd62
+    if (tmp_uint != (uint64_t) -1) {
74fd62
+        if (tmp_uint > UINT32_MAX) {
74fd62
+            DEBUG(SSSDBG_OP_FAILURE, "Priority value [%lu] too large.\n",
74fd62
+                                     (unsigned long) tmp_uint);
74fd62
+            ret = EINVAL;
74fd62
+            goto done;
74fd62
+        }
74fd62
+
74fd62
+        map->priority = (uint32_t) tmp_uint;
74fd62
+    } else {
74fd62
+        map->priority = SSS_CERTMAP_MIN_PRIO;
74fd62
+    }
74fd62
+
74fd62
+    tmp_el = ldb_msg_find_element(msg, attr_map[SSS_CMIM_DOMAINS]);
74fd62
+    if (tmp_el != NULL) {
74fd62
+        num_values = tmp_el->num_values;
74fd62
+    } else {
74fd62
+        num_values = 0;
74fd62
+    }
74fd62
+
74fd62
+    map->domains = talloc_zero_array(map, const char *, num_values + 1);
74fd62
+    if (map->domains == NULL) {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
74fd62
+        ret = ENOMEM;
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    for (d = 0; d < num_values; d++) {
74fd62
+        map->domains[d] = talloc_strndup(map->domains,
74fd62
+                                         (char *) tmp_el->values[d].data,
74fd62
+                                         tmp_el->values[d].length);
74fd62
+        if (map->domains[d] == NULL) {
74fd62
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
74fd62
+            ret = ENOMEM;
74fd62
+            goto done;
74fd62
+        }
74fd62
+    }
74fd62
+
74fd62
+    *certmap = map;
74fd62
+
74fd62
+    ret = EOK;
74fd62
+
74fd62
+done:
74fd62
+    if (ret != EOK) {
74fd62
+        talloc_free(map);
74fd62
+    }
74fd62
+
74fd62
+    return ret;
74fd62
+}
74fd62
+
74fd62
 errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
74fd62
                           struct certmap_info ***certmaps, bool *user_name_hint)
74fd62
 {
74fd62
     size_t c;
74fd62
-    size_t d;
74fd62
     struct ldb_dn *container_dn = NULL;
74fd62
     int ret;
74fd62
     struct certmap_info **maps = NULL;
74fd62
     TALLOC_CTX *tmp_ctx = NULL;
74fd62
     struct ldb_result *res;
74fd62
-    const char *tmp_str;
74fd62
-    uint64_t tmp_uint;
74fd62
-    struct ldb_message_element *tmp_el;
74fd62
     const char *attrs[] = {SYSDB_NAME,
74fd62
-                           SYSDB_CERTMAP_PRIORITY,
74fd62
-                           SYSDB_CERTMAP_MATCHING_RULE,
74fd62
                            SYSDB_CERTMAP_MAPPING_RULE,
74fd62
+                           SYSDB_CERTMAP_MATCHING_RULE,
74fd62
+                           SYSDB_CERTMAP_PRIORITY,
74fd62
                            SYSDB_CERTMAP_DOMAINS,
74fd62
                            NULL};
74fd62
     const char *config_attrs[] = {SYSDB_CERTMAP_USER_NAME_HINT,
74fd62
                                   NULL};
74fd62
-    size_t num_values;
74fd62
     bool hint = false;
74fd62
 
74fd62
     tmp_ctx = talloc_new(NULL);
74fd62
@@ -355,86 +479,13 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
74fd62
     }
74fd62
 
74fd62
     for (c = 0; c < res->count; c++) {
74fd62
-        maps[c] = talloc_zero(maps, struct certmap_info);
74fd62
-        if (maps[c] == NULL) {
74fd62
-            ret = ENOMEM;
74fd62
-            goto done;
74fd62
-        }
74fd62
-        tmp_str = ldb_msg_find_attr_as_string(res->msgs[c], SYSDB_NAME, NULL);
74fd62
-        if (tmp_str == NULL) {
74fd62
-            DEBUG(SSSDBG_MINOR_FAILURE, "The object [%s] doesn't have a name.\n",
74fd62
-                                       ldb_dn_get_linearized(res->msgs[c]->dn));
74fd62
-            ret = EINVAL;
74fd62
-            goto done;
74fd62
-        }
74fd62
-
74fd62
-        maps[c]->name = talloc_strdup(maps, tmp_str);
74fd62
-        if (maps[c]->name == NULL) {
74fd62
-            ret = ENOMEM;
74fd62
-            goto done;
74fd62
-        }
74fd62
-
74fd62
-        tmp_str = ldb_msg_find_attr_as_string(res->msgs[c],
74fd62
-                                              SYSDB_CERTMAP_MAPPING_RULE, NULL);
74fd62
-        if (tmp_str != NULL) {
74fd62
-            maps[c]->map_rule = talloc_strdup(maps, tmp_str);
74fd62
-            if (maps[c]->map_rule == NULL) {
74fd62
-                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
74fd62
-                ret = ENOMEM;
74fd62
-                goto done;
74fd62
-            }
74fd62
-        }
74fd62
-
74fd62
-        tmp_str = ldb_msg_find_attr_as_string(res->msgs[c],
74fd62
-                                              SYSDB_CERTMAP_MATCHING_RULE, NULL);
74fd62
-        if (tmp_str != NULL) {
74fd62
-            maps[c]->match_rule = talloc_strdup(maps, tmp_str);
74fd62
-            if (maps[c]->match_rule == NULL) {
74fd62
-                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
74fd62
-                ret = ENOMEM;
74fd62
-                goto done;
74fd62
-            }
74fd62
-        }
74fd62
-
74fd62
-        tmp_uint = ldb_msg_find_attr_as_uint64(res->msgs[c],
74fd62
-                                               SYSDB_CERTMAP_PRIORITY,
74fd62
-                                               (uint64_t) -1);
74fd62
-        if (tmp_uint != (uint64_t) -1) {
74fd62
-            if (tmp_uint > UINT32_MAX) {
74fd62
-                DEBUG(SSSDBG_OP_FAILURE, "Priority value [%lu] too large.\n",
74fd62
-                                         (unsigned long) tmp_uint);
74fd62
-                ret = EINVAL;
74fd62
-                goto done;
74fd62
-            }
74fd62
-
74fd62
-            maps[c]->priority = (uint32_t) tmp_uint;
74fd62
-        }
74fd62
-
74fd62
-        tmp_el = ldb_msg_find_element(res->msgs[c], SYSDB_CERTMAP_DOMAINS);
74fd62
-        if (tmp_el != NULL) {
74fd62
-            num_values = tmp_el->num_values;
74fd62
-        } else {
74fd62
-            num_values = 0;
74fd62
-        }
74fd62
-
74fd62
-        maps[c]->domains = talloc_zero_array(maps[c], const char *,
74fd62
-                                             num_values + 1);
74fd62
-        if (maps[c]->domains == NULL) {
74fd62
-            DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
74fd62
-            ret = ENOMEM;
74fd62
+        ret = sysdb_ldb_msg_attr_to_certmap_info(maps, res->msgs[c], attrs,
74fd62
+                                                 &maps[c]);
74fd62
+        if (ret != EOK) {
74fd62
+            DEBUG(SSSDBG_OP_FAILURE,
74fd62
+                  "sysdb_ldb_msg_attr_to_certmap_info failed.\n");
74fd62
             goto done;
74fd62
         }
74fd62
-
74fd62
-        for (d = 0; d < num_values; d++) {
74fd62
-            maps[c]->domains[d] = talloc_strndup(maps[c]->domains,
74fd62
-                                            (char *) tmp_el->values[d].data,
74fd62
-                                            tmp_el->values[d].length);
74fd62
-            if (maps[c]->domains[d] == NULL) {
74fd62
-                DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
74fd62
-                ret = ENOMEM;
74fd62
-                goto done;
74fd62
-            }
74fd62
-        }
74fd62
     }
74fd62
 
74fd62
     ret = EOK;
74fd62
diff --git a/src/external/cwrap.m4 b/src/external/cwrap.m4
74fd62
index b8489cc76..6e3487c13 100644
74fd62
--- a/src/external/cwrap.m4
74fd62
+++ b/src/external/cwrap.m4
74fd62
@@ -28,3 +28,8 @@ AC_DEFUN([AM_CHECK_NSS_WRAPPER],
74fd62
 [
74fd62
     AM_CHECK_WRAPPER(nss_wrapper, HAVE_NSS_WRAPPER)
74fd62
 ])
74fd62
+
74fd62
+AC_DEFUN([AM_CHECK_PAM_WRAPPER],
74fd62
+[
74fd62
+    AM_CHECK_WRAPPER(pam_wrapper, HAVE_PAM_WRAPPER)
74fd62
+])
74fd62
diff --git a/src/external/intgcheck.m4 b/src/external/intgcheck.m4
74fd62
index ef81ec718..d73c5dfb1 100644
74fd62
--- a/src/external/intgcheck.m4
74fd62
+++ b/src/external/intgcheck.m4
74fd62
@@ -75,6 +75,7 @@ AC_DEFUN([SSS_ENABLE_INTGCHECK_REQS], [
74fd62
     if test x"$enable_intgcheck_reqs" = xyes; then
74fd62
         SSS_INTGCHECK_REQ([HAVE_UID_WRAPPER], [uid_wrapper])
74fd62
         SSS_INTGCHECK_REQ([HAVE_NSS_WRAPPER], [nss_wrapper])
74fd62
+        SSS_INTGCHECK_REQ([HAVE_PAM_WRAPPER], [pam_wrapper])
74fd62
         SSS_INTGCHECK_REQ([HAVE_SLAPD], [slapd])
74fd62
         SSS_INTGCHECK_REQ([HAVE_LDAPMODIFY], [ldapmodify])
74fd62
         SSS_INTGCHECK_REQ([HAVE_FAKEROOT], [fakeroot])
74fd62
diff --git a/src/external/test_ca.m4 b/src/external/test_ca.m4
74fd62
index 2cdb3c750..bb4872698 100644
74fd62
--- a/src/external/test_ca.m4
74fd62
+++ b/src/external/test_ca.m4
74fd62
@@ -58,7 +58,7 @@ AC_DEFUN([AM_CHECK_TEST_CA],
74fd62
             AC_MSG_NOTICE([Could not find p11tool])
74fd62
         fi
74fd62
 
74fd62
-        AM_CONDITIONAL([BUILD_TEST_CA], [test -x "$OPENSSL" -a -x "$SSH_KEYGEN" -a -x "$SOFTHSM2_PATH" -a -x "$SOFTHSM2_UTIL" -a -x "$P11TOOL"])
74fd62
+        AM_CONDITIONAL([BUILD_TEST_CA], [test -x "$OPENSSL" -a -x "$SSH_KEYGEN" -a -r "$SOFTHSM2_PATH" -a -x "$SOFTHSM2_UTIL" -a -x "$P11TOOL"])
74fd62
     fi
74fd62
 
74fd62
     AM_COND_IF([BUILD_TEST_CA],
74fd62
diff --git a/src/lib/certmap/sss_cert_content_crypto.c b/src/lib/certmap/sss_cert_content_crypto.c
74fd62
index ee9aec208..b01830aec 100644
74fd62
--- a/src/lib/certmap/sss_cert_content_crypto.c
74fd62
+++ b/src/lib/certmap/sss_cert_content_crypto.c
74fd62
@@ -771,11 +771,25 @@ int sss_cert_get_content(TALLOC_CTX *mem_ctx,
74fd62
         ret = EIO;
74fd62
         goto done;
74fd62
     }
74fd62
-    if (!(X509_get_extension_flags(cert) & EXFLAG_KUSAGE)) {
74fd62
-        ret = EINVAL;
74fd62
-        goto done;
74fd62
+    if ((X509_get_extension_flags(cert) & EXFLAG_KUSAGE)) {
74fd62
+        cont->key_usage = X509_get_key_usage(cert);
74fd62
+    } else {
74fd62
+        /* According to X.509 https://www.itu.int/rec/T-REC-X.509-201610-I
74fd62
+         * section 13.3.2 "Certificate match" "keyUsage matches if all of the
74fd62
+         * bits set in the presented value are also set in the key usage
74fd62
+         * extension in the stored attribute value, or if there is no key
74fd62
+         * usage extension in the stored attribute value;". So we set all bits
74fd62
+         * in our key_usage to make sure everything matches is keyUsage is not
74fd62
+         * set in the certificate.
74fd62
+         *
74fd62
+         * Please note that NSS currently
74fd62
+         * (https://bugzilla.mozilla.org/show_bug.cgi?id=549952) does not
74fd62
+         * support 'decipherOnly' and will only use 0xff in this case. To have
74fd62
+         * a consistent behavior with both libraries we will use UINT32_MAX
74fd62
+         * for NSS as well. Since comparisons should be always done with a
74fd62
+         * bit-wise and-operation the difference should not matter. */
74fd62
+        cont->key_usage = UINT32_MAX;
74fd62
     }
74fd62
-    cont->key_usage = X509_get_key_usage(cert);
74fd62
 
74fd62
     ret = get_extended_key_usage_oids(cont, cert,
74fd62
                                       &(cont->extended_key_usage_oids));
74fd62
diff --git a/src/lib/certmap/sss_cert_content_nss.c b/src/lib/certmap/sss_cert_content_nss.c
74fd62
index ed7ce24c4..cef1efc26 100644
74fd62
--- a/src/lib/certmap/sss_cert_content_nss.c
74fd62
+++ b/src/lib/certmap/sss_cert_content_nss.c
74fd62
@@ -887,8 +887,25 @@ int sss_cert_get_content(TALLOC_CTX *mem_ctx,
74fd62
         goto done;
74fd62
     }
74fd62
 
74fd62
-
74fd62
-    cont->key_usage = cert->keyUsage;
74fd62
+    /* According to X.509 https://www.itu.int/rec/T-REC-X.509-201610-I
74fd62
+     * section 13.3.2 "Certificate match" "keyUsage matches if all of the
74fd62
+     * bits set in the presented value are also set in the key usage
74fd62
+     * extension in the stored attribute value, or if there is no key
74fd62
+     * usage extension in the stored attribute value;". So we set all bits
74fd62
+     * in our key_usage to make sure everything matches is keyUsage is not
74fd62
+     * set in the certificate.
74fd62
+     *
74fd62
+     * Please note that NSS currently
74fd62
+     * (https://bugzilla.mozilla.org/show_bug.cgi?id=549952) does not
74fd62
+     * support 'decipherOnly' and will only use 0xff in this case. To have
74fd62
+     * a consistent behavior with both libraries we will use UINT32_MAX
74fd62
+     * for NSS as well. Since comparisons should be always done with a
74fd62
+     * bit-wise and-operation the difference should not matter. */
74fd62
+    if (cert->keyUsagePresent == PR_FALSE) {
74fd62
+        cont->key_usage = UINT32_MAX;
74fd62
+    } else {
74fd62
+        cont->key_usage = cert->keyUsage;
74fd62
+    }
74fd62
 
74fd62
     ret = get_extended_key_usage_oids(cont, cert,
74fd62
                                       &(cont->extended_key_usage_oids));
74fd62
diff --git a/src/man/sss-certmap.5.xml b/src/man/sss-certmap.5.xml
74fd62
index db258d14a..10343625e 100644
74fd62
--- a/src/man/sss-certmap.5.xml
74fd62
+++ b/src/man/sss-certmap.5.xml
74fd62
@@ -92,6 +92,15 @@
74fd62
                     <para>
74fd62
                         Example: <SUBJECT>.*,DC=MY,DC=DOMAIN
74fd62
                     </para>
74fd62
+                    <para>
74fd62
+                        Please note that the characters "^.[$()|*+?{\" have a
74fd62
+                        special meaning in regular expressions and must be
74fd62
+                        escaped with the help of the '\' character so that they
74fd62
+                        are matched as ordinary characters.
74fd62
+                    </para>
74fd62
+                    <para>
74fd62
+                        Example: <SUBJECT>^CN=.* \(Admin\),DC=MY,DC=DOMAIN$
74fd62
+                    </para>
74fd62
                     </listitem>
74fd62
                 </varlistentry>
74fd62
                 <varlistentry>
74fd62
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
74fd62
index 0e1a97a31..8adbb8de9 100644
74fd62
--- a/src/man/sssd.conf.5.xml
74fd62
+++ b/src/man/sssd.conf.5.xml
74fd62
@@ -3452,6 +3452,135 @@ ldap_user_extra_attrs = phone:telephoneNumber
74fd62
         </para>
74fd62
     </refsect1>
74fd62
 
74fd62
+    <refsect1 id='certmap'>
74fd62
+        <title>CERTIFICATE MAPPING SECTION</title>
74fd62
+        <para>
74fd62
+            To allow authentication with Smartcards and certificates SSSD must
74fd62
+            be able to map certificates to users. This can be done by adding the
74fd62
+            full certificate to the LDAP object of the user or to a local
74fd62
+            override. While using the full certificate is required to use the
74fd62
+            Smartcard authentication feature of SSH (see
74fd62
+                <citerefentry>
74fd62
+                    <refentrytitle>sss_ssh_authorizedkeys</refentrytitle>
74fd62
+                    <manvolnum>8</manvolnum>
74fd62
+                </citerefentry>
74fd62
+            for details) it might be cumbersome or not even possible to do this
74fd62
+            for the general case where local services use PAM for
74fd62
+            authentication.
74fd62
+        </para>
74fd62
+        <para>
74fd62
+            To make the mapping more flexible mapping and matching rules were
74fd62
+            added to SSSD (see
74fd62
+                <citerefentry>
74fd62
+                    <refentrytitle>sss-certmap</refentrytitle>
74fd62
+                    <manvolnum>5</manvolnum>
74fd62
+                </citerefentry>
74fd62
+            for details).
74fd62
+        </para>
74fd62
+        <para>
74fd62
+            A mapping and matching rule can be added to the SSSD configuration
74fd62
+            in a section on its own with a name like
74fd62
+            <quote>[certmap/<replaceable>DOMAIN_NAME</replaceable>/<replaceable>RULE_NAME</replaceable>]</quote>.
74fd62
+            In this section the following options are allowed:
74fd62
+        </para>
74fd62
+        <variablelist>
74fd62
+            <varlistentry>
74fd62
+                <term>matchrule (string)</term>
74fd62
+                <listitem>
74fd62
+                    <para>
74fd62
+                        Only certificates from the Smartcard which matches this
74fd62
+                        rule will be processed, all others are ignored.
74fd62
+                    </para>
74fd62
+                    <para>
74fd62
+                        Default: KRB5:<EKU>clientAuth, i.e. only
74fd62
+                        certificates which have the Extended Key Usage
74fd62
+                        <quote>clientAuth</quote>
74fd62
+                    </para>
74fd62
+                </listitem>
74fd62
+            </varlistentry>
74fd62
+            <varlistentry>
74fd62
+                <term>maprule (string)</term>
74fd62
+                <listitem>
74fd62
+                    <para>
74fd62
+                        Defines how the user is found for a given certificate.
74fd62
+                    </para>
74fd62
+                    <para>
74fd62
+                        Default:
74fd62
+                        <itemizedlist>
74fd62
+                            <listitem>
74fd62
+                                <para>LDAP:(userCertificate;binary={cert!bin})
74fd62
+                                for LDAP based providers like
74fd62
+                                <quote>ldap</quote>, <quote>AD</quote> or
74fd62
+                                <quote>ipa</quote>.</para>
74fd62
+                            </listitem>
74fd62
+                            <listitem>
74fd62
+                                <para>The RULE_NAME for the <quote>files</quote>
74fd62
+                                provider which tries to find a user with the
74fd62
+                                same name.</para>
74fd62
+                            </listitem>
74fd62
+                        </itemizedlist>
74fd62
+                    </para>
74fd62
+                </listitem>
74fd62
+            </varlistentry>
74fd62
+            <varlistentry>
74fd62
+                <term>domains (string)</term>
74fd62
+                <listitem>
74fd62
+                    <para>
74fd62
+                        Comma separated list of domain names the rule should be
74fd62
+                        applied. By default a rule is only valid in the domain
74fd62
+                        configured in sssd.conf. If the provider supports
74fd62
+                        subdomains this option can be used to add the rule to
74fd62
+                        subdomains as well.
74fd62
+                    </para>
74fd62
+                    <para>
74fd62
+                        Default: the configured domain in sssd.conf
74fd62
+                    </para>
74fd62
+                </listitem>
74fd62
+            </varlistentry>
74fd62
+            <varlistentry>
74fd62
+                <term>priority (integer)</term>
74fd62
+                <listitem>
74fd62
+                    <para>
74fd62
+                        Unsigned integer value defining the priority of the
74fd62
+                        rule. The higher the number the lower the priority.
74fd62
+                        <quote>0</quote> stands for the highest priority while
74fd62
+                        <quote>4294967295</quote> is the lowest.
74fd62
+                    </para>
74fd62
+                    <para>
74fd62
+                        Default: the lowest priority
74fd62
+                    </para>
74fd62
+                </listitem>
74fd62
+            </varlistentry>
74fd62
+        </variablelist>
74fd62
+        <para>
74fd62
+            To make the configuration simple and reduce the amount of
74fd62
+            configuration options the <quote>files</quote> provider has some
74fd62
+            special properties:
74fd62
+            <itemizedlist>
74fd62
+                <listitem>
74fd62
+                    <para>
74fd62
+                        if maprule is not set the RULE_NAME name is assumed to
74fd62
+                        be the name of the matching user
74fd62
+                    </para>
74fd62
+                </listitem>
74fd62
+                <listitem>
74fd62
+                    <para>
74fd62
+                        if a maprule is used both a single user name or a
74fd62
+                        template like
74fd62
+                        <quote>{subject_rfc822_name.short_name}</quote> must
74fd62
+                        be in braces like e.g. <quote>(username)</quote> or
74fd62
+                        <quote>({subject_rfc822_name.short_name})</quote>
74fd62
+                    </para>
74fd62
+                </listitem>
74fd62
+                <listitem>
74fd62
+                    <para>
74fd62
+                        the <quote>domains</quote> option is ignored
74fd62
+                    </para>
74fd62
+                </listitem>
74fd62
+            </itemizedlist>
74fd62
+        </para>
74fd62
+    </refsect1>
74fd62
+
74fd62
     <refsect1 id='example'>
74fd62
         <title>EXAMPLES</title>
74fd62
         <para>
74fd62
@@ -3494,6 +3623,26 @@ enumerate = False
74fd62
 <programlisting>
74fd62
 [domain/ipa.com/child.ad.com]
74fd62
 use_fully_qualified_names = false
74fd62
+</programlisting>
74fd62
+        </para>
74fd62
+        <para>
74fd62
+            3. The following example shows the configuration for two certificate
74fd62
+            mapping rules. The first is valid for the configured domain
74fd62
+            <quote>my.domain</quote> and additionally for the subdomains
74fd62
+            <quote>your.domain</quote> and uses the full certificate in the
74fd62
+            search filter. The second example is valid for the domain
74fd62
+            <quote>files</quote> where it is assumed the files provider is used
74fd62
+            for this domain and contains a matching rule for the local user
74fd62
+            <quote>myname</quote>.
74fd62
+<programlisting>
74fd62
+[certmap/my.domain/rule_name]
74fd62
+matchrule = <ISSUER>^CN=My-CA,DC=MY,DC=DOMAIN$
74fd62
+maprule = (userCertificate;binary={cert!bin})
74fd62
+domains = my.domain, your.domain
74fd62
+priority = 10
74fd62
+
74fd62
+[certmap/files/myname]
74fd62
+matchrule = <ISSUER>^CN=My-CA,DC=MY,DC=DOMAIN$<SUBJECT>^CN=User.Name,DC=MY,DC=DOMAIN$
74fd62
 </programlisting>
74fd62
         </para>
74fd62
     </refsect1>
74fd62
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
74fd62
index 09397852b..fb24a28e1 100644
74fd62
--- a/src/providers/ad/ad_init.c
74fd62
+++ b/src/providers/ad/ad_init.c
74fd62
@@ -427,6 +427,22 @@ static errno_t ad_init_misc(struct be_ctx *be_ctx,
74fd62
         return ret;
74fd62
     }
74fd62
 
74fd62
+    ret = confdb_certmap_to_sysdb(be_ctx->cdb, be_ctx->domain);
74fd62
+    if (ret != EOK) {
74fd62
+        DEBUG(SSSDBG_CRIT_FAILURE,
74fd62
+              "Failed to initialize certificate mapping rules. "
74fd62
+              "Authentication with certificates/Smartcards might not work "
74fd62
+              "as expected.\n");
74fd62
+        /* not fatal, ignored */
74fd62
+    }
74fd62
+
74fd62
+    ret = sdap_init_certmap(sdap_id_ctx, sdap_id_ctx);
74fd62
+    if (ret != EOK) {
74fd62
+        DEBUG(SSSDBG_CRIT_FAILURE,
74fd62
+              "Failed to initialized certificate mapping.\n");
74fd62
+        return ret;
74fd62
+    }
74fd62
+
74fd62
     return EOK;
74fd62
 }
74fd62
 
74fd62
diff --git a/src/providers/files/files_auth.c b/src/providers/files/files_auth.c
74fd62
new file mode 100644
74fd62
index 000000000..b71de6971
74fd62
--- /dev/null
74fd62
+++ b/src/providers/files/files_auth.c
74fd62
@@ -0,0 +1,69 @@
74fd62
+/*
74fd62
+    SSSD
74fd62
+
74fd62
+    files_auth.c - PAM operations on the files provider
74fd62
+
74fd62
+    Copyright (C) 2018 Red Hat
74fd62
+
74fd62
+    This program is free software; you can redistribute it and/or modify
74fd62
+    it under the terms of the GNU General Public License as published by
74fd62
+    the Free Software Foundation; either version 3 of the License, or
74fd62
+    (at your option) any later version.
74fd62
+
74fd62
+    This program is distributed in the hope that it will be useful,
74fd62
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
74fd62
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
74fd62
+    GNU General Public License for more details.
74fd62
+
74fd62
+    You should have received a copy of the GNU General Public License
74fd62
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
74fd62
+*/
74fd62
+
74fd62
+#include <security/pam_modules.h>
74fd62
+
74fd62
+#include "providers/data_provider/dp.h"
74fd62
+#include "providers/data_provider.h"
74fd62
+#include "providers/files/files_private.h"
74fd62
+#include "util/cert.h"
74fd62
+
74fd62
+struct files_auth_ctx {
74fd62
+    struct pam_data *pd;
74fd62
+};
74fd62
+
74fd62
+struct tevent_req *
74fd62
+files_auth_handler_send(TALLOC_CTX *mem_ctx,
74fd62
+                        void *unused,
74fd62
+                        struct pam_data *pd,
74fd62
+                        struct dp_req_params *params)
74fd62
+{
74fd62
+    struct files_auth_ctx *state;
74fd62
+    struct tevent_req *req;
74fd62
+
74fd62
+    req = tevent_req_create(mem_ctx, &state, struct files_auth_ctx);
74fd62
+    if (req == NULL) {
74fd62
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
74fd62
+        return NULL;
74fd62
+    }
74fd62
+
74fd62
+    state->pd = pd;
74fd62
+    state->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
74fd62
+
74fd62
+    tevent_req_done(req);
74fd62
+    tevent_req_post(req, params->ev);
74fd62
+    return req;
74fd62
+}
74fd62
+
74fd62
+errno_t files_auth_handler_recv(TALLOC_CTX *mem_ctx,
74fd62
+                                struct tevent_req *req,
74fd62
+                                struct pam_data **_data)
74fd62
+{
74fd62
+    struct files_auth_ctx *state = NULL;
74fd62
+
74fd62
+    state = tevent_req_data(req, struct files_auth_ctx);
74fd62
+
74fd62
+    TEVENT_REQ_RETURN_ON_ERROR(req);
74fd62
+
74fd62
+    *_data = talloc_steal(mem_ctx, state->pd);
74fd62
+
74fd62
+    return EOK;
74fd62
+}
74fd62
diff --git a/src/providers/files/files_certmap.c b/src/providers/files/files_certmap.c
74fd62
new file mode 100644
74fd62
index 000000000..7d90a1fec
74fd62
--- /dev/null
74fd62
+++ b/src/providers/files/files_certmap.c
74fd62
@@ -0,0 +1,186 @@
74fd62
+/*
74fd62
+    SSSD
74fd62
+
74fd62
+    files_init.c - Initialization of the files provider
74fd62
+
74fd62
+    Copyright (C) 2018 Red Hat
74fd62
+
74fd62
+    This program is free software; you can redistribute it and/or modify
74fd62
+    it under the terms of the GNU General Public License as published by
74fd62
+    the Free Software Foundation; either version 3 of the License, or
74fd62
+    (at your option) any later version.
74fd62
+
74fd62
+    This program is distributed in the hope that it will be useful,
74fd62
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
74fd62
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
74fd62
+    GNU General Public License for more details.
74fd62
+
74fd62
+    You should have received a copy of the GNU General Public License
74fd62
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
74fd62
+*/
74fd62
+
74fd62
+#include "providers/files/files_private.h"
74fd62
+#include "util/util.h"
74fd62
+#include "util/cert.h"
74fd62
+#include "lib/certmap/sss_certmap.h"
74fd62
+
74fd62
+struct priv_sss_debug {
74fd62
+    int level;
74fd62
+};
74fd62
+
74fd62
+static void ext_debug(void *private, const char *file, long line,
74fd62
+                      const char *function, const char *format, ...)
74fd62
+{
74fd62
+    va_list ap;
74fd62
+    struct priv_sss_debug *data = private;
74fd62
+    int level = SSSDBG_OP_FAILURE;
74fd62
+
74fd62
+    if (data != NULL) {
74fd62
+        level = data->level;
74fd62
+    }
74fd62
+
74fd62
+    if (DEBUG_IS_SET(level)) {
74fd62
+        va_start(ap, format);
74fd62
+        sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
74fd62
+                      format, ap);
74fd62
+        va_end(ap);
74fd62
+    }
74fd62
+}
74fd62
+
74fd62
+errno_t files_init_certmap(TALLOC_CTX *mem_ctx, struct files_id_ctx *id_ctx)
74fd62
+{
74fd62
+    int ret;
74fd62
+    bool hint;
74fd62
+    struct certmap_info **certmap_list = NULL;
74fd62
+    size_t c;
74fd62
+
74fd62
+    ret = sysdb_get_certmap(mem_ctx, id_ctx->be->domain->sysdb,
74fd62
+                            &certmap_list, &hint);
74fd62
+    if (ret != EOK) {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_certmap failed.\n");
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    if (certmap_list == NULL || *certmap_list == NULL) {
74fd62
+        DEBUG(SSSDBG_TRACE_ALL, "No certmap data, nothing to do.\n");
74fd62
+        ret = EOK;
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    ret = sss_certmap_init(mem_ctx, ext_debug, NULL, &id_ctx->sss_certmap_ctx);
74fd62
+    if (ret != EOK) {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n");
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    for (c = 0; certmap_list[c] != NULL; c++) {
74fd62
+        DEBUG(SSSDBG_TRACE_ALL, "Trying to add rule [%s][%d][%s][%s].\n",
74fd62
+                                certmap_list[c]->name,
74fd62
+                                certmap_list[c]->priority,
74fd62
+                                certmap_list[c]->match_rule,
74fd62
+                                certmap_list[c]->map_rule);
74fd62
+
74fd62
+        ret = sss_certmap_add_rule(id_ctx->sss_certmap_ctx,
74fd62
+                                   certmap_list[c]->priority,
74fd62
+                                   certmap_list[c]->match_rule,
74fd62
+                                   certmap_list[c]->map_rule,
74fd62
+                                   certmap_list[c]->domains);
74fd62
+        if (ret != 0) {
74fd62
+            DEBUG(SSSDBG_CRIT_FAILURE,
74fd62
+                  "sss_certmap_add_rule failed for rule [%s] "
74fd62
+                  "with error [%d][%s], skipping. "
74fd62
+                  "Please check for typos and if rule syntax is supported.\n",
74fd62
+                  certmap_list[c]->name, ret, sss_strerror(ret));
74fd62
+            continue;
74fd62
+        }
74fd62
+    }
74fd62
+
74fd62
+    ret = EOK;
74fd62
+
74fd62
+done:
74fd62
+    talloc_free(certmap_list);
74fd62
+
74fd62
+    return ret;
74fd62
+}
74fd62
+
74fd62
+errno_t files_map_cert_to_user(struct files_id_ctx *id_ctx,
74fd62
+                               struct dp_id_data *data)
74fd62
+{
74fd62
+    errno_t ret;
74fd62
+    char *filter;
74fd62
+    char *user;
74fd62
+    struct ldb_message *msg = NULL;
74fd62
+    struct sysdb_attrs *attrs = NULL;
74fd62
+    TALLOC_CTX *tmp_ctx;
74fd62
+
74fd62
+    tmp_ctx = talloc_new(NULL);
74fd62
+    if (tmp_ctx == NULL) {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
74fd62
+        return ENOMEM;
74fd62
+    }
74fd62
+
74fd62
+    ret = sss_cert_derb64_to_ldap_filter(tmp_ctx, data->filter_value, "",
74fd62
+                                         id_ctx->sss_certmap_ctx,
74fd62
+                                         id_ctx->domain, &filter);
74fd62
+    if (ret != EOK) {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE,
74fd62
+              "sss_cert_derb64_to_ldap_filter failed.\n");
74fd62
+        goto done;
74fd62
+    }
74fd62
+    if (filter == NULL || filter[0] != '('
74fd62
+                       || filter[strlen(filter) - 1] != ')') {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE,
74fd62
+              "sss_cert_derb64_to_ldap_filter returned bad filter [%s].\n",
74fd62
+              filter);
74fd62
+        ret = EINVAL;
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    filter[strlen(filter) - 1] = '\0';
74fd62
+    user = sss_create_internal_fqname(tmp_ctx, &filter[1],
74fd62
+                                      id_ctx->domain->name);
74fd62
+    if (user == NULL) {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE, "sss_create_internal_fqname failed.\n");
74fd62
+        ret = ENOMEM;
74fd62
+        goto done;
74fd62
+    }
74fd62
+    DEBUG(SSSDBG_TRACE_ALL, "Certificate mapped to user: [%s].\n", user);
74fd62
+
74fd62
+    ret = sysdb_search_user_by_name(tmp_ctx, id_ctx->domain, user, NULL, &msg;;
74fd62
+    if (ret == EOK) {
74fd62
+        attrs = sysdb_new_attrs(tmp_ctx);
74fd62
+        if (attrs == NULL) {
74fd62
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
74fd62
+            ret = ENOMEM;
74fd62
+            goto done;
74fd62
+        }
74fd62
+
74fd62
+        ret = sysdb_attrs_add_base64_blob(attrs, SYSDB_USER_MAPPED_CERT,
74fd62
+                                          data->filter_value);
74fd62
+        if (ret != EOK) {
74fd62
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_base64_blob failed.\n");
74fd62
+            goto done;
74fd62
+        }
74fd62
+
74fd62
+        ret = sysdb_set_entry_attr(id_ctx->domain->sysdb, msg->dn, attrs,
74fd62
+                                   SYSDB_MOD_ADD);
74fd62
+        if (ret != EOK) {
74fd62
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_entry_attr failed.\n");
74fd62
+            goto done;
74fd62
+        }
74fd62
+    } else if (ret == ENOENT) {
74fd62
+        DEBUG(SSSDBG_TRACE_ALL, "Mapped user [%s] not found.\n", user);
74fd62
+        ret = EOK;
74fd62
+        goto done;
74fd62
+    } else {
74fd62
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_name failed.\n");
74fd62
+        goto done;
74fd62
+    }
74fd62
+
74fd62
+    ret = EOK;
74fd62
+
74fd62
+done:
74fd62
+    talloc_free(tmp_ctx);
74fd62
+
74fd62
+    return ret;
74fd62
+}
74fd62
diff --git a/src/providers/files/files_id.c b/src/providers/files/files_id.c
74fd62
index 41314c66b..f6f8c7311 100644
74fd62
--- a/src/providers/files/files_id.c
74fd62
+++ b/src/providers/files/files_id.c
74fd62
@@ -87,6 +87,26 @@ files_account_info_handler_send(TALLOC_CTX *mem_ctx,
74fd62
                        ? true \
74fd62
                        : false;
74fd62
         break;
74fd62
+    case BE_REQ_BY_CERT:
74fd62
+        if (data->filter_type != BE_FILTER_CERT) {
74fd62
+            DEBUG(SSSDBG_CRIT_FAILURE,
74fd62
+                  "Unexpected filter type for lookup by cert: %d\n",
74fd62
+                  data->filter_type);
74fd62
+            ret = EINVAL;
74fd62
+            goto immediate;
74fd62
+        }
74fd62
+        if (id_ctx->sss_certmap_ctx == NULL) {
74fd62
+            DEBUG(SSSDBG_TRACE_ALL, "Certificate mapping not configured.\n");
74fd62
+            ret = EOK;
74fd62
+            goto immediate;
74fd62
+        }
74fd62
+
74fd62
+        ret = files_map_cert_to_user(id_ctx, data);
74fd62
+        if (ret != EOK) {
74fd62
+            DEBUG(SSSDBG_OP_FAILURE, "files_map_cert_to_user failed");
74fd62
+        }
74fd62
+        goto immediate;
74fd62
+        break;
74fd62
     default:
74fd62
         DEBUG(SSSDBG_CRIT_FAILURE,
74fd62
               "Unexpected entry type: %d\n", data->entry_type & BE_REQ_TYPE_MASK);
74fd62
diff --git a/src/providers/files/files_init.c b/src/providers/files/files_init.c
74fd62
index 746c04af1..1ce4bcf27 100644
74fd62
--- a/src/providers/files/files_init.c
74fd62
+++ b/src/providers/files/files_init.c
74fd62
@@ -189,6 +189,23 @@ int sssm_files_init(TALLOC_CTX *mem_ctx,
74fd62
         goto done;
74fd62
     }
74fd62
 
74fd62
+    ret = confdb_certmap_to_sysdb(be_ctx->cdb, be_ctx->domain);
74fd62
+    if (ret != EOK) {
74fd62
+        DEBUG(SSSDBG_CRIT_FAILURE,
74fd62
+              "Failed to initialize certificate mapping rules. "
74fd62
+              "Authentication with certificates/Smartcards might not work "
74fd62
+              "as expected.\n");
74fd62
+        /* not fatal, ignored */
74fd62
+    } else {
74fd62
+        ret = files_init_certmap(ctx, ctx);
74fd62
+        if (ret != EOK) {
74fd62
+            DEBUG(SSSDBG_CRIT_FAILURE, "files_init_certmap failed. "
74fd62
+                  "Authentication with certificates/Smartcards might not work "
74fd62
+                  "as expected.\n");
74fd62
+            /* not fatal, ignored */
74fd62
+        }
74fd62
+    }
74fd62
+
74fd62
     *_module_data = ctx;
74fd62
     ret = EOK;
74fd62
 done:
74fd62
@@ -224,3 +241,15 @@ int sssm_files_id_init(TALLOC_CTX *mem_ctx,
74fd62
 
74fd62
     return EOK;
74fd62
 }
74fd62
+
74fd62
+int sssm_files_auth_init(TALLOC_CTX *mem_ctx,
74fd62
+                         struct be_ctx *be_ctx,
74fd62
+                         void *module_data,
74fd62
+                         struct dp_method *dp_methods)
74fd62
+{
74fd62
+    dp_set_method(dp_methods, DPM_AUTH_HANDLER,
74fd62
+                  files_auth_handler_send, files_auth_handler_recv, NULL, void,
74fd62
+                  struct pam_data, struct pam_data *);
74fd62
+
74fd62
+    return EOK;
74fd62
+}
74fd62
diff --git a/src/providers/files/files_private.h b/src/providers/files/files_private.h
74fd62
index f44e6d458..fd1781930 100644
74fd62
--- a/src/providers/files/files_private.h
74fd62
+++ b/src/providers/files/files_private.h
74fd62
@@ -38,6 +38,7 @@ struct files_id_ctx {
74fd62
     struct be_ctx *be;
74fd62
     struct sss_domain_info *domain;
74fd62
     struct files_ctx *fctx;
74fd62
+    struct sss_certmap_ctx *sss_certmap_ctx;
74fd62
 
74fd62
     const char **passwd_files;
74fd62
     const char **group_files;
74fd62
@@ -71,4 +72,20 @@ errno_t files_account_info_handler_recv(TALLOC_CTX *mem_ctx,
74fd62
 void files_account_info_finished(struct files_id_ctx *id_ctx,
74fd62
                                  int req_type,
74fd62
                                  errno_t ret);
74fd62
+
74fd62
+/* files_auth.c */
74fd62
+struct tevent_req *files_auth_handler_send(TALLOC_CTX *mem_ctx,
74fd62
+                                           void *unused,
74fd62
+                                           struct pam_data *pd,
74fd62
+                                           struct dp_req_params *params);
74fd62
+
74fd62
+errno_t files_auth_handler_recv(TALLOC_CTX *mem_ctx,
74fd62
+                                struct tevent_req *req,
74fd62
+                                struct pam_data **_data);
74fd62
+
74fd62
+/* files_certmap.c */
74fd62
+errno_t files_init_certmap(TALLOC_CTX *mem_ctx, struct files_id_ctx *id_ctx);
74fd62
+
74fd62
+errno_t files_map_cert_to_user(struct files_id_ctx *id_ctx,
74fd62
+                               struct dp_id_data *data);
74fd62
 #endif /* __FILES_PRIVATE_H_ */
74fd62
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
74fd62
index 3714d5d79..7998cc8ff 100644
74fd62
--- a/src/providers/ldap/ldap_init.c
74fd62
+++ b/src/providers/ldap/ldap_init.c
74fd62
@@ -439,6 +439,22 @@ static errno_t ldap_init_misc(struct be_ctx *be_ctx,
74fd62
               "[%d]: %s\n", ret, sss_strerror(ret));
74fd62
     }
74fd62
 
74fd62
+    ret = confdb_certmap_to_sysdb(be_ctx->cdb, be_ctx->domain);
74fd62
+    if (ret != EOK) {
74fd62
+        DEBUG(SSSDBG_CRIT_FAILURE,
74fd62
+              "Failed to initialize certificate mapping rules. "
74fd62
+              "Authentication with certificates/Smartcards might not work "
74fd62
+              "as expected.\n");
74fd62
+        /* not fatal, ignored */
74fd62
+    }
74fd62
+
74fd62
+    ret = sdap_init_certmap(id_ctx, id_ctx);
74fd62
+    if (ret != EOK) {
74fd62
+        DEBUG(SSSDBG_CRIT_FAILURE,
74fd62
+              "Failed to initialized certificate mapping.\n");
74fd62
+        return ret;
74fd62
+    }
74fd62
+
74fd62
     return EOK;
74fd62
 }
74fd62
 
74fd62
diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c
74fd62
index 208c415ac..a49b31528 100644
74fd62
--- a/src/responder/common/responder_dp.c
74fd62
+++ b/src/responder/common/responder_dp.c
74fd62
@@ -598,15 +598,17 @@ static int sss_dp_account_files_params(struct sss_domain_info *dom,
74fd62
                                        enum sss_dp_acct_type *_type_out,
74fd62
                                        const char **_opt_name_out)
74fd62
 {
74fd62
-    if (sss_domain_get_state(dom) != DOM_INCONSISTENT) {
74fd62
+    if (type_in != SSS_DP_CERT) {
74fd62
+        if (sss_domain_get_state(dom) != DOM_INCONSISTENT) {
74fd62
+            DEBUG(SSSDBG_TRACE_INTERNAL,
74fd62
+                  "The entries in the files domain are up-to-date\n");
74fd62
+            return EOK;
74fd62
+        }
74fd62
+
74fd62
         DEBUG(SSSDBG_TRACE_INTERNAL,
74fd62
-              "The entries in the files domain are up-to-date\n");
74fd62
-        return EOK;
74fd62
+              "Domain files is not consistent, issuing update\n");
74fd62
     }
74fd62
 
74fd62
-    DEBUG(SSSDBG_TRACE_INTERNAL,
74fd62
-          "Domain files is not consistent, issuing update\n");
74fd62
-
74fd62
     switch(type_in) {
74fd62
     case SSS_DP_USER:
74fd62
     case SSS_DP_GROUP:
74fd62
@@ -620,12 +622,16 @@ static int sss_dp_account_files_params(struct sss_domain_info *dom,
74fd62
         *_type_out = type_in;
74fd62
         *_opt_name_out = DP_REQ_OPT_FILES_INITGR;
74fd62
         return EAGAIN;
74fd62
+    case SSS_DP_CERT:
74fd62
+        /* Let the backend handle certificate mapping for local users */
74fd62
+        *_type_out = type_in;
74fd62
+        *_opt_name_out = opt_name_in;
74fd62
+        return EAGAIN;
74fd62
     /* These are not handled by the files provider, just fall back */
74fd62
     case SSS_DP_NETGR:
74fd62
     case SSS_DP_SERVICES:
74fd62
     case SSS_DP_SECID:
74fd62
     case SSS_DP_USER_AND_GROUP:
74fd62
-    case SSS_DP_CERT:
74fd62
     case SSS_DP_WILDCARD_USER:
74fd62
     case SSS_DP_WILDCARD_GROUP:
74fd62
         return EOK;
74fd62
diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
74fd62
index 319362a95..ccb2037b1 100644
74fd62
--- a/src/responder/pam/pamsrv.h
74fd62
+++ b/src/responder/pam/pamsrv.h
74fd62
@@ -123,7 +123,7 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
74fd62
 bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd);
74fd62
 
74fd62
 errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx,
74fd62
-                                struct certmap_info **certmap_list);
74fd62
+                                struct sss_domain_info *domains);
74fd62
 
74fd62
 errno_t
74fd62
 pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain,
74fd62
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
74fd62
index 00302be75..139f4260e 100644
74fd62
--- a/src/responder/pam/pamsrv_cmd.c
74fd62
+++ b/src/responder/pam/pamsrv_cmd.c
74fd62
@@ -1461,7 +1461,9 @@ static void pam_forwarder_cert_cb(struct tevent_req *req)
74fd62
             if (pd->cmd == SSS_PAM_AUTHENTICATE) {
74fd62
                 DEBUG(SSSDBG_CRIT_FAILURE,
74fd62
                       "No certificate returned, authentication failed.\n");
74fd62
-                ret = ENOENT;
74fd62
+                preq->pd->pam_status = PAM_AUTH_ERR;
74fd62
+                pam_reply(preq);
74fd62
+                return;
74fd62
             } else {
74fd62
                 ret = pam_check_user_search(preq);
74fd62
             }
74fd62
@@ -1762,7 +1764,7 @@ static void pam_forwarder_cb(struct tevent_req *req)
74fd62
         goto done;
74fd62
     }
74fd62
 
74fd62
-    ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains->certmaps);
74fd62
+    ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains);
74fd62
     if (ret != EOK) {
74fd62
         DEBUG(SSSDBG_OP_FAILURE,
74fd62
               "p11_refresh_certmap_ctx failed, "
74fd62
diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
74fd62
index c7e57be17..c58a8bedd 100644
74fd62
--- a/src/responder/pam/pamsrv_p11.c
74fd62
+++ b/src/responder/pam/pamsrv_p11.c
74fd62
@@ -141,11 +141,14 @@ static void ext_debug(void *private, const char *file, long line,
74fd62
 }
74fd62
 
74fd62
 errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx,
74fd62
-                                struct certmap_info **certmap_list)
74fd62
+                                struct sss_domain_info *domains)
74fd62
 {
74fd62
     int ret;
74fd62
     struct sss_certmap_ctx *sss_certmap_ctx = NULL;
74fd62
     size_t c;
74fd62
+    struct sss_domain_info *dom;
74fd62
+    bool certmap_found = false;
74fd62
+    struct certmap_info **certmap_list;
74fd62
 
74fd62
     ret = sss_certmap_init(pctx, ext_debug, NULL, &sss_certmap_ctx);
74fd62
     if (ret != EOK) {
74fd62
@@ -153,7 +156,15 @@ errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx,
74fd62
         goto done;
74fd62
     }
74fd62
 
74fd62
-    if (certmap_list == NULL || *certmap_list == NULL) {
74fd62
+    DLIST_FOR_EACH(dom, domains) {
74fd62
+        certmap_list = dom->certmaps;
74fd62
+        if (certmap_list != NULL && *certmap_list != NULL) {
74fd62
+            certmap_found = true;
74fd62
+            break;
74fd62
+        }
74fd62
+    }
74fd62
+
74fd62
+    if (!certmap_found) {
74fd62
         /* Try to add default matching rule */
74fd62
         ret = sss_certmap_add_rule(sss_certmap_ctx, SSS_CERTMAP_MIN_PRIO,
74fd62
                                    CERT_AUTH_DEFAULT_MATCHING_RULE, NULL, NULL);
74fd62
@@ -165,24 +176,32 @@ errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx,
74fd62
         goto done;
74fd62
     }
74fd62
 
74fd62
-    for (c = 0; certmap_list[c] != NULL; c++) {
74fd62
-        DEBUG(SSSDBG_TRACE_ALL,
74fd62
-              "Trying to add rule [%s][%d][%s][%s].\n",
74fd62
-              certmap_list[c]->name, certmap_list[c]->priority,
74fd62
-              certmap_list[c]->match_rule, certmap_list[c]->map_rule);
74fd62
-
74fd62
-        ret = sss_certmap_add_rule(sss_certmap_ctx, certmap_list[c]->priority,
74fd62
-                                   certmap_list[c]->match_rule,
74fd62
-                                   certmap_list[c]->map_rule,
74fd62
-                                   certmap_list[c]->domains);
74fd62
-        if (ret != 0) {
74fd62
-            DEBUG(SSSDBG_CRIT_FAILURE,
74fd62
-                  "sss_certmap_add_rule failed for rule [%s] "
74fd62
-                  "with error [%d][%s], skipping. "
74fd62
-                  "Please check for typos and if rule syntax is supported.\n",
74fd62
-                  certmap_list[c]->name, ret, sss_strerror(ret));
74fd62
+    DLIST_FOR_EACH(dom, domains) {
74fd62
+        certmap_list = dom->certmaps;
74fd62
+        if (certmap_list == NULL || *certmap_list == NULL) {
74fd62
             continue;
74fd62
         }
74fd62
+
74fd62
+        for (c = 0; certmap_list[c] != NULL; c++) {
74fd62
+            DEBUG(SSSDBG_TRACE_ALL,
74fd62
+                  "Trying to add rule [%s][%d][%s][%s].\n",
74fd62
+                  certmap_list[c]->name, certmap_list[c]->priority,
74fd62
+                  certmap_list[c]->match_rule, certmap_list[c]->map_rule);
74fd62
+
74fd62
+            ret = sss_certmap_add_rule(sss_certmap_ctx,
74fd62
+                                       certmap_list[c]->priority,
74fd62
+                                       certmap_list[c]->match_rule,
74fd62
+                                       certmap_list[c]->map_rule,
74fd62
+                                       certmap_list[c]->domains);
74fd62
+            if (ret != 0) {
74fd62
+                DEBUG(SSSDBG_CRIT_FAILURE,
74fd62
+                      "sss_certmap_add_rule failed for rule [%s] "
74fd62
+                      "with error [%d][%s], skipping. "
74fd62
+                      "Please check for typos and if rule syntax is supported.\n",
74fd62
+                      certmap_list[c]->name, ret, sss_strerror(ret));
74fd62
+                continue;
74fd62
+            }
74fd62
+        }
74fd62
     }
74fd62
 
74fd62
     ret = EOK;
74fd62
@@ -203,19 +222,21 @@ errno_t p11_child_init(struct pam_ctx *pctx)
74fd62
     int ret;
74fd62
     struct certmap_info **certmaps;
74fd62
     bool user_name_hint;
74fd62
-    struct sss_domain_info *dom = pctx->rctx->domains;
74fd62
+    struct sss_domain_info *dom;
74fd62
 
74fd62
-    ret = sysdb_get_certmap(dom, dom->sysdb, &certmaps, &user_name_hint);
74fd62
-    if (ret != EOK) {
74fd62
-        DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_certmap failed.\n");
74fd62
-        return ret;
74fd62
-    }
74fd62
+    DLIST_FOR_EACH(dom, pctx->rctx->domains) {
74fd62
+        ret = sysdb_get_certmap(dom, dom->sysdb, &certmaps, &user_name_hint);
74fd62
+        if (ret != EOK) {
74fd62
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_certmap failed.\n");
74fd62
+            return ret;
74fd62
+        }
74fd62
 
74fd62
-    dom->user_name_hint = user_name_hint;
74fd62
-    talloc_free(dom->certmaps);
74fd62
-    dom->certmaps = certmaps;
74fd62
+        dom->user_name_hint = user_name_hint;
74fd62
+        talloc_free(dom->certmaps);
74fd62
+        dom->certmaps = certmaps;
74fd62
+    }
74fd62
 
74fd62
-    ret = p11_refresh_certmap_ctx(pctx, dom->certmaps);
74fd62
+    ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains);
74fd62
     if (ret != EOK) {
74fd62
         DEBUG(SSSDBG_OP_FAILURE, "p11_refresh_certmap_ctx failed.\n");
74fd62
         return ret;
74fd62
diff --git a/src/tests/cmocka/test_certmap.c b/src/tests/cmocka/test_certmap.c
74fd62
index 3091e1abe..c882202a0 100644
74fd62
--- a/src/tests/cmocka/test_certmap.c
74fd62
+++ b/src/tests/cmocka/test_certmap.c
74fd62
@@ -46,8 +46,10 @@
74fd62
 
74fd62
 #ifdef HAVE_TEST_CA
74fd62
 #include "tests/test_CA/SSSD_test_cert_x509_0003.h"
74fd62
+#include "tests/test_CA/SSSD_test_cert_x509_0004.h"
74fd62
 #else
74fd62
 #define SSSD_TEST_CERT_0003 ""
74fd62
+#define SSSD_TEST_CERT_0004 ""
74fd62
 #endif
74fd62
 
74fd62
 struct priv_sss_debug {
74fd62
@@ -960,6 +962,48 @@ void test_sss_cert_get_content_test_cert_0003(void **state)
74fd62
     talloc_free(content);
74fd62
 }
74fd62
 
74fd62
+void test_sss_cert_get_content_test_cert_0004(void **state)
74fd62
+{
74fd62
+    int ret;
74fd62
+    uint8_t *der;
74fd62
+    size_t der_size;
74fd62
+    struct sss_cert_content *content;
74fd62
+
74fd62
+    der = sss_base64_decode(NULL, SSSD_TEST_CERT_0004, &der_size);
74fd62
+    assert_non_null(der);
74fd62
+
74fd62
+    ret = sss_cert_get_content(NULL, der, der_size, &content);
74fd62
+    assert_int_equal(ret, 0);
74fd62
+    assert_non_null(content);
74fd62
+    assert_non_null(content->issuer_str);
74fd62
+    assert_string_equal(content->issuer_str,
74fd62
+                        "CN=SSSD test CA,OU=SSSD test,O=SSSD");
74fd62
+
74fd62
+    assert_non_null(content->issuer_rdn_list);
74fd62
+    assert_string_equal(content->issuer_rdn_list[0], "O=SSSD");
74fd62
+    assert_string_equal(content->issuer_rdn_list[1], "OU=SSSD test");
74fd62
+    assert_string_equal(content->issuer_rdn_list[2], "CN=SSSD test CA");
74fd62
+    assert_null(content->issuer_rdn_list[3]);
74fd62
+
74fd62
+    assert_non_null(content->subject_str);
74fd62
+    assert_string_equal(content->subject_str,
74fd62
+                        "CN=SSSD test cert 0004,OU=SSSD test,O=SSSD");
74fd62
+
74fd62
+    assert_non_null(content->subject_rdn_list);
74fd62
+    assert_string_equal(content->issuer_rdn_list[0], "O=SSSD");
74fd62
+    assert_string_equal(content->issuer_rdn_list[1], "OU=SSSD test");
74fd62
+    assert_string_equal(content->subject_rdn_list[2], "CN=SSSD test cert 0004");
74fd62
+    assert_null(content->subject_rdn_list[3]);
74fd62
+
74fd62
+    assert_int_equal(content->key_usage, UINT32_MAX);
74fd62
+
74fd62
+    assert_non_null(content->extended_key_usage_oids);
74fd62
+    assert_null(content->extended_key_usage_oids[0]);
74fd62
+
74fd62
+    assert_null(content->san_list);
74fd62
+
74fd62
+    talloc_free(content);
74fd62
+}
74fd62
 
74fd62
 static void test_sss_certmap_match_cert(void **state)
74fd62
 {
74fd62
@@ -1572,6 +1616,7 @@ int main(int argc, const char *argv[])
74fd62
         cmocka_unit_test(test_sss_cert_get_content_2),
74fd62
 #ifdef HAVE_TEST_CA
74fd62
         cmocka_unit_test(test_sss_cert_get_content_test_cert_0003),
74fd62
+        cmocka_unit_test(test_sss_cert_get_content_test_cert_0004),
74fd62
 #endif
74fd62
         cmocka_unit_test(test_sss_certmap_match_cert),
74fd62
         cmocka_unit_test(test_sss_certmap_add_mapping_rule),
74fd62
diff --git a/src/tests/cmocka/test_config_check.c b/src/tests/cmocka/test_config_check.c
74fd62
index a2958de63..f1fdbc8eb 100644
74fd62
--- a/src/tests/cmocka/test_config_check.c
74fd62
+++ b/src/tests/cmocka/test_config_check.c
74fd62
@@ -213,6 +213,18 @@ void config_check_test_bad_subdom_option_name(void **state)
74fd62
     config_check_test_common(cfg_str, 1, expected_errors);
74fd62
 }
74fd62
 
74fd62
+void config_check_test_bad_certmap_option_name(void **state)
74fd62
+{
74fd62
+    char cfg_str[] = "[certmap/files/testuser]\n"
74fd62
+                     "debug_level = 10\n";
74fd62
+    const char *expected_errors[] = {
74fd62
+        "[rule/allowed_certmap_options]: Attribute 'debug_level' is not "
74fd62
+        "allowed in section 'certmap/files/testuser'. Check for typos.",
74fd62
+    };
74fd62
+
74fd62
+    config_check_test_common(cfg_str, 1, expected_errors);
74fd62
+}
74fd62
+
74fd62
 void config_check_test_good_sections(void **state)
74fd62
 {
74fd62
     char cfg_str[] = "[sssd]\n"
74fd62
@@ -225,7 +237,8 @@ void config_check_test_good_sections(void **state)
74fd62
                      "[secrets/users/1000]\n"
74fd62
                      "[ssh]\n"
74fd62
                      "[ifp]\n"
74fd62
-                     "[pac]\n";
74fd62
+                     "[pac]\n"
74fd62
+                     "[certmap/files/testuser]\n";
74fd62
     const char *expected_errors[] = { NULL };
74fd62
 
74fd62
     config_check_test_common(cfg_str, 0, expected_errors);
74fd62
@@ -272,6 +285,7 @@ int main(int argc, const char *argv[])
74fd62
         cmocka_unit_test(config_check_test_bad_ifp_option_name),
74fd62
         cmocka_unit_test(config_check_test_bad_appdomain_option_name),
74fd62
         cmocka_unit_test(config_check_test_bad_subdom_option_name),
74fd62
+        cmocka_unit_test(config_check_test_bad_certmap_option_name),
74fd62
         cmocka_unit_test(config_check_test_good_sections),
74fd62
         cmocka_unit_test(config_check_test_inherit_from_in_normal_dom),
74fd62
         cmocka_unit_test(config_check_test_inherit_from_in_app_dom),
74fd62
diff --git a/src/tests/intg/test_pam_responder.py b/src/tests/intg/test_pam_responder.py
74fd62
index 7e5828dde..e97bd409b 100644
74fd62
--- a/src/tests/intg/test_pam_responder.py
74fd62
+++ b/src/tests/intg/test_pam_responder.py
74fd62
@@ -27,12 +27,9 @@ import signal
74fd62
 import errno
74fd62
 import subprocess
74fd62
 import time
74fd62
-import pytest
74fd62
-
74fd62
-import config
74fd62
 import shutil
74fd62
-from util import unindent
74fd62
 
74fd62
+import config
74fd62
 import intg.ds_openldap
74fd62
 
74fd62
 import pytest
74fd62
@@ -109,24 +106,35 @@ def format_basic_conf(ldap_conn):
74fd62
     """).format(**locals())
74fd62
 
74fd62
 
74fd62
-def format_pam_cert_auth_conf():
74fd62
+USER1 = dict(name='user1', passwd='x', uid=10001, gid=20001,
74fd62
+             gecos='User for tests',
74fd62
+             dir='/home/user1',
74fd62
+             shell='/bin/bash')
74fd62
+
74fd62
+
74fd62
+def format_pam_cert_auth_conf(config):
74fd62
     """Format a basic SSSD configuration"""
74fd62
     return unindent("""\
74fd62
         [sssd]
74fd62
+        debug_level = 10
74fd62
         domains = auth_only
74fd62
-        services = pam
74fd62
+        services = pam, nss
74fd62
 
74fd62
         [nss]
74fd62
+        debug_level = 10
74fd62
 
74fd62
         [pam]
74fd62
         pam_cert_auth = True
74fd62
+        pam_p11_allowed_services = +pam_sss_service
74fd62
+        pam_cert_db_path = {config.PAM_CERT_DB_PATH}
74fd62
         debug_level = 10
74fd62
 
74fd62
         [domain/auth_only]
74fd62
-        id_provider = ldap
74fd62
-        auth_provider = ldap
74fd62
-        chpass_provider = ldap
74fd62
-        access_provider = ldap
74fd62
+        debug_level = 10
74fd62
+        id_provider = files
74fd62
+
74fd62
+        [certmap/auth_only/user1]
74fd62
+        matchrule = <SUBJECT>.*CN=SSSD test cert 0001.*
74fd62
     """).format(**locals())
74fd62
 
74fd62
 
74fd62
@@ -193,12 +201,42 @@ def create_sssd_fixture(request):
74fd62
     request.addfinalizer(cleanup_sssd_process)
74fd62
 
74fd62
 
74fd62
+def create_nssdb():
74fd62
+    os.mkdir(config.SYSCONFDIR + "/pki")
74fd62
+    os.mkdir(config.SYSCONFDIR + "/pki/nssdb")
74fd62
+    if subprocess.call(["certutil", "-N", "-d",
74fd62
+                        "sql:" + config.SYSCONFDIR + "/pki/nssdb/",
74fd62
+                        "--empty-password"]) != 0:
74fd62
+        raise Exception("certutil failed")
74fd62
+
74fd62
+    pkcs11_txt = open(config.SYSCONFDIR + "/pki/nssdb/pkcs11.txt", "w")
74fd62
+    pkcs11_txt.write("library=libsoftokn3.so\nname=soft\n" +
74fd62
+                     "parameters=configdir='sql:" + config.ABS_BUILDDIR +
74fd62
+                     "/../test_CA/p11_nssdb' " +
74fd62
+                     "dbSlotDescription='SSSD Test Slot' " +
74fd62
+                     "dbTokenDescription='SSSD Test Token' " +
74fd62
+                     "secmod='secmod.db' flags=readOnly)\n\n")
74fd62
+    pkcs11_txt.close()
74fd62
+
74fd62
+
74fd62
+def cleanup_nssdb():
74fd62
+    shutil.rmtree(config.SYSCONFDIR + "/pki")
74fd62
+
74fd62
+
74fd62
+def create_nssdb_fixture(request):
74fd62
+    create_nssdb()
74fd62
+    request.addfinalizer(cleanup_nssdb)
74fd62
+
74fd62
+
74fd62
 @pytest.fixture
74fd62
-def simple_pam_cert_auth(request):
74fd62
+def simple_pam_cert_auth(request, passwd_ops_setup):
74fd62
     """Setup SSSD with pam_cert_auth=True"""
74fd62
-    conf = format_pam_cert_auth_conf()
74fd62
+    config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH']
74fd62
+    conf = format_pam_cert_auth_conf(config)
74fd62
     create_conf_fixture(request, conf)
74fd62
     create_sssd_fixture(request)
74fd62
+    create_nssdb_fixture(request)
74fd62
+    passwd_ops_setup.useradd(**USER1)
74fd62
     return None
74fd62
 
74fd62
 
74fd62
@@ -281,3 +319,50 @@ def env_for_sssctl(request):
74fd62
     env_for_sssctl['LD_PRELOAD'] += ':' + os.environ['PAM_WRAPPER_PATH']
74fd62
 
74fd62
     return env_for_sssctl
74fd62
+
74fd62
+
74fd62
+def test_sc_auth_wrong_pin(simple_pam_cert_auth, env_for_sssctl):
74fd62
+
74fd62
+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
74fd62
+                               "--action=auth", "--service=pam_sss_service"],
74fd62
+                              universal_newlines=True,
74fd62
+                              env=env_for_sssctl, stdin=subprocess.PIPE,
74fd62
+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
74fd62
+
74fd62
+    try:
74fd62
+        out, err = sssctl.communicate(input="111")
74fd62
+    except:
74fd62
+        sssctl.kill()
74fd62
+        out, err = sssctl.communicate()
74fd62
+
74fd62
+    sssctl.stdin.close()
74fd62
+    sssctl.stdout.close()
74fd62
+
74fd62
+    if sssctl.wait() != 0:
74fd62
+        raise Exception("sssctl failed")
74fd62
+
74fd62
+    assert err.find("pam_authenticate for user [user1]: " +
74fd62
+                    "Authentication failure") != -1
74fd62
+
74fd62
+
74fd62
+def test_sc_auth(simple_pam_cert_auth, env_for_sssctl):
74fd62
+
74fd62
+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
74fd62
+                               "--action=auth", "--service=pam_sss_service"],
74fd62
+                              universal_newlines=True,
74fd62
+                              env=env_for_sssctl, stdin=subprocess.PIPE,
74fd62
+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
74fd62
+
74fd62
+    try:
74fd62
+        out, err = sssctl.communicate(input="123456")
74fd62
+    except:
74fd62
+        sssctl.kill()
74fd62
+        out, err = sssctl.communicate()
74fd62
+
74fd62
+    sssctl.stdin.close()
74fd62
+    sssctl.stdout.close()
74fd62
+
74fd62
+    if sssctl.wait() != 0:
74fd62
+        raise Exception("sssctl failed")
74fd62
+
74fd62
+    assert err.find("pam_authenticate for user [user1]: Success") != -1
74fd62
diff --git a/src/tests/test_CA/Makefile.am b/src/tests/test_CA/Makefile.am
74fd62
index 0c7099390..19772d150 100644
74fd62
--- a/src/tests/test_CA/Makefile.am
74fd62
+++ b/src/tests/test_CA/Makefile.am
74fd62
@@ -4,9 +4,11 @@ dist_noinst_DATA = \
74fd62
     SSSD_test_cert_0001.config \
74fd62
     SSSD_test_cert_0002.config \
74fd62
     SSSD_test_cert_0003.config \
74fd62
+    SSSD_test_cert_0004.config \
74fd62
     SSSD_test_cert_key_0001.pem \
74fd62
     SSSD_test_cert_key_0002.pem \
74fd62
     SSSD_test_cert_key_0003.pem \
74fd62
+    SSSD_test_cert_key_0004.pem \
74fd62
     $(NULL)
74fd62
 
74fd62
 openssl_ca_config = $(srcdir)/SSSD_test_CA.config
74fd62
@@ -33,14 +35,18 @@ endif
74fd62
 ca_all: clean serial SSSD_test_CA.pem $(certs) $(certs_h) $(pubkeys) $(pubkeys_h) $(pkcs12) $(extra)
74fd62
 
74fd62
 $(pwdfile):
74fd62
-	@echo "12345678" > $@
74fd62
+	@echo "123456" > $@
74fd62
 
74fd62
 SSSD_test_CA.pem: $(openssl_ca_key) $(openssl_ca_config) serial
74fd62
 	$(OPENSSL) req -batch -config ${openssl_ca_config} -x509 -new -nodes -key $< -sha256 -days 1024 -set_serial 0 -extensions v3_ca -out $@
74fd62
 
74fd62
 
74fd62
 SSSD_test_cert_req_%.pem: $(srcdir)/SSSD_test_cert_key_%.pem $(srcdir)/SSSD_test_cert_%.config
74fd62
-	$(OPENSSL) req -new -nodes -key $< -reqexts req_exts -config $(srcdir)/SSSD_test_cert_$*.config -out $@
74fd62
+	if [ $(shell grep -c req_exts $(srcdir)/SSSD_test_cert_$*.config) -eq 0 ]; then \
74fd62
+		$(OPENSSL) req -new -nodes -key $< -config $(srcdir)/SSSD_test_cert_$*.config -out $@ ; \
74fd62
+	else \
74fd62
+		$(OPENSSL) req -new -nodes -key $< -reqexts req_exts -config $(srcdir)/SSSD_test_cert_$*.config -out $@ ; \
74fd62
+	fi
74fd62
 
74fd62
 SSSD_test_cert_x509_%.pem: SSSD_test_cert_req_%.pem $(openssl_ca_config) SSSD_test_CA.pem
74fd62
 	$(OPENSSL) ca -config ${openssl_ca_config} -batch -notext -keyfile $(openssl_ca_key) -in $< -days 200 -extensions usr_cert -out $@
74fd62
@@ -65,18 +71,18 @@ SSSD_test_cert_pubsshkey_%.h: SSSD_test_cert_pubsshkey_%.pub
74fd62
 # - src/tests/cmocka/test_pam_srv.c
74fd62
 p11_nssdb: SSSD_test_cert_pkcs12_0001.pem SSSD_test_CA.pem $(pwdfile)
74fd62
 	mkdir $@
74fd62
-	$(CERTUTIL) -d sql:./$@ -N --empty-password
74fd62
-	$(CERTUTIL) -d sql:./$@ -A -n 'SSSD test CA' -t CT,CT,CT -a -i SSSD_test_CA.pem
74fd62
-	$(PK12UTIL) -d sql:./$@ -i SSSD_test_cert_pkcs12_0001.pem -w $(pwdfile)
74fd62
+	$(CERTUTIL) -d sql:./$@ -N -f $(pwdfile)
74fd62
+	$(CERTUTIL) -d sql:./$@ -A -n 'SSSD test CA' -t CT,CT,CT -a -i SSSD_test_CA.pem -f $(pwdfile)
74fd62
+	$(PK12UTIL) -d sql:./$@ -i SSSD_test_cert_pkcs12_0001.pem -w $(pwdfile) -k $(pwdfile)
74fd62
 
74fd62
 # This nss db is used in
74fd62
 # - src/tests/cmocka/test_pam_srv.c
74fd62
 p11_nssdb_2certs: SSSD_test_cert_pkcs12_0001.pem SSSD_test_cert_pkcs12_0002.pem SSSD_test_CA.pem $(pwdfile)
74fd62
 	mkdir $@
74fd62
-	$(CERTUTIL) -d sql:./$@ -N --empty-password
74fd62
-	$(CERTUTIL) -d sql:./$@ -A -n 'SSSD test CA' -t CT,CT,CT -a -i SSSD_test_CA.pem
74fd62
-	$(PK12UTIL) -d sql:./$@ p11_nssdb -i SSSD_test_cert_pkcs12_0001.pem -w $(pwdfile)
74fd62
-	$(PK12UTIL) -d sql:./$@ p11_nssdb -i SSSD_test_cert_pkcs12_0002.pem -w $(pwdfile)
74fd62
+	$(CERTUTIL) -d sql:./$@ -N -f $(pwdfile)
74fd62
+	$(CERTUTIL) -d sql:./$@ -A -n 'SSSD test CA' -t CT,CT,CT -a -i SSSD_test_CA.pem -f $(pwdfile)
74fd62
+	$(PK12UTIL) -d sql:./$@ -i SSSD_test_cert_pkcs12_0001.pem -w $(pwdfile) -k $(pwdfile)
74fd62
+	$(PK12UTIL) -d sql:./$@ -i SSSD_test_cert_pkcs12_0002.pem -w $(pwdfile) -k $(pwdfile)
74fd62
 
74fd62
 # The softhsm2 PKCS#11 setups are used in
74fd62
 # - src/tests/cmocka/test_pam_srv.c
74fd62
diff --git a/src/tests/test_CA/SSSD_test_cert_0004.config b/src/tests/test_CA/SSSD_test_cert_0004.config
74fd62
new file mode 100644
74fd62
index 000000000..cb61b43ce
74fd62
--- /dev/null
74fd62
+++ b/src/tests/test_CA/SSSD_test_cert_0004.config
74fd62
@@ -0,0 +1,11 @@
74fd62
+# This certificate is used in
74fd62
+# - test_sss_cert_get_content_test_cert_0004
74fd62
+# as an example for a simple certificate without KU, EKU and SAN extensions
74fd62
+[ req ]
74fd62
+distinguished_name = req_distinguished_name
74fd62
+prompt = no
74fd62
+
74fd62
+[ req_distinguished_name ]
74fd62
+O = SSSD
74fd62
+OU = SSSD test
74fd62
+CN = SSSD test cert 0004
74fd62
diff --git a/src/tests/test_CA/SSSD_test_cert_key_0004.pem b/src/tests/test_CA/SSSD_test_cert_key_0004.pem
74fd62
new file mode 100644
74fd62
index 000000000..e7e1b1de7
74fd62
--- /dev/null
74fd62
+++ b/src/tests/test_CA/SSSD_test_cert_key_0004.pem
74fd62
@@ -0,0 +1,28 @@
74fd62
+-----BEGIN PRIVATE KEY-----
74fd62
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCdue/OaH/8xyzm
74fd62
+PUXFJeVJe0GOLZv3Pv/wPuIlNjAU1JNSDQUUKBlv7SOJr7KZ+4se6RyTU22G0KMN
74fd62
+0qswY5hlpOtCbRlH2fp5zaYakDVbAv00UBvllPuLetQA9hjCxvz3DZLfLC/N954N
74fd62
+ZKJIrO2fqTDvJwKqhw7gvp4p1vZcpAcsDf/AYzPgw1oX3yZyzQhfQwQ5Gu3U0Fwc
74fd62
+nQL/l++mDFD2faDBfn9CFu7hPHKMQvjITsK/RwuFqZa1BzU80x0iyRMhYyDuUDWD
74fd62
+2tDgzgt4qlMIHJb0ACHuSZFNIiqCF2xkM63PP3is2w7DUpRSu26FR4JacoKq7v5g
74fd62
+yhtw9y9HAgMBAAECggEAVpNKKy03G4QkhBib5HRBoAz01dr5IkTFbZTGwxA0Yiqw
74fd62
+1rfo0sCT/djXyerUCSuGmKfyFHgVxYteBOdfKgdxDlHxBJwn5UWj9BnKlAgWEWfZ
74fd62
+nk5eka0uSchY+FIdE0Twc5dSyAdUEiVZ7xYO8f9hy2KuRodOMlZB92EKJgMlZYGS
74fd62
+/hYOfZYmz3c4LFWO+UEiXyKKjENtnp5CpOw+Vcrwlu77PbFiT4Y12dOOwDRP4a/a
74fd62
+ddXQBUaApOMDBA6gpB4jaysq5EBnrLTL5fzHNpATVKFnAL7icPuIfefjU2kxQMoo
74fd62
+siUL7RzZnLlx0mN37DIzTv4uGltvGzzqhkIA5X/TsQKBgQDNBt3+dih7YbDt/4cC
74fd62
+HtuApUAbwYDYhETzU8Zt+WRiFZdOgBcm/bacxOqBWGJ1WCYnegPYmk4WVThH1zrF
74fd62
+Pr2EN2sOn2KJzQlLIOR7hvtTXgLx1hqc9XVBq/8JKhvCPfk/RoCjt+GmkoLHdrWI
74fd62
+w1kd2milRcFs09UCV8LGa/vYSQKBgQDE8JUXD8x77IP/CBXLBmFq6tSwYkRWh4jC
74fd62
+l8HB75VWXrknzgjv4Iqx4FEm2T0Mp0QFZLF6WCoclUcsGiCTz7jm20eoRL+5dX1d
74fd62
+yASi00GSpS1p2Q9eTTU4FHVg1nD1B5F1kQB8uqBj0oSjeQLLPngaIftxTGNrkw3J
74fd62
+4mk5kVdrDwKBgF0iA3F1pwn05HQYIPHbpoYXirmQ+sBfxRprMbX/FZRgjmzATsQN
74fd62
+eAhagtPinEcFlb9U865O2a3XZEtt/2peB6Spr93ilNZX5yLTfDaIqF3EVL4aLdii
74fd62
+v3LneGBnWliv4irWEdVM0Bnkb7e/utK3OiIPdn2s5CJVT2tTBk0v/CTRAoGAIe04
74fd62
+IeLs3SRfkN25s2IEAkE2JrSnBSkQHEW8cUZuuZRT3VGXJIvQGNiF4mVmKPnfs/Ym
74fd62
+xObPSmFFA4n0tsIAHnUEIS7GwJJG6JL+iXZPQ44FBskH5rzyQBj2J5qJlwyYuGIk
74fd62
+bVhRLSElDGxaWN0IH6hfAqOgNPX+WBsS+YHaR20CgYAVUwTRA9kQgPZJfg+mepFG
74fd62
+zw9Tx7/TSwILZDlL0AU/i12xn0RA7sweLW8cPEDx1OnTbv+/pqSZ46eeZDzTrlu7
74fd62
+ASy844law96NdhpKuTyz/jEl6aj0RLp1wzQZLSQkV0nv3f2Qlknhz83uShhxmxJv
74fd62
+FqS4fShRFJNoQDwEUvE7ZA==
74fd62
+-----END PRIVATE KEY-----
74fd62
-- 
74fd62
2.21.3
74fd62