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