From 9f2ebfc70a98480ed4c6f0374fd48e533ca63e52 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Apr 10 2018 05:42:07 +0000 Subject: import sssd-1.16.0-19.el7 --- diff --git a/.gitignore b/.gitignore index bae0ba3..5a65ef2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -SOURCES/sssd-1.15.2.tar.gz +SOURCES/cert9.db +SOURCES/key4.db +SOURCES/sssd-1.16.0.tar.gz diff --git a/.sssd.metadata b/.sssd.metadata index bc1073e..d8d858c 100644 --- a/.sssd.metadata +++ b/.sssd.metadata @@ -1 +1,3 @@ -f94298ac05169cdf5a9082c3aba9f6a18513720a SOURCES/sssd-1.15.2.tar.gz +52bc755199e2c92ae81a8f93a7c6f2e46715b771 SOURCES/cert9.db +52770a7b7564ef8e0508ae60f5dc238b78e70b99 SOURCES/key4.db +fff74b3798e163a0fe311bdfc4588524afe6dd87 SOURCES/sssd-1.16.0.tar.gz diff --git a/SOURCES/0001-MAN-Mention-sssd-secrets-in-SEE-ALSO-section.patch b/SOURCES/0001-MAN-Mention-sssd-secrets-in-SEE-ALSO-section.patch deleted file mode 100644 index e405016..0000000 --- a/SOURCES/0001-MAN-Mention-sssd-secrets-in-SEE-ALSO-section.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 1bf225166db64e81fe94cbee0fd3b1dc124717f4 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Tue, 21 Mar 2017 12:27:16 +0100 -Subject: [PATCH 01/15] MAN: Mention sssd-secrets in "SEE ALSO" section -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: -https://pagure.io/SSSD/sssd/issue/3344 - -Reviewed-by: Fabiano Fidêncio ---- - src/man/include/seealso.xml | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/src/man/include/seealso.xml b/src/man/include/seealso.xml -index 25b421748fb19881552de8b6384af2c794063e11..2e9c646c475887bce3612472975ade375edbd819 100644 ---- a/src/man/include/seealso.xml -+++ b/src/man/include/seealso.xml -@@ -28,6 +28,12 @@ - 5 - , - -+ -+ -+ sssd-secrets -+ 5 -+ , -+ - - sss_cache8 - , --- -2.9.3 - diff --git a/SOURCES/0001-NSS-Move-memcache-setup-to-separate-function.patch b/SOURCES/0001-NSS-Move-memcache-setup-to-separate-function.patch new file mode 100644 index 0000000..0d2e9f4 --- /dev/null +++ b/SOURCES/0001-NSS-Move-memcache-setup-to-separate-function.patch @@ -0,0 +1,143 @@ +From 82d52dbfd51330cd1fda4734b9e901431e137211 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Thu, 19 Oct 2017 16:39:27 +0200 +Subject: [PATCH 01/21] NSS: Move memcache setup to separate function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: +https://pagure.io/SSSD/sssd/issue/3496 + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit 878b0d42aca5839fdc1d97a68ce181e280f1ed7b) +--- + src/responder/nss/nsssrv.c | 91 ++++++++++++++++++++++++++-------------------- + 1 file changed, 51 insertions(+), 40 deletions(-) + +diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c +index d67b9fac8d770d113560e41b259e2d5edd219343..21dd198226da6cf14d7db4941806048662970fed 100644 +--- a/src/responder/nss/nsssrv.c ++++ b/src/responder/nss/nsssrv.c +@@ -252,6 +252,56 @@ static void nss_dp_reconnect_init(struct sbus_connection *conn, + /* nss_shutdown(rctx); */ + } + ++static int setup_memcaches(struct nss_ctx *nctx) ++{ ++ int ret; ++ int memcache_timeout; ++ ++ /* Remove the CLEAR_MC_FLAG file if exists. */ ++ ret = unlink(SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG); ++ if (ret != 0 && errno != ENOENT) { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to unlink file [%s]. This can cause memory cache to " ++ "be purged when next log rotation is requested. %d: %s\n", ++ SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG, ret, strerror(ret)); ++ } ++ ++ ret = confdb_get_int(nctx->rctx->cdb, ++ CONFDB_NSS_CONF_ENTRY, ++ CONFDB_MEMCACHE_TIMEOUT, ++ 300, &memcache_timeout); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to get 'memcache_timeout' option from confdb.\n"); ++ return ret; ++ } ++ ++ /* TODO: read cache sizes from configuration */ ++ ret = sss_mmap_cache_init(nctx, "passwd", SSS_MC_PASSWD, ++ SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout, ++ &nctx->pwd_mc_ctx); ++ if (ret) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "passwd mmap cache is DISABLED\n"); ++ } ++ ++ ret = sss_mmap_cache_init(nctx, "group", SSS_MC_GROUP, ++ SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout, ++ &nctx->grp_mc_ctx); ++ if (ret) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "group mmap cache is DISABLED\n"); ++ } ++ ++ ret = sss_mmap_cache_init(nctx, "initgroups", SSS_MC_INITGROUPS, ++ SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout, ++ &nctx->initgr_mc_ctx); ++ if (ret) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "initgroups mmap cache is DISABLED\n"); ++ } ++ ++ return EOK; ++} ++ + int nss_process_init(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct confdb_ctx *cdb) +@@ -260,7 +310,6 @@ int nss_process_init(TALLOC_CTX *mem_ctx, + struct sss_cmd_table *nss_cmds; + struct be_conn *iter; + struct nss_ctx *nctx; +- int memcache_timeout; + int ret, max_retries; + enum idmap_error_code err; + int fd_limit; +@@ -330,49 +379,11 @@ int nss_process_init(TALLOC_CTX *mem_ctx, + goto fail; + } + +- /* create mmap caches */ +- /* Remove the CLEAR_MC_FLAG file if exists. */ +- ret = unlink(SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG); +- if (ret != 0 && errno != ENOENT) { +- ret = errno; +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to unlink file [%s]. This can cause memory cache to " +- "be purged when next log rotation is requested. %d: %s\n", +- SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG, ret, strerror(ret)); +- } +- +- ret = confdb_get_int(nctx->rctx->cdb, +- CONFDB_NSS_CONF_ENTRY, +- CONFDB_MEMCACHE_TIMEOUT, +- 300, &memcache_timeout); ++ ret = setup_memcaches(nctx); + if (ret != EOK) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Failed to get 'memcache_timeout' option from confdb.\n"); + goto fail; + } + +- /* TODO: read cache sizes from configuration */ +- ret = sss_mmap_cache_init(nctx, "passwd", SSS_MC_PASSWD, +- SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout, +- &nctx->pwd_mc_ctx); +- if (ret) { +- DEBUG(SSSDBG_CRIT_FAILURE, "passwd mmap cache is DISABLED\n"); +- } +- +- ret = sss_mmap_cache_init(nctx, "group", SSS_MC_GROUP, +- SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout, +- &nctx->grp_mc_ctx); +- if (ret) { +- DEBUG(SSSDBG_CRIT_FAILURE, "group mmap cache is DISABLED\n"); +- } +- +- ret = sss_mmap_cache_init(nctx, "initgroups", SSS_MC_INITGROUPS, +- SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout, +- &nctx->initgr_mc_ctx); +- if (ret) { +- DEBUG(SSSDBG_CRIT_FAILURE, "initgroups mmap cache is DISABLED\n"); +- } +- + /* Set up file descriptor limits */ + ret = confdb_get_int(nctx->rctx->cdb, + CONFDB_NSS_CONF_ENTRY, +-- +2.13.5 + diff --git a/SOURCES/0002-NSS-Specify-memcache_timeout-0-semantics.patch b/SOURCES/0002-NSS-Specify-memcache_timeout-0-semantics.patch new file mode 100644 index 0000000..6fb4dca --- /dev/null +++ b/SOURCES/0002-NSS-Specify-memcache_timeout-0-semantics.patch @@ -0,0 +1,118 @@ +From f23a358915cfa27669c019fe0df21cce8851459e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Thu, 19 Oct 2017 16:42:19 +0200 +Subject: [PATCH 02/21] NSS: Specify memcache_timeout=0 semantics +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With this patch the memcache files will not be created when +memcache_timeout is set to zero. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3496 + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit ffe29e570a9e885c2f0061c34bb6be2bbd6ab9e4) +--- + src/responder/nss/nsssrv.c | 6 ++++ + src/tests/intg/test_memory_cache.py | 59 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 65 insertions(+) + +diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c +index 21dd198226da6cf14d7db4941806048662970fed..32bfcd69bbb9b35e9932b70a826c4f99ab6a07f3 100644 +--- a/src/responder/nss/nsssrv.c ++++ b/src/responder/nss/nsssrv.c +@@ -277,6 +277,12 @@ static int setup_memcaches(struct nss_ctx *nctx) + return ret; + } + ++ if (memcache_timeout == 0) { ++ DEBUG(SSSDBG_CONF_SETTINGS, ++ "Fast in-memory cache will not be initialized."); ++ return EOK; ++ } ++ + /* TODO: read cache sizes from configuration */ + ret = sss_mmap_cache_init(nctx, "passwd", SSS_MC_PASSWD, + SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout, +diff --git a/src/tests/intg/test_memory_cache.py b/src/tests/intg/test_memory_cache.py +index c7ba72490174a6ec2257f9d317ac96b35c674779..cac9feb00459957650c5e455db1b2712e17ccd68 100644 +--- a/src/tests/intg/test_memory_cache.py ++++ b/src/tests/intg/test_memory_cache.py +@@ -207,6 +207,32 @@ def fqname_case_insensitive_rfc2307(request, ldap_conn): + return None + + ++@pytest.fixture ++def zero_timeout_rfc2307(request, ldap_conn): ++ load_data_to_ldap(request, ldap_conn) ++ ++ conf = unindent("""\ ++ [sssd] ++ domains = LDAP ++ services = nss ++ ++ [nss] ++ memcache_timeout = 0 ++ ++ [domain/LDAP] ++ ldap_auth_disable_tls_never_use_in_production = true ++ ldap_schema = rfc2307 ++ id_provider = ldap ++ auth_provider = ldap ++ sudo_provider = ldap ++ ldap_uri = {ldap_conn.ds_inst.ldap_url} ++ ldap_search_base = {ldap_conn.ds_inst.base_dn} ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ + def test_getpwnam(ldap_conn, sanity_rfc2307): + ent.assert_passwd_by_name( + 'user1', +@@ -778,3 +804,36 @@ def test_removed_mc(ldap_conn, sanity_rfc2307): + grp.getgrnam('group1') + with pytest.raises(KeyError): + grp.getgrgid(2001) ++ ++ ++def test_mc_zero_timeout(ldap_conn, zero_timeout_rfc2307): ++ """ ++ Test that the memory cache is not created at all with memcache_timeout=0 ++ """ ++ # No memory cache files must be created ++ assert len(os.listdir(config.MCACHE_PATH)) == 0 ++ ++ ent.assert_passwd_by_name( ++ 'user1', ++ dict(name='user1', passwd='*', uid=1001, gid=2001, ++ gecos='1001', shell='/bin/bash')) ++ ent.assert_passwd_by_uid( ++ 1001, ++ dict(name='user1', passwd='*', uid=1001, gid=2001, ++ gecos='1001', shell='/bin/bash')) ++ ++ ent.assert_group_by_name("group1", dict(name="group1", gid=2001)) ++ ent.assert_group_by_gid(2001, dict(name="group1", gid=2001)) ++ stop_sssd() ++ ++ # sssd is stopped; so the memory cache should not be used ++ # in long living clients (py.test in this case) ++ with pytest.raises(KeyError): ++ pwd.getpwnam('user1') ++ with pytest.raises(KeyError): ++ pwd.getpwuid(1001) ++ ++ with pytest.raises(KeyError): ++ grp.getgrnam('group1') ++ with pytest.raises(KeyError): ++ grp.getgrgid(2001) +-- +2.13.5 + diff --git a/SOURCES/0002-split_on_separator-move-to-a-separate-file.patch b/SOURCES/0002-split_on_separator-move-to-a-separate-file.patch deleted file mode 100644 index 24961c7..0000000 --- a/SOURCES/0002-split_on_separator-move-to-a-separate-file.patch +++ /dev/null @@ -1,369 +0,0 @@ -From 4f98b36562fb02f95c9af7af6fde548334ce9c34 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 8 Feb 2017 14:28:28 +0100 -Subject: [PATCH 02/15] split_on_separator: move to a separate file -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -To be able to include split_on_separator() without additional -dependencies (only talloc), it is moved into a separate file. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - Makefile.am | 30 ++++++++++--- - src/util/util.c | 93 ---------------------------------------- - src/util/util_ext.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 144 insertions(+), 100 deletions(-) - create mode 100644 src/util/util_ext.c - -diff --git a/Makefile.am b/Makefile.am -index 45b04de2638a745a189c0b4e5794ccd29913b10d..6dae4f2dd7f2dee501add82c7ab4f15fcbcc59ac 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -987,6 +987,7 @@ libsss_util_la_SOURCES = \ - src/sbus/sssd_dbus_common_signals.c \ - src/sbus/sssd_dbus_utils.c \ - src/util/util.c \ -+ src/util/util_ext.c \ - src/util/memory.c \ - src/util/safe-format-string.c \ - src/util/server.c \ -@@ -2355,19 +2356,23 @@ test_authtok_SOURCES = \ - src/tests/cmocka/test_authtok.c \ - src/util/authtok.c \ - src/util/authtok-utils.c \ -- src/util/util.c -+ src/util/util.c \ -+ src/util/util_ext.c \ -+ $(NULL) - test_authtok_CFLAGS = \ - $(AM_CFLAGS) \ - $(TALLOC_CFLAGS) \ - $(POPT_CFLAGS) \ -- $(DHASH_CFLAGS) -+ $(DHASH_CFLAGS) \ -+ $(NULL) - test_authtok_LDADD = \ - $(TALLOC_LIBS) \ - $(CMOCKA_LIBS) \ - $(DHASH_LIBS) \ - $(POPT_LIBS) \ - libsss_test_common.la \ -- libsss_debug.la -+ libsss_debug.la \ -+ $(NULL) - - sss_nss_idmap_tests_SOURCES = \ - src/tests/cmocka/sss_nss_idmap-tests.c -@@ -2839,6 +2844,7 @@ test_child_common_SOURCES = \ - src/util/atomic_io.c \ - src/util/util_errors.c \ - src/util/util.c \ -+ src/util/util_ext.c \ - $(NULL) - test_child_common_CFLAGS = \ - $(AM_CFLAGS) \ -@@ -3774,6 +3780,7 @@ krb5_child_SOURCES = \ - src/util/authtok.c \ - src/util/authtok-utils.c \ - src/util/util.c \ -+ src/util/util_ext.c \ - src/util/signal.c \ - src/util/strtonum.c \ - src/util/become_user.c \ -@@ -3807,6 +3814,7 @@ ldap_child_SOURCES = \ - src/util/authtok.c \ - src/util/authtok-utils.c \ - src/util/util.c \ -+ src/util/util_ext.c \ - src/util/signal.c \ - src/util/become_user.c \ - $(NULL) -@@ -3827,6 +3835,7 @@ selinux_child_SOURCES = \ - src/util/sss_semanage.c \ - src/util/atomic_io.c \ - src/util/util.c \ -+ src/util/util_ext.c \ - $(NULL) - selinux_child_CFLAGS = \ - $(AM_CFLAGS) \ -@@ -3845,6 +3854,7 @@ gpo_child_SOURCES = \ - src/providers/ad/ad_gpo_child.c \ - src/util/atomic_io.c \ - src/util/util.c \ -+ src/util/util_ext.c \ - src/util/signal.c - gpo_child_CFLAGS = \ - $(AM_CFLAGS) \ -@@ -3876,6 +3886,7 @@ p11_child_SOURCES = \ - src/p11_child/p11_child_nss.c \ - src/util/atomic_io.c \ - src/util/util.c \ -+ src/util/util_ext.c \ - $(NULL) - p11_child_CFLAGS = \ - $(AM_CFLAGS) \ -@@ -3893,16 +3904,21 @@ p11_child_LDADD = \ - - memberof_la_SOURCES = \ - src/ldb_modules/memberof.c \ -- src/util/util.c -+ src/util/util.c \ -+ src/util/util_ext.c \ -+ $(NULL) - memberof_la_CFLAGS = \ -- $(AM_CFLAGS) -+ $(AM_CFLAGS) \ -+ $(NULL) - memberof_la_LIBADD = \ - libsss_debug.la \ - $(LDB_LIBS) \ -- $(DHASH_LIBS) -+ $(DHASH_LIBS) \ -+ $(NULL) - memberof_la_LDFLAGS = \ - -avoid-version \ -- -module -+ -module \ -+ $(NULL) - - if BUILD_KRB5_LOCATOR_PLUGIN - sssd_krb5_locator_plugin_la_SOURCES = \ -diff --git a/src/util/util.c b/src/util/util.c -index a528f0c0249c33bfc3d3275250e74d5edcef2e6f..9d6202f695d516f20d648621da81a2d5e746daa5 100644 ---- a/src/util/util.c -+++ b/src/util/util.c -@@ -35,99 +35,6 @@ - int socket_activated = 0; - int dbus_activated = 0; - --int split_on_separator(TALLOC_CTX *mem_ctx, const char *str, -- const char sep, bool trim, bool skip_empty, -- char ***_list, int *size) --{ -- int ret; -- const char *substr_end = str; -- const char *substr_begin = str; -- const char *sep_pos = NULL; -- size_t substr_len; -- char **list = NULL; -- int num_strings = 0; -- TALLOC_CTX *tmp_ctx = NULL; -- -- if (str == NULL || *str == '\0' || _list == NULL) { -- return EINVAL; -- } -- -- tmp_ctx = talloc_new(NULL); -- if (tmp_ctx == NULL) { -- return ENOMEM; -- } -- -- do { -- substr_len = 0; -- -- /* If this is not the first substring, then move from the separator. */ -- if (sep_pos != NULL) { -- substr_end = sep_pos + 1; -- substr_begin = sep_pos + 1; -- } -- -- /* Find end of the first substring */ -- while (*substr_end != sep && *substr_end != '\0') { -- substr_end++; -- substr_len++; -- } -- -- sep_pos = substr_end; -- -- if (trim) { -- /* Trim leading whitespace */ -- while (isspace(*substr_begin) && substr_begin < substr_end) { -- substr_begin++; -- substr_len--; -- } -- -- /* Trim trailing whitespace */ -- while (substr_end - 1 > substr_begin && isspace(*(substr_end-1))) { -- substr_end--; -- substr_len--; -- } -- } -- -- /* Copy the substring to the output list of strings */ -- if (skip_empty == false || substr_len > 0) { -- list = talloc_realloc(tmp_ctx, list, char*, num_strings + 2); -- if (list == NULL) { -- ret = ENOMEM; -- goto done; -- } -- -- /* empty string is stored for substr_len == 0 */ -- list[num_strings] = talloc_strndup(list, substr_begin, substr_len); -- if (list[num_strings] == NULL) { -- ret = ENOMEM; -- goto done; -- } -- num_strings++; -- } -- -- } while (*sep_pos != '\0'); -- -- if (list == NULL) { -- /* No allocations were done, make space for the NULL */ -- list = talloc(tmp_ctx, char *); -- if (list == NULL) { -- ret = ENOMEM; -- goto done; -- } -- } -- list[num_strings] = NULL; -- -- if (size) { -- *size = num_strings; -- } -- -- *_list = talloc_steal(mem_ctx, list); -- ret = EOK; --done: -- talloc_free(tmp_ctx); -- return ret; --} -- - static void free_args(char **args) - { - int i; -diff --git a/src/util/util_ext.c b/src/util/util_ext.c -new file mode 100644 -index 0000000000000000000000000000000000000000..fceb8c873a26471d476b39d5d4e567c445ed8d0b ---- /dev/null -+++ b/src/util/util_ext.c -@@ -0,0 +1,121 @@ -+/* -+ SSSD helper calls - can be used by libraries for external use as well -+ -+ Authors: -+ Simo Sorce -+ -+ Copyright (C) 2017 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 -+#include -+#include -+ -+#define EOK 0 -+ -+int split_on_separator(TALLOC_CTX *mem_ctx, const char *str, -+ const char sep, bool trim, bool skip_empty, -+ char ***_list, int *size) -+{ -+ int ret; -+ const char *substr_end = str; -+ const char *substr_begin = str; -+ const char *sep_pos = NULL; -+ size_t substr_len; -+ char **list = NULL; -+ int num_strings = 0; -+ TALLOC_CTX *tmp_ctx = NULL; -+ -+ if (str == NULL || *str == '\0' || _list == NULL) { -+ return EINVAL; -+ } -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ do { -+ substr_len = 0; -+ -+ /* If this is not the first substring, then move from the separator. */ -+ if (sep_pos != NULL) { -+ substr_end = sep_pos + 1; -+ substr_begin = sep_pos + 1; -+ } -+ -+ /* Find end of the first substring */ -+ while (*substr_end != sep && *substr_end != '\0') { -+ substr_end++; -+ substr_len++; -+ } -+ -+ sep_pos = substr_end; -+ -+ if (trim) { -+ /* Trim leading whitespace */ -+ while (isspace(*substr_begin) && substr_begin < substr_end) { -+ substr_begin++; -+ substr_len--; -+ } -+ -+ /* Trim trailing whitespace */ -+ while (substr_end - 1 > substr_begin && isspace(*(substr_end-1))) { -+ substr_end--; -+ substr_len--; -+ } -+ } -+ -+ /* Copy the substring to the output list of strings */ -+ if (skip_empty == false || substr_len > 0) { -+ list = talloc_realloc(tmp_ctx, list, char*, num_strings + 2); -+ if (list == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ /* empty string is stored for substr_len == 0 */ -+ list[num_strings] = talloc_strndup(list, substr_begin, substr_len); -+ if (list[num_strings] == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ num_strings++; -+ } -+ -+ } while (*sep_pos != '\0'); -+ -+ if (list == NULL) { -+ /* No allocations were done, make space for the NULL */ -+ list = talloc(tmp_ctx, char *); -+ if (list == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ list[num_strings] = NULL; -+ -+ if (size) { -+ *size = num_strings; -+ } -+ -+ *_list = talloc_steal(mem_ctx, list); -+ ret = EOK; -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} --- -2.9.3 - diff --git a/SOURCES/0003-MAN-Document-memcache_timeout-0-meaning.patch b/SOURCES/0003-MAN-Document-memcache_timeout-0-meaning.patch new file mode 100644 index 0000000..a64b5a5 --- /dev/null +++ b/SOURCES/0003-MAN-Document-memcache_timeout-0-meaning.patch @@ -0,0 +1,51 @@ +From 22bd144b48e83d812dd823298b723983c4e3288a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Thu, 19 Oct 2017 16:46:43 +0200 +Subject: [PATCH 03/21] MAN: Document memcache_timeout=0 meaning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Document that by setting memcache_timeout to 0 the in-memoory cache +will be disabled. + +Related: +https://pagure.io/SSSD/sssd/issue/3496 + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit 1becbb7bec29a3d418d8f19fc52433cf86bcf395) +--- + src/man/sssd.conf.5.xml | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 7752e450835b5beba50ddc4c635ff985d38ca421..7443f718319e292842c670aaf47cfc537545d021 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -974,12 +974,19 @@ fallback_homedir = /home/%u + + + Specifies time in seconds for which records +- in the in-memory cache will be valid. ++ in the in-memory cache will be valid. Setting this ++ option to zero will disable the in-memory cache. + + + Default: 300 + + ++ WARNING: Disabling the in-memory cache will ++ have significant negative impact on SSSD's ++ performance and should only be used for ++ testing. ++ ++ + NOTE: If the environment variable + SSS_NSS_USE_MEMCACHE is set to "NO", client + applications will not use the fast in-memory +-- +2.13.5 + diff --git a/SOURCES/0003-util-move-string_in_list-to-util_ext.patch b/SOURCES/0003-util-move-string_in_list-to-util_ext.patch deleted file mode 100644 index f21cb03..0000000 --- a/SOURCES/0003-util-move-string_in_list-to-util_ext.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 7bf6cf5632fbdf83a37c52c40b7b982094b5c668 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 20 Feb 2017 17:28:51 +0100 -Subject: [PATCH 03/15] util: move string_in_list to util_ext -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -To be able to include string_in_list() without additional -dependencies it is moved into a separate file. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - src/util/util.c | 20 -------------------- - src/util/util_ext.c | 22 ++++++++++++++++++++++ - 2 files changed, 22 insertions(+), 20 deletions(-) - -diff --git a/src/util/util.c b/src/util/util.c -index 9d6202f695d516f20d648621da81a2d5e746daa5..f0e8f9dd6a4bceed6befb74c57aa066b19a72bb7 100644 ---- a/src/util/util.c -+++ b/src/util/util.c -@@ -617,26 +617,6 @@ errno_t add_string_to_list(TALLOC_CTX *mem_ctx, const char *string, - return EOK; - } - --bool string_in_list(const char *string, char **list, bool case_sensitive) --{ -- size_t c; -- int(*compare)(const char *s1, const char *s2); -- -- if (string == NULL || list == NULL || *list == NULL) { -- return false; -- } -- -- compare = case_sensitive ? strcmp : strcasecmp; -- -- for (c = 0; list[c] != NULL; c++) { -- if (compare(string, list[c]) == 0) { -- return true; -- } -- } -- -- return false; --} -- - void safezero(void *data, size_t size) - { - volatile uint8_t *p = data; -diff --git a/src/util/util_ext.c b/src/util/util_ext.c -index fceb8c873a26471d476b39d5d4e567c445ed8d0b..04dc02a8adf32bd0590fe6eba230658e67d0a362 100644 ---- a/src/util/util_ext.c -+++ b/src/util/util_ext.c -@@ -24,6 +24,8 @@ - #include - #include - #include -+#include -+#include - - #define EOK 0 - -@@ -119,3 +121,23 @@ done: - talloc_free(tmp_ctx); - return ret; - } -+ -+bool string_in_list(const char *string, char **list, bool case_sensitive) -+{ -+ size_t c; -+ int(*compare)(const char *s1, const char *s2); -+ -+ if (string == NULL || list == NULL || *list == NULL) { -+ return false; -+ } -+ -+ compare = case_sensitive ? strcmp : strcasecmp; -+ -+ for (c = 0; list[c] != NULL; c++) { -+ if (compare(string, list[c]) == 0) { -+ return true; -+ } -+ } -+ -+ return false; -+} --- -2.9.3 - diff --git a/SOURCES/0004-CONFIG-Add-a-new-option-auto_private_groups.patch b/SOURCES/0004-CONFIG-Add-a-new-option-auto_private_groups.patch new file mode 100644 index 0000000..9f2a67d --- /dev/null +++ b/SOURCES/0004-CONFIG-Add-a-new-option-auto_private_groups.patch @@ -0,0 +1,159 @@ +From 1deab05ac0820d9be261b55027a90078a758febd Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Oct 2017 12:34:33 +0200 +Subject: [PATCH 04/21] CONFIG: Add a new option auto_private_groups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The auto_private_groups option is used to configure the domain->mpg flag +which was already set automatically for subdomains, but for some time was +not settable by the admin via the configuration file. + +The new option name, instead of the old magic_private_groups, was chosen +purely because this name would hopefully be better understood by admins. + +The option doesn't do anything yet, it is just added to all the places a +new option should be added to. + +Related: + https://pagure.io/SSSD/sssd/issue/1872 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +(cherry picked from commit d72ac2c58360cd272277b5ddde67bbff53106a74) +--- + src/confdb/confdb.c | 8 ++++++++ + src/confdb/confdb.h | 1 + + src/config/SSSDConfig/__init__.py.in | 1 + + src/config/SSSDConfigTest.py | 6 ++++-- + src/config/cfg_rules.ini | 1 + + src/config/etc/sssd.api.conf | 1 + + src/man/sssd.conf.5.xml | 20 ++++++++++++++++++++ + 7 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index fefecc03d554f6eca12efe07990bfae17033bd02..a028224817f12ace2a0c4165d7b9cb0bb80ce5a1 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -936,6 +936,14 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + goto done; + } + ++ ret = get_entry_as_bool(res->msgs[0], &domain->mpg, ++ CONFDB_DOMAIN_AUTO_UPG, 0); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Invalid value for %s\n", CONFDB_DOMAIN_AUTO_UPG); ++ goto done; ++ } ++ + if (strcasecmp(domain->provider, "local") == 0) { + /* If this is the local provider, we need to ensure that + * no other provider was specified for other types, since +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index bcea99ae49a3fa5f0393ce6b2c215b5b2d4bc3fc..2539b906993edbceb38aac9265e04deed69cf2e4 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -198,6 +198,7 @@ + #define CONFDB_DEFAULT_CACHE_CREDS_MIN_FF_LENGTH 8 + #define CONFDB_DOMAIN_LEGACY_PASS "store_legacy_passwords" + #define CONFDB_DOMAIN_MPG "magic_private_groups" ++#define CONFDB_DOMAIN_AUTO_UPG "auto_private_groups" + #define CONFDB_DOMAIN_FQ "use_fully_qualified_names" + #define CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT "entry_cache_timeout" + #define CONFDB_DOMAIN_ACCOUNT_CACHE_EXPIRATION "account_cache_expiration" +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index d99b718e09283d113f73639e0f94e7f1cec55f68..d2bb709d69c8790558b5c06a7e405463b508c189 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -195,6 +195,7 @@ option_strings = { + 'cached_auth_timeout' : _('How long can cached credentials be used for cached authentication'), + 'full_name_format' : _('Printf-compatible format for displaying fully-qualified names'), + 're_expression' : _('Regex to parse username and domain'), ++ 'auto_private_groups' : _('Whether to automatically create private groups for users'), + + # [provider/ipa] + 'ipa_domain' : _('IPA domain'), +diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py +index 4a583bdd3124dc05a116d2e6bd48afb92aa0b54d..87d1f6e6410dfeafc77d578cf0b950dc71a1f0a2 100755 +--- a/src/config/SSSDConfigTest.py ++++ b/src/config/SSSDConfigTest.py +@@ -624,7 +624,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'subdomain_homedir', + 'full_name_format', + 're_expression', +- 'cached_auth_timeout'] ++ 'cached_auth_timeout', ++ 'auto_private_groups'] + + self.assertTrue(type(options) == dict, + "Options should be a dictionary") +@@ -994,7 +995,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'subdomain_homedir', + 'full_name_format', + 're_expression', +- 'cached_auth_timeout'] ++ 'cached_auth_timeout', ++ 'auto_private_groups'] + + self.assertTrue(type(options) == dict, + "Options should be a dictionary") +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index e49e8d43f4aead14d833866110784fd62382cc2b..4e70bf7b6f0fa7421a0c35bd4279830265bf3470 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -382,6 +382,7 @@ option = cached_auth_timeout + option = wildcard_limit + option = full_name_format + option = re_expression ++option = auto_private_groups + + #Entry cache timeouts + option = entry_cache_user_timeout +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index 7f2b8977b7e67fcfc20df49056cda8ebe6da0be8..2be2e3e685ba3abd9a4a419f93332a89ff774262 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -185,6 +185,7 @@ subdomain_homedir = str, None, false + cached_auth_timeout = int, None, false + full_name_format = str, None, false + re_expression = str, None, false ++auto_private_groups = str, None, false + + #Entry cache timeouts + entry_cache_user_timeout = int, None, false +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 7443f718319e292842c670aaf47cfc537545d021..47da07c33bdcfbf2fa94ff932492e9ea4bbfe846 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -2823,6 +2823,26 @@ subdomain_inherit = ldap_purge_cache_timeout + + + ++ ++ auto_private_groups (string) ++ ++ ++ If this option is enabled, SSSD will automatically ++ create user private groups based on user's ++ UID number. The GID number is ignored in this case. ++ ++ ++ NOTE: Because the GID number and the user private group ++ are inferred frm the UID number, it is not supported ++ to have multiple entries with the same UID or GID number ++ with this option. In other words, enabling this option ++ enforces uniqueness across the ID space. ++ ++ ++ Default: False ++ ++ ++ + + + +-- +2.13.5 + diff --git a/SOURCES/0004-certmap-add-new-library-libsss_certmap.patch b/SOURCES/0004-certmap-add-new-library-libsss_certmap.patch deleted file mode 100644 index 1a04fe7..0000000 --- a/SOURCES/0004-certmap-add-new-library-libsss_certmap.patch +++ /dev/null @@ -1,5787 +0,0 @@ -From 64d74f65ca66fafd67c99ac17c5e45e584f59d83 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 2 Feb 2017 11:24:02 +0100 -Subject: [PATCH 04/15] certmap: add new library libsss_certmap -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -With this library it would be possible to map certificates and users not -only by adding the full certificate to the user's LDAP object but by -adding e.g. only parts like the issuer and subject name. Additionally -the library is also able to flexible select/match certificates based on -values in the certificate. - -Details about mapping and matching rules can be found in the included -man page. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - Makefile.am | 55 ++ - configure.ac | 1 + - contrib/sssd.spec.in | 32 + - src/lib/certmap/sss_cert_content_nss.c | 1014 +++++++++++++++++++ - src/lib/certmap/sss_certmap.c | 993 +++++++++++++++++++ - src/lib/certmap/sss_certmap.doxy.in | 3 + - src/lib/certmap/sss_certmap.exports | 13 + - src/lib/certmap/sss_certmap.h | 155 +++ - src/lib/certmap/sss_certmap.pc.in | 11 + - src/lib/certmap/sss_certmap_attr_names.c | 107 +++ - src/lib/certmap/sss_certmap_int.h | 187 ++++ - src/lib/certmap/sss_certmap_krb5_match.c | 558 +++++++++++ - src/lib/certmap/sss_certmap_ldap_mapping.c | 367 +++++++ - src/man/Makefile.am | 2 +- - src/man/po/po4a.cfg | 1 + - src/man/sss-certmap.5.xml | 600 ++++++++++++ - src/tests/cmocka/test_certmap.c | 1443 ++++++++++++++++++++++++++++ - src/tests/dlopen-tests.c | 1 + - 18 files changed, 5542 insertions(+), 1 deletion(-) - create mode 100644 src/lib/certmap/sss_cert_content_nss.c - create mode 100644 src/lib/certmap/sss_certmap.c - create mode 100644 src/lib/certmap/sss_certmap.doxy.in - create mode 100644 src/lib/certmap/sss_certmap.exports - create mode 100644 src/lib/certmap/sss_certmap.h - create mode 100644 src/lib/certmap/sss_certmap.pc.in - create mode 100644 src/lib/certmap/sss_certmap_attr_names.c - create mode 100644 src/lib/certmap/sss_certmap_int.h - create mode 100644 src/lib/certmap/sss_certmap_krb5_match.c - create mode 100644 src/lib/certmap/sss_certmap_ldap_mapping.c - create mode 100644 src/man/sss-certmap.5.xml - create mode 100644 src/tests/cmocka/test_certmap.c - -diff --git a/Makefile.am b/Makefile.am -index 6dae4f2dd7f2dee501add82c7ab4f15fcbcc59ac..8ca12c10d2713b6a72361d84b25486500c79f407 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -278,6 +278,7 @@ if HAVE_CMOCKA - simple-access-tests \ - krb5_common_test \ - test_iobuf \ -+ sss_certmap_test \ - $(NULL) - - if HAVE_LIBRESOLV -@@ -1074,6 +1075,7 @@ SSSD_INTERNAL_LTLIBS = \ - lib_LTLIBRARIES = libipa_hbac.la \ - libsss_idmap.la \ - libsss_nss_idmap.la \ -+ libsss_certmap.la \ - $(NULL) - - pkgconfig_DATA += src/lib/ipa_hbac/ipa_hbac.pc -@@ -1128,6 +1130,7 @@ include_HEADERS = \ - src/lib/ipa_hbac/ipa_hbac.h \ - src/lib/idmap/sss_idmap.h \ - src/sss_client/idmap/sss_nss_idmap.h \ -+ src/lib/certmap/sss_certmap.h \ - $(NULL) - - if BUILD_LIBWBCLIENT -@@ -1712,6 +1715,38 @@ sssd_check_socket_activated_responders_LDADD = \ - $(NULL) - endif - -+if HAVE_NSS -+pkgconfig_DATA += src/lib/certmap/sss_certmap.pc -+libsss_certmap_la_DEPENDENCIES = src/lib/certmap/sss_certmap.exports -+libsss_certmap_la_SOURCES = \ -+ src/lib/certmap/sss_certmap.c \ -+ src/lib/certmap/sss_certmap_attr_names.c \ -+ src/lib/certmap/sss_cert_content_nss.c \ -+ src/lib/certmap/sss_certmap_krb5_match.c \ -+ src/lib/certmap/sss_certmap_ldap_mapping.c \ -+ src/util/util_ext.c \ -+ src/util/cert/cert_common.c \ -+ src/util/crypto/nss/nss_base64.c \ -+ src/util/cert/nss/cert.c \ -+ src/util/crypto/nss/nss_util.c \ -+ $(NULL) -+libsss_certmap_la_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(TALLOC_CFLAGS) \ -+ $(NSS_CFLAGS) \ -+ $(NULL) -+libsss_certmap_la_LIBADD = \ -+ $(TALLOC_LIBS) \ -+ $(NSS_LIBS) \ -+ $(NULL) -+libsss_certmap_la_LDFLAGS = \ -+ -Wl,--version-script,$(srcdir)/src/lib/certmap/sss_certmap.exports \ -+ -version-info 0:0:0 -+ -+dist_noinst_DATA += src/lib/certmap/sss_certmap.exports -+dist_noinst_HEADERS += src/lib/certmap/sss_certmap_int.h -+endif -+ - ################# - # Feature Tests # - ################# -@@ -3245,6 +3280,25 @@ test_inotify_LDADD = \ - libsss_test_common.la \ - $(NULL) - -+if HAVE_NSS -+sss_certmap_test_SOURCES = \ -+ src/tests/cmocka/test_certmap.c \ -+ src/lib/certmap/sss_certmap_attr_names.c \ -+ $(NULL) -+sss_certmap_test_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(NSS_CFLAGS) \ -+ $(NULL) -+sss_certmap_test_LDADD = \ -+ $(CMOCKA_LIBS) \ -+ $(POPT_LIBS) \ -+ $(TALLOC_LIBS) \ -+ $(NSS_LIBS) \ -+ $(SSSD_INTERNAL_LTLIBS) \ -+ libsss_test_common.la \ -+ libsss_certmap.la \ -+ $(NULL) -+endif - endif # HAVE_CMOCKA - - noinst_PROGRAMS = pam_test_client -@@ -4404,6 +4458,7 @@ docs: - $(DOXYGEN) src/lib/ipa_hbac/ipa_hbac.doxy - $(DOXYGEN) src/lib/idmap/sss_idmap.doxy - $(DOXYGEN) src/sss_client/idmap/sss_nss_idmap.doxy -+ $(DOXYGEN) src/lib/certmap/sss_certmap.doxy - if BUILD_IFP - $(DOXYGEN) src/lib/sifp/sss_simpleifp.doxy - endif -diff --git a/configure.ac b/configure.ac -index e6a3b4e857bcbec16873f54008e6b42aeb9b7cd7..dd1012015a5fea9f25e5b5199b4868fbc0bc14c4 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -483,6 +483,7 @@ AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config - src/tests/intg/Makefile - src/lib/ipa_hbac/ipa_hbac.pc src/lib/ipa_hbac/ipa_hbac.doxy - src/lib/idmap/sss_idmap.pc src/lib/idmap/sss_idmap.doxy -+ src/lib/certmap/sss_certmap.pc src/lib/certmap/sss_certmap.doxy - src/sss_client/idmap/sss_nss_idmap.pc - src/sss_client/idmap/sss_nss_idmap.doxy - src/sss_client/libwbclient/wbclient_sssd.pc -diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in -index 5bd2beb89014ba7c86b4231f0357a7a6e10a18a8..28ebe07a26a3112210b092b7831e7f6aae061c8d 100644 ---- a/contrib/sssd.spec.in -+++ b/contrib/sssd.spec.in -@@ -658,6 +658,25 @@ The libnfsidmap sssd module provides a way for rpc.idmapd to call SSSD to map - UIDs/GIDs to names and vice versa. It can be also used for mapping principal - (user) name to IDs(UID or GID) or to obtain groups which user are member of. - -+%package -n libsss_certmap -+Summary: SSSD Certficate Mapping Library -+Group: Development/Libraries -+License: LGPLv3+ -+Requires(post): /sbin/ldconfig -+Requires(postun): /sbin/ldconfig -+ -+%description -n libsss_certmap -+Library to map certificates to users based on rules -+ -+%package -n libsss_certmap-devel -+Summary: SSSD Certficate Mapping Library -+Group: Development/Libraries -+License: LGPLv3+ -+Requires: libsss_certmap = %{version}-%{release} -+ -+%description -n libsss_certmap-devel -+Library to map certificates to users based on rules -+ - %prep - %setup -q -n %{name}-%{version} - -@@ -888,6 +907,7 @@ done - %{_datadir}/sssd/sssd.api.d - %{_mandir}/man1/sss_ssh_authorizedkeys.1* - %{_mandir}/man1/sss_ssh_knownhostsproxy.1* -+%{_mandir}/man5/sss-certmap.5* - %{_mandir}/man5/sssd.conf.5* - %{_mandir}/man5/sssd-simple.5* - %{_mandir}/man5/sssd-sudo.5* -@@ -1146,6 +1166,18 @@ done - %files nfs-idmap - %{_libdir}/libnfsidmap/sss.so - -+%files -n libsss_certmap -+%defattr(-,root,root,-) -+%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER -+%{_libdir}/libsss_certmap.so.* -+ -+%files -n libsss_certmap-devel -+%defattr(-,root,root,-) -+%doc certmap_doc/html -+%{_includedir}/sss_certmap.h -+%{_libdir}/libsss_certmap.so -+%{_libdir}/pkgconfig/sss_certmap.pc -+ - %pre common - getent group sssd >/dev/null || groupadd -r sssd - getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd -diff --git a/src/lib/certmap/sss_cert_content_nss.c b/src/lib/certmap/sss_cert_content_nss.c -new file mode 100644 -index 0000000000000000000000000000000000000000..d3182895465706c87503b8abb0cea49b7677625d ---- /dev/null -+++ b/src/lib/certmap/sss_cert_content_nss.c -@@ -0,0 +1,1014 @@ -+/* -+ SSSD - certificate handling utils - NSS version -+ The calls defined here should be useable outside of SSSD as well, e.g. in -+ libsss_certmap. -+ -+ Copyright (C) Sumit Bose 2017 -+ -+ 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 "config.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "util/crypto/sss_crypto.h" -+#include "util/crypto/nss/nss_util.h" -+#include "util/cert.h" -+#include "lib/certmap/sss_certmap.h" -+#include "lib/certmap/sss_certmap_int.h" -+ -+ -+/* The following two functions are copied from NSS's lib/certdb/secname.c -+ * becasue CERT_AddAVA is not exported. I just renamed it and made it static -+ * to avoid issues if the call gets exported some time in future. */ -+ -+static void ** -+AddToArray(PLArenaPool *arena, void **array, void *element) -+{ -+ unsigned count; -+ void **ap; -+ -+ /* Count up number of slots already in use in the array */ -+ count = 0; -+ ap = array; -+ if (ap) { -+ while (*ap++) { -+ count++; -+ } -+ } -+ -+ if (array) { -+ array = (void**) PORT_ArenaGrow(arena, array, -+ (count + 1) * sizeof(void *), -+ (count + 2) * sizeof(void *)); -+ } else { -+ array = (void**) PORT_ArenaAlloc(arena, (count + 2) * sizeof(void *)); -+ } -+ if (array) { -+ array[count] = element; -+ array[count+1] = 0; -+ } -+ return array; -+} -+ -+ -+static SECStatus -+sss_CERT_AddAVA(PLArenaPool *arena, CERTRDN *rdn, CERTAVA *ava) -+{ -+ rdn->avas = (CERTAVA**) AddToArray(arena, (void**) rdn->avas, ava); -+ return rdn->avas ? SECSuccess : SECFailure; -+} -+ -+static SECItem * -+cert_get_ext_by_tag(CERTCertificate *cert, SECOidTag tag) -+{ -+ SECOidData *oid; -+ int i; -+ -+ oid = SECOID_FindOIDByTag(tag); -+ for (i = 0; -+ (cert->extensions != NULL) && (cert->extensions[i] != NULL); -+ i++) -+ if (SECITEM_ItemsAreEqual(&cert->extensions[i]->id, &oid->oid)) -+ return &cert->extensions[i]->value; -+ return NULL; -+} -+ -+static int get_extended_key_usage_oids(TALLOC_CTX *mem_ctx, -+ CERTCertificate *cert, -+ const char ***_oids) -+{ -+ PLArenaPool *pool; -+ SECItem *ext; -+ SECItem **oids = NULL; -+ const char **oids_list = NULL; -+ size_t c; -+ SECStatus rv; -+ char *tmp_str; -+ int ret; -+ -+ pool = PORT_NewArena(sizeof(double)); -+ ext = cert_get_ext_by_tag(cert, SEC_OID_X509_EXT_KEY_USAGE); -+ if (ext != NULL) { -+ rv = SEC_ASN1DecodeItem(pool, &oids, -+ SEC_ASN1_GET(SEC_SequenceOfObjectIDTemplate), -+ ext); -+ if (rv != SECSuccess) { -+ ret = EINVAL; -+ goto done; -+ } -+ } -+ -+ for (c = 0; (oids != NULL && oids[c] != NULL); c++); -+ oids_list = talloc_zero_array(mem_ctx, const char *, c + 1); -+ if (oids_list == NULL) { -+ return ENOMEM; -+ } -+ -+ for (c = 0; (oids != NULL && oids[c] != NULL); c++) { -+ tmp_str = CERT_GetOidString(oids[c]); -+ /* is it expexted that NSS OID strings start with "OID." but we -+ * prefer the plain dotted-decimal version so the prefix is skipped */ -+ if (tmp_str == NULL || strncmp(tmp_str, "OID.", 4) != 0) { -+ PR_smprintf_free(tmp_str); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ oids_list[c] = talloc_strdup(oids_list, tmp_str + 4); -+ PR_smprintf_free(tmp_str); -+ if(oids_list[c] == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ ret = 0; -+ -+done: -+ PORT_FreeArena(pool, PR_TRUE); -+ if (ret == 0) { -+ *_oids = oids_list; -+ } else { -+ talloc_free(oids_list); -+ } -+ -+ return ret; -+ -+} -+ -+static int get_rdn_str(TALLOC_CTX *mem_ctx, CERTAVA **avas, -+ const char **rdn_str) -+{ -+ size_t c; -+ char *tmp_name = NULL; -+ const char *tmp_str = NULL; -+ int ret; -+ SECStatus rv; -+ CERTRDN rdn = { 0 }; -+ CERTName *name = NULL; -+ PLArenaPool *arena = NULL; -+ -+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); -+ if (arena == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ -+ /* Multiple AVAs should be avoided becasue there is no general ordering -+ * rule and the RDN strings are not reproducible */ -+ for (c = 0; avas[c] != NULL; c++) { -+ rv = sss_CERT_AddAVA(arena, &rdn, avas[c]); -+ if (rv != SECSuccess) { -+ ret = EIO; -+ goto done; -+ } -+ } -+ -+ name = CERT_CreateName(&rdn, NULL); -+ if (name == NULL) { -+ ret = EIO; -+ goto done; -+ } -+ -+ tmp_name = CERT_NameToAscii(name); -+ CERT_DestroyName(name); -+ if (tmp_name == NULL) { -+ ret = EIO; -+ goto done; -+ } -+ -+ tmp_str = talloc_strdup(mem_ctx, tmp_name); -+ PORT_Free(tmp_name); -+ if (tmp_str == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *rdn_str = tmp_str; -+ } else { -+ talloc_free(discard_const(tmp_str)); -+ } -+ PORT_FreeArena(arena, PR_FALSE); -+ -+ return ret; -+} -+ -+static int get_rdn_list(TALLOC_CTX *mem_ctx, CERTRDN **rdns, -+ const char ***rdn_list) -+{ -+ int ret; -+ size_t c; -+ const char **list = NULL; -+ -+ for (c = 0; rdns[c] != NULL; c++); -+ list = talloc_zero_array(mem_ctx, const char *, c + 1); -+ if (list == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ for (c = 0; rdns[c] != NULL; c++) { -+ ret = get_rdn_str(list, rdns[c]->avas, -+ &(list[c])); -+ if (ret != 0) { -+ goto done; -+ } -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *rdn_list = list; -+ } else { -+ talloc_free(list); -+ } -+ -+ return ret; -+} -+ -+enum san_opt nss_name_type_to_san_opt(CERTGeneralNameType type) -+{ -+ switch (type) { -+ case certOtherName: -+ return SAN_OTHER_NAME; -+ case certRFC822Name: -+ return SAN_RFC822_NAME; -+ case certDNSName: -+ return SAN_DNS_NAME; -+ case certX400Address: -+ return SAN_X400_ADDRESS; -+ case certDirectoryName: -+ return SAN_DIRECTORY_NAME; -+ case certEDIPartyName: -+ return SAN_EDIPART_NAME; -+ case certURI: -+ return SAN_URI; -+ case certIPAddress: -+ return SAN_IP_ADDRESS; -+ case certRegisterID: -+ return SAN_REGISTERED_ID; -+ default: -+ return SAN_INVALID; -+ } -+} -+ -+static int add_to_san_list(TALLOC_CTX *mem_ctx, bool is_bin, -+ enum san_opt san_opt, uint8_t *data, size_t len, -+ struct san_list **item) -+{ -+ struct san_list *i; -+ -+ if (data == NULL || len == 0 || san_opt == SAN_INVALID) { -+ return EINVAL; -+ } -+ -+ i = talloc_zero(mem_ctx, struct san_list); -+ if (i == NULL) { -+ return ENOMEM; -+ } -+ -+ i->san_opt = san_opt; -+ if (is_bin) { -+ i->bin_val = talloc_memdup(i, data, len); -+ i->bin_val_len = len; -+ } else { -+ i->val = talloc_strndup(i, (char *) data, len); -+ } -+ if (i->val == NULL) { -+ talloc_free(i); -+ return ENOMEM; -+ } -+ -+ *item = i; -+ -+ return 0; -+} -+ -+/* taken from pkinit_crypto_nss.c of MIT Kerberos */ -+/* KerberosString: RFC 4120, 5.2.1. */ -+static const SEC_ASN1Template kerberos_string_template[] = { -+ { -+ SEC_ASN1_GENERAL_STRING, -+ 0, -+ NULL, -+ sizeof(SECItem), -+ } -+}; -+ -+/* Realm: RFC 4120, 5.2.2. */ -+struct realm { -+ SECItem name; -+}; -+static const SEC_ASN1Template realm_template[] = { -+ { -+ SEC_ASN1_GENERAL_STRING, -+ 0, -+ NULL, -+ sizeof(SECItem), -+ } -+}; -+ -+/* PrincipalName: RFC 4120, 5.2.2. */ -+static const SEC_ASN1Template sequence_of_kerberos_string_template[] = { -+ { -+ SEC_ASN1_SEQUENCE_OF, -+ 0, -+ &kerberos_string_template, -+ 0, -+ } -+}; -+ -+struct principal_name { -+ SECItem name_type; -+ SECItem **name_string; -+}; -+static const SEC_ASN1Template principal_name_template[] = { -+ { -+ SEC_ASN1_SEQUENCE, -+ 0, -+ NULL, -+ sizeof(struct principal_name), -+ }, -+ { -+ SEC_ASN1_CONTEXT_SPECIFIC | 0 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT, -+ offsetof(struct principal_name, name_type), -+ &SEC_IntegerTemplate, -+ sizeof(SECItem), -+ }, -+ { -+ SEC_ASN1_CONTEXT_SPECIFIC | 1 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT, -+ offsetof(struct principal_name, name_string), -+ sequence_of_kerberos_string_template, -+ sizeof(struct SECItem **), -+ }, -+ {0, 0, NULL, 0}, -+}; -+ -+/* KRB5PrincipalName: RFC 4556, 3.2.2. */ -+struct kerberos_principal_name { -+ SECItem realm; -+ struct principal_name principal_name; -+}; -+static const SEC_ASN1Template kerberos_principal_name_template[] = { -+ { -+ SEC_ASN1_SEQUENCE, -+ 0, -+ NULL, -+ sizeof(struct kerberos_principal_name), -+ }, -+ { -+ SEC_ASN1_CONTEXT_SPECIFIC | 0 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT, -+ offsetof(struct kerberos_principal_name, realm), -+ &realm_template, -+ sizeof(struct realm), -+ }, -+ { -+ SEC_ASN1_CONTEXT_SPECIFIC | 1 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT, -+ offsetof(struct kerberos_principal_name, principal_name), -+ &principal_name_template, -+ sizeof(struct principal_name), -+ }, -+ {0, 0, NULL, 0} -+}; -+ -+#define PKINIT_OID "1.3.6.1.5.2.2" -+#define NT_PRINCIPAL_OID "1.3.6.1.4.1.311.20.2.3" -+ -+static int add_string_other_name_to_san_list(TALLOC_CTX *mem_ctx, -+ enum san_opt san_opt, -+ CERTGeneralName *current, -+ struct san_list **item) -+{ -+ struct san_list *i = NULL; -+ int ret; -+ char *tmp_str; -+ -+ tmp_str = CERT_GetOidString(&(current->name.OthName.oid)); -+ /* is it expexted that NSS OID strings start with "OID." but we -+ * prefer the plain dotted-decimal version so the prefix is skipped */ -+ if (tmp_str == NULL || strncmp(tmp_str, "OID.", 4) != 0) { -+ PR_smprintf_free(tmp_str); -+ return EINVAL; -+ } -+ -+ i = talloc_zero(mem_ctx, struct san_list); -+ if (i == NULL) { -+ PR_smprintf_free(tmp_str); -+ return ENOMEM; -+ } -+ i->san_opt = san_opt; -+ -+ i->other_name_oid = talloc_strdup(i, tmp_str + 4); -+ PR_smprintf_free(tmp_str); -+ if (i->other_name_oid == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ i->bin_val = talloc_memdup(i, current->name.OthName.name.data, -+ current->name.OthName.name.len); -+ if (i->bin_val == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ i->bin_val_len = current->name.OthName.name.len; -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *item = i; -+ } else { -+ talloc_free(i); -+ } -+ -+ return ret; -+} -+ -+static int get_short_name(TALLOC_CTX *mem_ctx, const char *full_name, -+ char delim, char **short_name) -+{ -+ char *at; -+ char *s; -+ -+ if (full_name == NULL || delim == '\0' || short_name == NULL) { -+ return EINVAL; -+ } -+ -+ at = strchr(full_name, delim); -+ if (at != NULL) { -+ s = talloc_strndup(mem_ctx, full_name, (at - full_name)); -+ } else { -+ s = talloc_strdup(mem_ctx, full_name); -+ } -+ if (s == NULL) { -+ return ENOMEM; -+ } -+ -+ *short_name = s; -+ -+ return 0; -+} -+ -+static int add_nt_princ_to_san_list(TALLOC_CTX *mem_ctx, -+ PLArenaPool *pool, -+ enum san_opt san_opt, -+ CERTGeneralName *current, -+ struct san_list **item) -+{ -+ struct san_list *i = NULL; -+ SECStatus rv; -+ SECItem tmp_secitem = { 0 }; -+ int ret; -+ -+ rv = SEC_ASN1DecodeItem(pool, &tmp_secitem, -+ SEC_ASN1_GET(SEC_UTF8StringTemplate), -+ &(current->name.OthName.name)); -+ if (rv != SECSuccess) { -+ return EINVAL; -+ } -+ -+ i = talloc_zero(mem_ctx, struct san_list); -+ if (i == NULL) { -+ return ENOMEM; -+ } -+ i->san_opt = san_opt; -+ -+ i->val = talloc_strndup(i, (char *) tmp_secitem.data, -+ tmp_secitem.len); -+ if (i->val == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = get_short_name(i, i->val, '@', &(i->short_name)); -+ if (ret != 0) { -+ goto done; -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *item = i; -+ } else { -+ talloc_free(i); -+ } -+ -+ return ret; -+} -+ -+static int add_pkinit_princ_to_san_list(TALLOC_CTX *mem_ctx, -+ PLArenaPool *pool, -+ enum san_opt san_opt, -+ CERTGeneralName *current, -+ struct san_list **item) -+{ -+ struct san_list *i = NULL; -+ SECStatus rv; -+ struct kerberos_principal_name kname; -+ int ret; -+ size_t c; -+ -+ rv = SEC_ASN1DecodeItem(pool, &kname, -+ kerberos_principal_name_template, -+ &(current->name.OthName.name)); -+ if (rv != SECSuccess) { -+ return EINVAL; -+ } -+ -+ i = talloc_zero(mem_ctx, struct san_list); -+ if (i == NULL) { -+ return ENOMEM; -+ } -+ i->san_opt = san_opt; -+ -+ if (kname.principal_name.name_string != NULL) { -+ i->val = talloc_strdup(i, ""); -+ if (i->val == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ for (c = 0; kname.principal_name.name_string[c] != NULL; c++) { -+ if (c > 0) { -+ i->val = talloc_strdup_append(i->val, "/"); -+ if (i->val == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ i->val = talloc_strndup_append(i->val, -+ (char *) kname.principal_name.name_string[c]->data, -+ kname.principal_name.name_string[c]->len); -+ if (i->val == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ i->val = talloc_strndup_append(i->val, -+ (char *) kname.realm.data, -+ kname.realm.len); -+ if (i->val == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = get_short_name(i, i->val, '@', &(i->short_name)); -+ if (ret != 0) { -+ goto done; -+ } -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *item = i; -+ } else { -+ talloc_free(i); -+ } -+ -+ return ret; -+} -+ -+static int add_oid_to_san_list(TALLOC_CTX *mem_ctx, -+ enum san_opt san_opt, -+ SECItem oid, -+ struct san_list **item) -+{ -+ struct san_list *i = NULL; -+ char *tmp_str; -+ -+ tmp_str = CERT_GetOidString(&oid); -+ /* is it expexted that NSS OID strings start with "OID." but we -+ * prefer the plain dotted-decimal version so the prefix is skipped */ -+ if (tmp_str == NULL || strncmp(tmp_str, "OID.", 4) != 0) { -+ PR_smprintf_free(tmp_str); -+ return EINVAL; -+ } -+ -+ i = talloc_zero(mem_ctx, struct san_list); -+ if (i == NULL) { -+ PR_smprintf_free(tmp_str); -+ return ENOMEM; -+ } -+ i->san_opt = san_opt; -+ -+ i->val = talloc_strdup(i, tmp_str + 4); -+ PR_smprintf_free(tmp_str); -+ if (i->val == NULL) { -+ talloc_free(i); -+ return ENOMEM; -+ } -+ -+ *item = i; -+ return 0; -+} -+ -+static int add_rdn_list_to_san_list(TALLOC_CTX *mem_ctx, -+ enum san_opt san_opt, -+ CERTName name, -+ struct san_list **item) -+{ -+ struct san_list *i = NULL; -+ int ret; -+ -+ i = talloc_zero(mem_ctx, struct san_list); -+ if (i == NULL) { -+ return ENOMEM; -+ } -+ i->san_opt = san_opt; -+ -+ ret = get_rdn_list(i, name.rdns, &(i->rdn_list)); -+ if (ret != 0) { -+ talloc_free(i); -+ return ret; -+ } -+ -+ *item = i; -+ return 0; -+} -+ -+static int add_ip_to_san_list(TALLOC_CTX *mem_ctx, enum san_opt san_opt, -+ uint8_t *data, size_t len, -+ struct san_list **item) -+{ -+ struct san_list *i; -+ PRStatus st; -+ PRNetAddr addr; -+ char addrBuf[80]; -+ -+ if (data == NULL || len == 0 || san_opt == SAN_INVALID) { -+ return EINVAL; -+ } -+ -+ /* taken from secu_PrintIPAddress() */ -+ memset(&addr, 0, sizeof addr); -+ if (len == 4) { -+ addr.inet.family = PR_AF_INET; -+ memcpy(&addr.inet.ip, data, len); -+ } else if (len == 16) { -+ addr.ipv6.family = PR_AF_INET6; -+ memcpy(addr.ipv6.ip.pr_s6_addr, data, len); -+ if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) { -+ /* convert to IPv4. */ -+ addr.inet.family = PR_AF_INET; -+ memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4); -+ memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad); -+ } -+ } else { -+ return EINVAL; -+ } -+ -+ st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf); -+ if (st != PR_SUCCESS) { -+ return EIO; -+ } -+ -+ i = talloc_zero(mem_ctx, struct san_list); -+ if (i == NULL) { -+ return ENOMEM; -+ } -+ -+ i->san_opt = san_opt; -+ i->val = talloc_strdup(i, addrBuf); -+ if (i->val == NULL) { -+ talloc_free(i); -+ return ENOMEM; -+ } -+ -+ *item = i; -+ return 0; -+} -+static int add_principal_to_san_list(TALLOC_CTX *mem_ctx, -+ enum san_opt san_opt, -+ const char *princ, -+ struct san_list **item) -+{ -+ struct san_list *i = NULL; -+ int ret; -+ -+ i = talloc_zero(mem_ctx, struct san_list); -+ if (i == NULL) { -+ return ENOMEM; -+ } -+ i->san_opt = san_opt; -+ -+ i->val = talloc_strdup(i, princ); -+ if (i->val == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = get_short_name(i, i->val, '@', &(i->short_name)); -+ if (ret != 0) { -+ goto done; -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *item = i; -+ } else { -+ talloc_free(i); -+ } -+ -+ return ret; -+} -+ -+static int get_san(TALLOC_CTX *mem_ctx, CERTCertificate *cert, -+ struct san_list **san_list) -+{ -+ -+ SECItem subAltName = { 0 }; -+ SECStatus rv; -+ CERTGeneralName *name_list = NULL; -+ CERTGeneralName *current; -+ PLArenaPool *pool = NULL; -+ int ret; -+ struct san_list *list = NULL; -+ struct san_list *item = NULL; -+ struct san_list *item_s = NULL; -+ struct san_list *item_p = NULL; -+ struct san_list *item_pb = NULL; -+ -+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, -+ &subAltName); -+ if (rv != SECSuccess) { -+ if (rv == SECFailure -+ && PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) { -+ ret = EOK; -+ } else { -+ ret = EIO; -+ } -+ goto done; -+ } -+ -+ pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); -+ if (pool == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ name_list = CERT_DecodeAltNameExtension(pool, &subAltName); -+ if (name_list == NULL ) { -+ ret = EIO; -+ goto done; -+ } -+ -+ current = name_list; -+ do { -+ switch (current->type) { -+ case certOtherName: -+ ret = add_string_other_name_to_san_list(mem_ctx, -+ SAN_STRING_OTHER_NAME, -+ current, &item_s); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(list, item_s); -+ -+ item_p = NULL; -+ if (strcmp(item_s->other_name_oid, NT_PRINCIPAL_OID) == 0) { -+ ret = add_nt_princ_to_san_list(mem_ctx, pool, SAN_NT, current, -+ &item_p); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(list, item_p); -+ } else if (strcmp(item_s->other_name_oid, PKINIT_OID) == 0) { -+ ret = add_pkinit_princ_to_san_list(mem_ctx, pool, SAN_PKINIT, -+ current, &item_p); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(list, item_p); -+ } -+ -+ if (item_p != NULL) { -+ ret = add_principal_to_san_list(mem_ctx, SAN_PRINCIPAL, -+ item_p->val, &item_pb); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(list, item_pb); -+ } -+ -+ break; -+ case certRFC822Name: -+ case certDNSName: -+ case certURI: -+ ret = add_to_san_list(mem_ctx, false, -+ nss_name_type_to_san_opt(current->type), -+ current->name.other.data, -+ current->name.other.len, &item); -+ if (ret != 0) { -+ goto done; -+ } -+ -+ if (current->type == certRFC822Name -+ || current->type == certDNSName) { -+ ret = get_short_name(item, item->val, -+ (current->type == certRFC822Name -+ ? '@' : '.'), -+ &(item->short_name)); -+ if (ret != 0) { -+ goto done; -+ } -+ } -+ -+ DLIST_ADD(list, item); -+ break; -+ case certIPAddress: -+ ret = add_ip_to_san_list(mem_ctx, -+ nss_name_type_to_san_opt(current->type), -+ current->name.other.data, -+ current->name.other.len, &item); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(list, item); -+ break; -+ case certDirectoryName: -+ ret = add_rdn_list_to_san_list(mem_ctx, -+ nss_name_type_to_san_opt(current->type), -+ current->name.directoryName, &item); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(list, item); -+ break; -+ case certRegisterID: -+ ret = add_oid_to_san_list(mem_ctx, -+ nss_name_type_to_san_opt(current->type), -+ current->name.other, &item); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(list, item); -+ break; -+ case certX400Address: -+ case certEDIPartyName: -+ ret = add_to_san_list(mem_ctx, true, -+ nss_name_type_to_san_opt(current->type), -+ current->name.other.data, -+ current->name.other.len, &item); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(list, item); -+ break; -+ default: -+ ret = EINVAL; -+ } -+ -+ current = CERT_GetNextGeneralName(current); -+ if (current == NULL) { -+ ret = EIO; -+ goto done; -+ } -+ } while (current != name_list); -+ -+done: -+ -+ /* Don't free nameList, it's part of the arena. */ -+ -+ if (pool != NULL) { -+ PORT_FreeArena(pool, PR_FALSE); -+ } -+ -+ if (subAltName.data != NULL) { -+ SECITEM_FreeItem(&subAltName, PR_FALSE); -+ } -+ -+ if (ret == EOK) { -+ *san_list = list; -+ } -+ return ret; -+} -+ -+int sss_cert_get_content(TALLOC_CTX *mem_ctx, -+ const uint8_t *der_blob, size_t der_size, -+ struct sss_cert_content **content) -+{ -+ int ret; -+ struct sss_cert_content *cont = NULL; -+ CERTCertDBHandle *handle; -+ CERTCertificate *cert = NULL; -+ SECItem der_item; -+ NSSInitContext *nss_ctx; -+ -+ if (der_blob == NULL || der_size == 0) { -+ return EINVAL; -+ } -+ -+ nss_ctx = NSS_InitContext("", "", "", "", NULL, NSS_INIT_READONLY -+ | NSS_INIT_NOCERTDB -+ | NSS_INIT_NOMODDB -+ | NSS_INIT_FORCEOPEN -+ | NSS_INIT_NOROOTINIT -+ | NSS_INIT_OPTIMIZESPACE); -+ if (nss_ctx == NULL) { -+ return EIO; -+ } -+ -+ cont = talloc_zero(mem_ctx, struct sss_cert_content); -+ if (cont == NULL) { -+ return ENOMEM; -+ } -+ -+ handle = CERT_GetDefaultCertDB(); -+ der_item.len = der_size; -+ der_item.data = discard_const(der_blob); -+ -+ cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE); -+ if (cert == NULL) { -+ ret = EINVAL; -+ goto done; -+ } -+ -+ cont->issuer_str = talloc_strdup(cont, cert->issuerName); -+ if (cont->issuer_str == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = get_rdn_list(cont, cert->issuer.rdns, &cont->issuer_rdn_list); -+ if (ret != 0) { -+ goto done; -+ } -+ -+ cont->subject_str = talloc_strdup(cont, cert->subjectName); -+ if (cont->subject_str == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = get_rdn_list(cont, cert->subject.rdns, &cont->subject_rdn_list); -+ if (ret != 0) { -+ goto done; -+ } -+ -+ -+ cont->key_usage = cert->keyUsage; -+ -+ ret = get_extended_key_usage_oids(cont, cert, -+ &(cont->extended_key_usage_oids)); -+ if (ret != 0) { -+ goto done; -+ } -+ -+ ret = get_san(cont, cert, &(cont->san_list)); -+ if (ret != 0) { -+ goto done; -+ } -+ -+ cont->cert_der = talloc_memdup(cont, der_blob, der_size); -+ if (cont->cert_der == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ cont->cert_der_size = der_size; -+ ret = EOK; -+ -+done: -+ -+ CERT_DestroyCertificate(cert); -+ NSS_ShutdownContext(nss_ctx); -+ -+ if (ret == EOK) { -+ *content = cont; -+ } else { -+ talloc_free(cont); -+ } -+ -+ return ret; -+} -diff --git a/src/lib/certmap/sss_certmap.c b/src/lib/certmap/sss_certmap.c -new file mode 100644 -index 0000000000000000000000000000000000000000..080cab8ab585ce64a88c352a23a8062887fa720a ---- /dev/null -+++ b/src/lib/certmap/sss_certmap.c -@@ -0,0 +1,993 @@ -+/* -+ SSSD -+ -+ Library for rule based certificate to user mapping -+ -+ Authors: -+ Sumit Bose -+ -+ Copyright (C) 2017 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 "util/util.h" -+#include "util/cert.h" -+#include "util/crypto/sss_crypto.h" -+#include "lib/certmap/sss_certmap.h" -+#include "lib/certmap/sss_certmap_int.h" -+ -+int debug_level; -+void sss_debug_fn(const char *file, -+ long line, -+ const char *function, -+ int level, -+ const char *format, ...) -+{ -+ return; -+} -+ -+static int get_type_prefix(TALLOC_CTX *mem_ctx, const char *match_rule, -+ char **type, const char **rule_start) -+{ -+ const char *c; -+ char *delim; -+ -+ *type = NULL; -+ *rule_start = match_rule; -+ -+ delim = strchr(match_rule, ':'); -+ if (delim == NULL) { -+ /* no type prefix found */ -+ return 0; -+ } -+ -+ /* rule starts with ':', empty type */ -+ if (delim == match_rule) { -+ *rule_start = delim + 1; -+ return EOK; -+ } -+ -+ for (c = match_rule; c < delim; c++) { -+ /* type prefix may only contain digits and upper-case ASCII characters */ -+ if (!(isascii(*c) && (isdigit(*c) || isupper(*c)))) { -+ /* no type prefix found */ -+ return 0; -+ } -+ } -+ -+ *rule_start = delim + 1; -+ *type = talloc_strndup(mem_ctx, match_rule, (delim - match_rule)); -+ if (*type == NULL) { -+ return ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static int parse_match_rule(struct sss_certmap_ctx *ctx, const char *match_rule, -+ struct krb5_match_rule **parsed_match_rule) -+{ -+ int ret; -+ char *type; -+ const char *rule_start; -+ -+ ret = get_type_prefix(ctx, match_rule, &type, &rule_start); -+ if (ret != EOK) { -+ CM_DEBUG(ctx, "Failed to read rule type."); -+ goto done; -+ } -+ -+ if (type == NULL || strcmp(type, "KRB5") == 0) { -+ ret = parse_krb5_match_rule(ctx, rule_start, parsed_match_rule); -+ if (ret != EOK) { -+ CM_DEBUG(ctx, "Failed to parse KRB5 matching rule."); -+ goto done; -+ } -+ } else { -+ CM_DEBUG(ctx, "Unsupported matching rule type."); -+ ret = ESRCH; -+ goto done; -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_free(type); -+ -+ return ret; -+} -+ -+static int parse_mapping_rule(struct sss_certmap_ctx *ctx, -+ const char *mapping_rule, -+ struct ldap_mapping_rule **parsed_mapping_rule) -+{ -+ int ret; -+ char *type; -+ const char *rule_start; -+ -+ ret = get_type_prefix(ctx, mapping_rule, &type, &rule_start); -+ if (ret != EOK) { -+ CM_DEBUG(ctx, "Failed to read rule type."); -+ goto done; -+ } -+ -+ if (type == NULL || strcmp(type, "LDAP") == 0) { -+ ret = parse_ldap_mapping_rule(ctx, rule_start, parsed_mapping_rule); -+ if (ret != EOK) { -+ CM_DEBUG(ctx, "Failed to parse LDAP mapping rule."); -+ goto done; -+ } -+ } else { -+ CM_DEBUG(ctx, "Unsupported mapping rule type."); -+ ret = ESRCH; -+ goto done; -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_free(type); -+ -+ return ret; -+} -+ -+int sss_certmap_add_rule(struct sss_certmap_ctx *ctx, -+ uint32_t priority, const char *match_rule, -+ const char *map_rule, const char **domains) -+{ -+ size_t c; -+ int ret; -+ struct match_map_rule *rule; -+ struct TALLOC_CTX *tmp_ctx; -+ struct priority_list *p; -+ struct priority_list *p_new; -+ struct krb5_match_rule *parsed_match_rule; -+ struct ldap_mapping_rule *parsed_mapping_rule; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ rule = talloc_zero(tmp_ctx, struct match_map_rule); -+ if (rule == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ rule->priority = priority; -+ -+ if (match_rule == NULL) { -+ match_rule = DEFAULT_MATCH_RULE; -+ } -+ ret = parse_match_rule(ctx, match_rule, &parsed_match_rule); -+ if (ret == 0) { -+ rule->parsed_match_rule = talloc_steal(rule, parsed_match_rule); -+ rule->match_rule = talloc_strdup(rule, match_rule); -+ if (rule->match_rule == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } else if (ret == ESRCH) { -+ /* report unsupported rules */ -+ goto done; -+ } else { -+ goto done; -+ } -+ -+ if (map_rule == NULL) { -+ map_rule = DEFAULT_MAP_RULE; -+ } -+ ret = parse_mapping_rule(ctx, map_rule, &parsed_mapping_rule); -+ if (ret == 0) { -+ rule->parsed_mapping_rule = talloc_steal(rule, parsed_mapping_rule); -+ rule->map_rule = talloc_strdup(rule, map_rule); -+ if (rule->map_rule == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } else if (ret == ESRCH) { -+ /* report unsupported rules */ -+ goto done; -+ } else { -+ goto done; -+ } -+ -+ if (domains != NULL && *domains != NULL) { -+ for (c = 0; domains[c] != NULL; c++); -+ rule->domains = talloc_zero_array(rule, char *, c + 1); -+ if (rule->domains == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ for (c = 0; domains[c] != NULL; c++) { -+ rule->domains[c] = talloc_strdup(rule->domains, domains[c]); -+ if (rule->domains[c] == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ } -+ -+ if (ctx->prio_list == NULL) { -+ ctx->prio_list = talloc_zero(ctx, struct priority_list); -+ if (ctx->prio_list == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ctx->prio_list->priority = rule->priority; -+ ctx->prio_list->rule_list = rule; -+ } else { -+ for (p = ctx->prio_list; p != NULL && p->priority < rule->priority; -+ p = p->next); -+ if (p != NULL && p->priority == priority) { -+ DLIST_ADD(p->rule_list, rule); -+ } else { -+ p_new = talloc_zero(ctx, struct priority_list); -+ if (p_new == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ p_new->priority = rule->priority; -+ p_new->rule_list = rule; -+ -+ if (p == NULL) { -+ DLIST_ADD_END(ctx->prio_list, p_new, struct priority_list *); -+ } else if (p->prev == NULL) { -+ DLIST_ADD(ctx->prio_list, p_new); -+ } else { -+ DLIST_ADD_AFTER(ctx->prio_list, p_new, p->prev); -+ } -+ } -+ } -+ -+ talloc_steal(ctx, rule); -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ -+ return ret; -+} -+ -+static int expand_cert(struct sss_certmap_ctx *ctx, -+ struct parsed_template *parsed_template, -+ struct sss_cert_content *cert_content, -+ char **expanded) -+{ -+ int ret; -+ char *tmp_str = NULL; -+ -+ if (parsed_template->conversion == NULL -+ || strcmp(parsed_template->conversion, "bin") == 0) { -+ ret = bin_to_ldap_filter_value(ctx, cert_content->cert_der, -+ cert_content->cert_der_size, &tmp_str); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "bin conversion failed."); -+ goto done; -+ } -+ } else if (strcmp(parsed_template->conversion, "base64") == 0) { -+ tmp_str = sss_base64_encode(ctx, cert_content->cert_der, -+ cert_content->cert_der_size); -+ if (tmp_str == NULL) { -+ CM_DEBUG(ctx, "base64 conversion failed."); -+ ret = ENOMEM; -+ goto done; -+ } -+ } else { -+ CM_DEBUG(ctx, "Unsupported conversion."); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *expanded = tmp_str; -+ } else { -+ talloc_free(tmp_str); -+ } -+ -+ return ret; -+} -+ -+static int get_dn_str(struct sss_certmap_ctx *ctx, const char *conversion, -+ const char **rdn_list, char **result) -+{ -+ char *str = NULL; -+ size_t c; -+ int ret; -+ char *conv = NULL; -+ -+ str = talloc_strdup(ctx, ""); -+ if (str == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ if (conversion == NULL || strcmp(conversion, "nss_ldap") == 0 -+ || strcmp(conversion, "nss") == 0) { -+ for (c = 0; rdn_list[c] != NULL; c++); -+ while (c != 0) { -+ c--; -+ str = talloc_asprintf_append(str, "%s%s", -+ (rdn_list[c + 1] == NULL) ? "" : ",", -+ rdn_list[c]); -+ if (str == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ }; -+ } else if (strcmp(conversion, "ad_ldap") == 0) { -+ for (c = 0; rdn_list[c] != NULL; c++); -+ while (c != 0) { -+ c--; -+ conv = check_ad_attr_name(str, rdn_list[c]); -+ str = talloc_asprintf_append(str, "%s%s", -+ (rdn_list[c + 1] == NULL) ? "" : ",", -+ conv == NULL ? rdn_list[c] : conv); -+ talloc_free(conv); -+ conv = NULL; -+ if (str == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ }; -+ } else if (strcmp(conversion, "nss_x500") == 0) { -+ for (c = 0; rdn_list[c] != NULL; c++) { -+ str = talloc_asprintf_append(str, "%s%s", (c == 0) ? "" : ",", -+ rdn_list[c]); -+ if (str == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ } else if (strcmp(conversion, "ad_x500") == 0 -+ || strcmp(conversion, "ad") == 0) { -+ for (c = 0; rdn_list[c] != NULL; c++) { -+ conv = check_ad_attr_name(str, rdn_list[c]); -+ str = talloc_asprintf_append(str, "%s%s", -+ (c == 0) ? "" : ",", -+ conv == NULL ? rdn_list[c] : conv); -+ talloc_free(conv); -+ conv = NULL; -+ if (str == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ } else { -+ ret = EINVAL; -+ goto done; -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *result = str; -+ } else { -+ talloc_free(str); -+ } -+ -+ return ret; -+} -+ -+static int expand_san_blob(struct sss_certmap_ctx *ctx, enum san_opt san_opt, -+ struct san_list *san_list, char **expanded) -+{ -+ struct san_list *item; -+ char *exp; -+ int ret; -+ -+ DLIST_FOR_EACH(item, san_list) { -+ if (item->san_opt == san_opt) { -+ ret = bin_to_ldap_filter_value(ctx, item->bin_val, -+ item->bin_val_len, &exp); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "bin conversion failed."); -+ return ret; -+ } -+ -+ *expanded = exp; -+ return 0; -+ } -+ } -+ -+ return ENOENT; -+} -+ -+static int expand_san_string(struct sss_certmap_ctx *ctx, enum san_opt san_opt, -+ struct san_list *san_list, const char *attr_name, -+ char **expanded) -+{ -+ struct san_list *item; -+ char *exp; -+ -+ DLIST_FOR_EACH(item, san_list) { -+ if (item->san_opt == san_opt) { -+ if (attr_name == NULL) { -+ exp = talloc_strdup(ctx, item->val); -+ } else if (strcasecmp(attr_name, "short_name") == 0) { -+ exp = talloc_strdup(ctx, item->short_name); -+ } else { -+ CM_DEBUG(ctx, "Unsupported attribute name [%s].", attr_name); -+ return EINVAL; -+ } -+ -+ if (exp == NULL) { -+ return ENOMEM; -+ } -+ -+ *expanded = exp; -+ return 0; -+ } -+ } -+ -+ return ENOENT; -+} -+ -+static int expand_san_rdn_list(struct sss_certmap_ctx *ctx, -+ enum san_opt san_opt, -+ struct san_list *san_list, -+ const char *conversion, -+ char **expanded) -+{ -+ struct san_list *item; -+ char *exp; -+ int ret; -+ -+ DLIST_FOR_EACH(item, san_list) { -+ if (item->san_opt == san_opt) { -+ ret = get_dn_str(ctx, conversion, item->rdn_list, &exp); -+ if (ret != 0) { -+ return ret; -+ } -+ -+ *expanded = exp; -+ return 0; -+ } -+ } -+ -+ return ENOENT; -+} -+ -+ -+static int expand_san(struct sss_certmap_ctx *ctx, -+ struct parsed_template *parsed_template, -+ struct san_list *san_list, -+ char **expanded) -+{ -+ int ret; -+ -+ if (strcmp("subject_rfc822_name", parsed_template->name) == 0) { -+ ret = expand_san_string(ctx, SAN_RFC822_NAME, san_list, -+ parsed_template->attr_name, expanded); -+ } else if (strcmp("subject_dns_name", parsed_template->name) == 0) { -+ ret = expand_san_string(ctx, SAN_DNS_NAME, san_list, -+ parsed_template->attr_name, expanded); -+ } else if (strcmp("subject_x400_address", parsed_template->name) == 0) { -+ ret = expand_san_blob(ctx, SAN_X400_ADDRESS, san_list, expanded); -+ } else if (strcmp("subject_directory_name", parsed_template->name) == 0) { -+ ret = expand_san_rdn_list(ctx, SAN_DIRECTORY_NAME, san_list, -+ parsed_template->conversion, expanded); -+ } else if (strcmp("subject_ediparty_name", parsed_template->name) == 0) { -+ ret = expand_san_blob(ctx, SAN_EDIPART_NAME, san_list, expanded); -+ } else if (strcmp("subject_uri", parsed_template->name) == 0) { -+ ret = expand_san_string(ctx, SAN_URI, san_list, -+ parsed_template->attr_name, expanded); -+ } else if (strcmp("subject_ip_address", parsed_template->name) == 0) { -+ ret = expand_san_string(ctx, SAN_IP_ADDRESS, san_list, -+ parsed_template->attr_name, expanded); -+ } else if (strcmp("subject_registered_id", parsed_template->name) == 0) { -+ ret = expand_san_string(ctx, SAN_REGISTERED_ID, san_list, -+ parsed_template->attr_name, expanded); -+ } else if (strcmp("subject_pkinit_principal", parsed_template->name) == 0) { -+ ret = expand_san_string(ctx, SAN_PKINIT, san_list, -+ parsed_template->attr_name, expanded); -+ } else if (strcmp("subject_nt_principal", parsed_template->name) == 0) { -+ ret = expand_san_string(ctx, SAN_NT, san_list, -+ parsed_template->attr_name, expanded); -+ } else if (strcmp("subject_principal", parsed_template->name) == 0) { -+ ret = expand_san_string(ctx, SAN_PRINCIPAL, san_list, -+ parsed_template->attr_name, expanded); -+ } else { -+ CM_DEBUG(ctx, "Unsupported template name [%s].n", -+ parsed_template->name); -+ ret = EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int expand_template(struct sss_certmap_ctx *ctx, -+ struct parsed_template *parsed_template, -+ struct sss_cert_content *cert_content, -+ char **expanded) -+{ -+ int ret; -+ char *exp = NULL; -+ -+ if (strcmp("issuer_dn", parsed_template->name) == 0) { -+ ret = get_dn_str(ctx, parsed_template->conversion, -+ cert_content->issuer_rdn_list, &exp); -+ } else if (strcmp("subject_dn", parsed_template->name) == 0) { -+ ret = get_dn_str(ctx, parsed_template->conversion, -+ cert_content->subject_rdn_list, &exp); -+ } else if (strncmp("subject_", parsed_template->name, 8) == 0) { -+ ret = expand_san(ctx, parsed_template, cert_content->san_list, &exp); -+ } else if (strcmp("cert", parsed_template->name) == 0) { -+ ret = expand_cert(ctx, parsed_template, cert_content, &exp); -+ } else { -+ CM_DEBUG(ctx, "Unsupported template name."); -+ ret = EINVAL; -+ goto done; -+ } -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to expand [%s] template.", parsed_template->name); -+ goto done; -+ } -+ -+ if (exp == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *expanded = exp; -+ } else { -+ talloc_free(exp); -+ } -+ -+ return ret; -+} -+ -+static int get_filter(struct sss_certmap_ctx *ctx, -+ struct ldap_mapping_rule *parsed_mapping_rule, -+ struct sss_cert_content *cert_content, -+ char **filter) -+{ -+ struct ldap_mapping_rule_comp *comp; -+ char *result = NULL; -+ char *expanded = NULL; -+ int ret; -+ -+ result = talloc_strdup(ctx, ""); -+ if (result == NULL) { -+ return ENOMEM; -+ } -+ -+ for (comp = parsed_mapping_rule->list; comp != NULL; comp = comp->next) { -+ if (comp->type == comp_string) { -+ result = talloc_strdup_append(result, comp->val); -+ } else if (comp->type == comp_template) { -+ ret = expand_template(ctx, comp->parsed_template, cert_content, -+ &expanded); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to expanded template."); -+ goto done; -+ } -+ -+ result = talloc_strdup_append(result, expanded); -+ talloc_free(expanded); -+ expanded = NULL; -+ if (result == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } else { -+ ret = EINVAL; -+ CM_DEBUG(ctx, "Unsupported component type."); -+ goto done; -+ } -+ } -+ -+ ret = 0; -+done: -+ talloc_free(expanded); -+ if (ret == 0) { -+ *filter = result; -+ } else { -+ talloc_free(result); -+ } -+ -+ return ret; -+} -+ -+static bool check_san_regexp(struct sss_certmap_ctx *ctx, -+ enum san_opt san_opt, regex_t regexp, -+ struct san_list *san_list) -+{ -+ struct san_list *item; -+ bool match = false; -+ int ret; -+ char *tmp_str = NULL; -+ -+ DLIST_FOR_EACH(item, san_list) { -+ if (item->san_opt == san_opt) { -+ if (item->san_opt == SAN_DIRECTORY_NAME) { -+ /* use LDAP order for matching */ -+ ret = get_dn_str(ctx, NULL, item->rdn_list, &tmp_str); -+ if (ret != 0 || tmp_str == NULL) { -+ return false; -+ } -+ match = (regexec(®exp, tmp_str, 0, NULL, 0) == 0); -+ talloc_free(tmp_str); -+ } else { -+ match = (item->val != NULL -+ && regexec(®exp, item->val, 0, NULL, 0) == 0); -+ } -+ if (!match) { -+ return false; -+ } -+ } -+ } -+ -+ return match; -+} -+ -+static bool check_san_blob(enum san_opt san_opt, -+ uint8_t *bin_val, size_t bin_val_len, -+ struct san_list *san_list) -+{ -+ struct san_list *item; -+ bool match = false; -+ -+ if (bin_val == NULL || bin_val_len == 0) { -+ return false; -+ } -+ -+ DLIST_FOR_EACH(item, san_list) { -+ if (item->san_opt == san_opt) { -+ match = (item->bin_val != NULL && item->bin_val_len != 0 -+ && memmem(item->bin_val, item->bin_val_len, -+ bin_val, bin_val_len) != NULL); -+ if (!match) { -+ return false; -+ } -+ } -+ } -+ -+ return match; -+} -+ -+static bool check_san_str_other_name(enum san_opt san_opt, -+ const char *str_other_name_oid, -+ regex_t regexp, -+ struct san_list *san_list) -+{ -+ struct san_list *item; -+ bool match = false; -+ char *tmp_str; -+ -+ if (str_other_name_oid == NULL) { -+ return false; -+ } -+ -+ DLIST_FOR_EACH(item, san_list) { -+ if (item->san_opt == san_opt -+ && strcmp(item->other_name_oid, str_other_name_oid) == 0) { -+ match = false; -+ if (item->bin_val != NULL && item->bin_val_len != 0) { -+ tmp_str = talloc_strndup(item, (char *) item->bin_val, -+ item->bin_val_len); -+ if (tmp_str != NULL) { -+ match = (regexec(®exp, tmp_str, 0, NULL, 0) == 0); -+ } -+ talloc_free(tmp_str); -+ } -+ if (!match) { -+ return false; -+ } -+ } -+ } -+ -+ return match; -+} -+ -+static bool do_san_match(struct sss_certmap_ctx *ctx, -+ struct component_list *comp, -+ struct san_list *san_list) -+{ -+ switch (comp->san_opt) { -+ case SAN_OTHER_NAME: -+ return check_san_blob(SAN_STRING_OTHER_NAME, -+ comp->bin_val, comp->bin_val_len, -+ san_list); -+ break; -+ case SAN_X400_ADDRESS: -+ case SAN_EDIPART_NAME: -+ return check_san_blob(comp->san_opt, comp->bin_val, comp->bin_val_len, -+ san_list); -+ break; -+ case SAN_RFC822_NAME: -+ case SAN_DNS_NAME: -+ case SAN_DIRECTORY_NAME: -+ case SAN_URI: -+ case SAN_IP_ADDRESS: -+ case SAN_REGISTERED_ID: -+ case SAN_PKINIT: -+ case SAN_NT: -+ case SAN_PRINCIPAL: -+ return check_san_regexp(ctx, comp->san_opt, comp->regexp, san_list); -+ break; -+ case SAN_STRING_OTHER_NAME: -+ return check_san_str_other_name(comp->san_opt, comp->str_other_name_oid, -+ comp->regexp, san_list); -+ break; -+ default: -+ CM_DEBUG(ctx, "Unsupported SAN option [%d].", comp->san_opt); -+ return false; -+ } -+} -+ -+static int do_match(struct sss_certmap_ctx *ctx, -+ struct krb5_match_rule *parsed_match_rule, -+ struct sss_cert_content *cert_content) -+{ -+ struct component_list *comp; -+ bool match = false; -+ size_t c; -+ -+ if (parsed_match_rule == NULL || cert_content == NULL) { -+ return EINVAL; -+ } -+ -+ /* Issuer */ -+ for (comp = parsed_match_rule->issuer; comp != NULL; comp = comp->next) { -+ match = (cert_content->issuer_str != NULL -+ && regexec(&(comp->regexp), cert_content->issuer_str, -+ 0, NULL, 0) == 0); -+ if (match && parsed_match_rule->r == relation_or) { -+ /* match */ -+ return 0; -+ } else if (!match && parsed_match_rule->r == relation_and) { -+ /* no match */ -+ return ENOENT; -+ } -+ -+ } -+ -+ /* Subject */ -+ for (comp = parsed_match_rule->subject; comp != NULL; comp = comp->next) { -+ match = (cert_content->subject_str != NULL -+ && regexec(&(comp->regexp), cert_content->subject_str, -+ 0, NULL, 0) == 0); -+ if (match && parsed_match_rule->r == relation_or) { -+ /* match */ -+ return 0; -+ } else if (!match && parsed_match_rule->r == relation_and) { -+ /* no match */ -+ return ENOENT; -+ } -+ -+ } -+ -+ /* Key Usage */ -+ for (comp = parsed_match_rule->ku; comp != NULL; comp = comp->next) { -+ match = ((cert_content->key_usage & comp->ku) == comp->ku); -+ if (match && parsed_match_rule->r == relation_or) { -+ /* match */ -+ return 0; -+ } else if (!match && parsed_match_rule->r == relation_and) { -+ /* no match */ -+ return ENOENT; -+ } -+ } -+ -+ /* Extended Key Usage */ -+ for (comp = parsed_match_rule->eku; comp != NULL; comp = comp->next) { -+ for (c = 0; comp->eku_oid_list[c] != NULL; c++) { -+ match = string_in_list(comp->eku_oid_list[c], -+ discard_const( -+ cert_content->extended_key_usage_oids), -+ true); -+ if (match && parsed_match_rule->r == relation_or) { -+ /* match */ -+ return 0; -+ } else if (!match && parsed_match_rule->r == relation_and) { -+ /* no match */ -+ return ENOENT; -+ } -+ } -+ } -+ -+ /* SAN */ -+ for (comp = parsed_match_rule->san; comp != NULL; comp = comp->next) { -+ match = do_san_match(ctx, comp, cert_content->san_list); -+ if (match && parsed_match_rule->r == relation_or) { -+ /* match */ -+ return 0; -+ } else if (!match && parsed_match_rule->r == relation_and) { -+ /* no match */ -+ return ENOENT; -+ } -+ } -+ -+ if (match) { -+ /* match */ -+ return 0; -+ } -+ -+ /* no match */ -+ return ENOENT; -+} -+ -+int sss_certmap_match_cert(struct sss_certmap_ctx *ctx, -+ const uint8_t *der_cert, size_t der_size) -+{ -+ int ret; -+ struct match_map_rule *r; -+ struct priority_list *p; -+ struct sss_cert_content *cert_content = NULL; -+ -+ ret = sss_cert_get_content(ctx, der_cert, der_size, &cert_content); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to get certificate content."); -+ return ret; -+ } -+ -+ if (ctx->prio_list == NULL) { -+ /* Match all certificates if there are no rules applied */ -+ ret = 0; -+ goto done; -+ } -+ -+ for (p = ctx->prio_list; p != NULL; p = p->next) { -+ for (r = p->rule_list; r != NULL; r = r->next) { -+ ret = do_match(ctx, r->parsed_match_rule, cert_content); -+ if (ret == 0) { -+ /* match */ -+ goto done; -+ } -+ } -+ } -+ -+ ret = ENOENT; -+done: -+ talloc_free(cert_content); -+ -+ return ret; -+} -+ -+int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx, -+ const uint8_t *der_cert, size_t der_size, -+ char **_filter, char ***_domains) -+{ -+ int ret; -+ struct match_map_rule *r; -+ struct priority_list *p; -+ struct sss_cert_content *cert_content = NULL; -+ char *filter = NULL; -+ char **domains = NULL; -+ size_t c; -+ -+ if (_filter == NULL || _domains == NULL) { -+ return EINVAL; -+ } -+ -+ ret = sss_cert_get_content(ctx, der_cert, der_size, &cert_content); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to get certificate content [%d].", ret); -+ return ret; -+ } -+ -+ if (ctx->prio_list == NULL) { -+ if (ctx->default_mapping_rule == NULL) { -+ CM_DEBUG(ctx, "No matching or mapping rules available."); -+ return EINVAL; -+ } -+ -+ ret = get_filter(ctx, ctx->default_mapping_rule, cert_content, &filter); -+ goto done; -+ } -+ -+ for (p = ctx->prio_list; p != NULL; p = p->next) { -+ for (r = p->rule_list; r != NULL; r = r->next) { -+ ret = do_match(ctx, r->parsed_match_rule, cert_content); -+ if (ret == 0) { -+ /* match */ -+ ret = get_filter(ctx, r->parsed_mapping_rule, cert_content, -+ &filter); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to get filter"); -+ goto done; -+ } -+ -+ if (r->domains != NULL) { -+ for (c = 0; r->domains[c] != NULL; c++); -+ domains = talloc_zero_array(ctx, char *, c + 1); -+ if (domains == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ for (c = 0; r->domains[c] != NULL; c++) { -+ domains[c] = talloc_strdup(domains, r->domains[c]); -+ if (domains[c] == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ } -+ -+ ret = 0; -+ goto done; -+ } -+ } -+ } -+ -+ ret = ENOENT; -+ -+done: -+ talloc_free(cert_content); -+ if (ret == 0) { -+ *_filter = filter; -+ *_domains = domains; -+ } else { -+ talloc_free(filter); -+ talloc_free(domains); -+ } -+ -+ return ret; -+} -+ -+int sss_certmap_init(TALLOC_CTX *mem_ctx, -+ sss_certmap_ext_debug *debug, void *debug_priv, -+ struct sss_certmap_ctx **ctx) -+{ -+ int ret; -+ -+ if (ctx == NULL) { -+ return EINVAL; -+ } -+ -+ *ctx = talloc_zero(mem_ctx, struct sss_certmap_ctx); -+ if (*ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ (*ctx)->debug = debug; -+ (*ctx)->debug_priv = debug_priv; -+ -+ ret = parse_mapping_rule(*ctx, DEFAULT_MAP_RULE, -+ &((*ctx)->default_mapping_rule)); -+ if (ret != 0) { -+ CM_DEBUG((*ctx), "Failed to parse default mapping rule."); -+ talloc_free(*ctx); -+ *ctx = NULL; -+ return ret; -+ } -+ -+ CM_DEBUG((*ctx), "sss_certmap initialized."); -+ return EOK; -+} -+ -+void sss_certmap_free_ctx(struct sss_certmap_ctx *ctx) -+{ -+ talloc_free(ctx); -+} -+ -+void sss_certmap_free_filter_and_domains(char *filter, char **domains) -+{ -+ talloc_free(filter); -+ talloc_free(domains); -+} -diff --git a/src/lib/certmap/sss_certmap.doxy.in b/src/lib/certmap/sss_certmap.doxy.in -new file mode 100644 -index 0000000000000000000000000000000000000000..e8959e2099a0f517c314833e47d410306fb02702 ---- /dev/null -+++ b/src/lib/certmap/sss_certmap.doxy.in -@@ -0,0 +1,3 @@ -+PROJECT_NAME = sss_certmap -+OUTPUT_DIRECTORY = certmap_doc -+INPUT = @abs_top_srcdir@/src/lib/certmap/sss_certmap.h -diff --git a/src/lib/certmap/sss_certmap.exports b/src/lib/certmap/sss_certmap.exports -new file mode 100644 -index 0000000000000000000000000000000000000000..8b5d5366697401649547c09c6b6f3db571c2b518 ---- /dev/null -+++ b/src/lib/certmap/sss_certmap.exports -@@ -0,0 +1,13 @@ -+SSS_CERTMAP_0.0 { -+ global: -+ sss_certmap_init; -+ sss_certmap_free_ctx; -+ sss_certmap_err_msg; -+ sss_certmap_add_rule; -+ sss_certmap_match_cert; -+ sss_certmap_get_search_filter; -+ sss_cert_get_content; -+ sss_certmap_free_filter_and_domains; -+ local: -+ *; -+}; -diff --git a/src/lib/certmap/sss_certmap.h b/src/lib/certmap/sss_certmap.h -new file mode 100644 -index 0000000000000000000000000000000000000000..55485cc35e8bd7cf2cb2b0c5a06a7521025e3c43 ---- /dev/null -+++ b/src/lib/certmap/sss_certmap.h -@@ -0,0 +1,155 @@ -+/* -+ SSSD -+ -+ Library for rule based certificate to user mapping -+ -+ Authors: -+ Sumit Bose -+ -+ Copyright (C) 2017 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 . -+*/ -+ -+#ifndef _SSS_CERTMAP_H_ -+#define _SSS_CERTMAP_H_ -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+/** -+ * @defgroup sss_certmap Allow rule-based mapping of certificates to users -+ * Libsss_certmap provides a mechanism to map X509 certificate to users based -+ * on rules. -+ * @{ -+ */ -+ -+/** -+ * Opaque type for the idmap context -+ */ -+struct sss_certmap_ctx; -+ -+/** -+ * Lowest priority of a rule -+ */ -+#define SSS_CERTMAP_MIN_PRIO UINT32_MAX -+ -+/** -+ * Typedef for external debug callback -+ */ -+typedef void (sss_certmap_ext_debug)(void *pvt, -+ const char *file, long line, -+ const char *function, -+ const char *format, ...); -+/** -+ * @brief Initialize certmap context -+ * -+ * @param[in] mem_ctx Talloc memory context, may be NULL -+ * @param[in] debug Callback to handle debug output, may be NULL -+ * @param[in] debug_priv Private data for debugging callback, may be NULL -+ * @param[out] ctx New certmap context -+ * -+ * @return -+ * - 0: success -+ * - ENOMEM: failed to allocate internal Talloc context -+ * - EINVAL: ctx is NULL -+ */ -+int sss_certmap_init(TALLOC_CTX *mem_ctx, -+ sss_certmap_ext_debug *debug, void *debug_priv, -+ struct sss_certmap_ctx **ctx); -+ -+/** -+ * @brief Free certmap context -+ * -+ * @param[in] ctx certmap context previously initialized with -+ * @ref sss_certmap_init, may be NULL -+ */ -+void sss_certmap_free_ctx(struct sss_certmap_ctx *ctx); -+ -+/** -+ * @brief Add a rule to the certmap context -+ * -+ * @param[in] ctx certmap context previously initialized with -+ * @ref sss_certmap_init -+ * @param[in] priority priority of the rule, 0 is the hightest priority, the -+ * lowest is SSS_CERTMAP_MIN_PRIO -+ * @param[in] match_rule String with the matching rule -+ * @param[in] map_rule String with the mapping rule -+ * @param[in] domains NULL-terminated string array with a list of domains -+ * the rule should be valid for, i.e. only this domains -+ * should be searched for matching users -+ * -+ * @return -+ * - 0: success -+ */ -+int sss_certmap_add_rule(struct sss_certmap_ctx *ctx, -+ uint32_t priority, const char *match_rule, -+ const char *map_rule, const char **domains); -+ -+/** -+ * @brief Check if a certificate matches any of the applied rules -+ * -+ * @param[in] ctx certmap context previously initialized with -+ * @ref sss_certmap_init -+ * @param[in] der_cert binary blog with the DER encoded certificate -+ * @param[in] der_size size of the certificate blob -+ * -+ * @return -+ * - 0: certificate matches a rule -+ * - ENOENT: certificate does not match -+ * - EINVAL: internal error -+ */ -+int sss_certmap_match_cert(struct sss_certmap_ctx *ctx, -+ const uint8_t *der_cert, size_t der_size); -+ -+/** -+ * @brief Get the LDAP filter string for a certificate -+ * -+ * @param[in] ctx certmap context previously initialized with -+ * @ref sss_certmap_init -+ * @param[in] der_cert binary blog with the DER encoded certificate -+ * @param[in] der_size size of the certificate blob -+ * @param[out] filter LDAP filter string, caller should free the data by -+ * calling sss_certmap_free_filter_and_domains -+ * @param[out] domains NULL-terminated array of strings with the domains the -+ * rule applies, caller should free the data by calling -+ * sss_certmap_free_filter_and_domains -+ * -+ * @return -+ * - 0: certificate matches a rule -+ * - ENOENT: certificate does not match -+ * - EINVAL: internal error -+ */ -+int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx, -+ const uint8_t *der_cert, size_t der_size, -+ char **filter, char ***domains); -+ -+/** -+ * @brief Free data returned by @ref sss_certmap_get_search_filter -+ * -+ * @param[in] filter LDAP filter strings returned by -+ * sss_certmap_get_search_filter -+ * @param[in] domains string array of domains returned by -+ * sss_certmap_get_search_filter -+ */ -+void sss_certmap_free_filter_and_domains(char *filter, char **domains); -+ -+/** -+ * @} -+ */ -+#endif /* _SSS_CERTMAP_H_ */ -diff --git a/src/lib/certmap/sss_certmap.pc.in b/src/lib/certmap/sss_certmap.pc.in -new file mode 100644 -index 0000000000000000000000000000000000000000..f1a4432fce8ccd5642a622ca6a8d3a7954fc7ba3 ---- /dev/null -+++ b/src/lib/certmap/sss_certmap.pc.in -@@ -0,0 +1,11 @@ -+prefix=@prefix@ -+exec_prefix=@exec_prefix@ -+libdir=@libdir@ -+includedir=@includedir@ -+ -+Name: sss_certmap -+Description: SSS certificate mapping library -+Version: @VERSION@ -+Libs: -L${libdir} -lsss_certmap -+Cflags: -+URL: https://pagure.io/SSSD/sssd/ -diff --git a/src/lib/certmap/sss_certmap_attr_names.c b/src/lib/certmap/sss_certmap_attr_names.c -new file mode 100644 -index 0000000000000000000000000000000000000000..a28a464910728cdd1f316b2b979da84f440685ea ---- /dev/null -+++ b/src/lib/certmap/sss_certmap_attr_names.c -@@ -0,0 +1,107 @@ -+/* -+ SSSD -+ -+ Library for rule based certificate to user mapping - Attribute name -+ mapping for different implementations -+ -+ Authors: -+ Sumit Bose -+ -+ Copyright (C) 2017 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 . -+*/ -+ -+/* NSS data taken from nss-utils:nss/lib/util/secoid.c and -+ * nss:nss/lib/certdb/alg1485.c */ -+ -+/* AD data taken from -+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa376556%28v=vs.85%29.aspx -+ * and wine source code dlls/crypt32/oid.c  and include/wincrypt.h . */ -+ -+#include -+#include -+#include -+ -+struct oid_attr_name_map { -+ bool nss_ad_differ; -+ const char *oid; -+ const char *nss; -+ const char *ad; -+} oid_attr_name_map[] = { -+ { false, "2.5.4.3", "CN", "CN"}, -+ { true, "2.5.4.8", "ST", "S"}, -+ { false, "2.5.4.10", "O", "O"}, -+ { false, "2.5.4.11", "OU", "OU"}, -+ { false, "2.5.4.46", "dnQualifier", "dnQualifier"}, -+ { false, "2.5.4.6", "C", "C"}, -+ { true, "2.5.4.5", "serialNumber", "SERIALNUMBER"}, -+ { false, "2.5.4.7", "L", "L"}, -+ { true, "2.5.4.12", "title", "T"}, -+ { false, "2.5.4.4", "SN", "SN"}, -+ { true, "2.5.4.42", "givenName", "G"}, -+ { true, "2.5.4.43", "initials", "I"}, -+ { true, "2.5.4.44", "generationQualifier", "OID.2.5.4.44"}, -+ { false, "0.9.2342.19200300.100.1.25", "DC", "DC"}, -+ { true, "0.9.2342.19200300.100.1.3", "MAIL", "OID,0.9.2342.19200300.100.1.3"}, -+ { true, "0.9.2342.19200300.100.1.1", "UID", "OID.0.9.2342.19200300.100.1.1"}, -+ { true, "2.5.4.13", "OID.2.5.4.13", "Description"}, -+ { true, "2.5.4.16", "postalAddress", "OID.2.5.4.16"}, -+ { true, "2.5.4.17", "postalCode", "PostalCode"}, -+ { true, "2.5.4.18", "postOfficeBox", "POBox"}, -+ { true, "2.5.4.51", "houseIdentifier", "OID.2.5.4.51"}, -+ { false, "1.2.840.113549.1.9.1", "E", "E"}, -+ { false, "2.5.4.9", "STREET", "STREET"}, -+ { true, "2.5.4.65", "pseudonym", "OID.2.5.4.65"}, -+ { true, "2.5.4.15", "businessCategory", "OID.2.5.4.15"}, -+ { true, "2.5.4.41", "name", "OID.2.5.4.41"}, -+ -+ { false, NULL, NULL, NULL} -+}; -+ -+char *check_ad_attr_name(TALLOC_CTX *mem_ctx, const char *rdn) -+{ -+ char *p; -+ size_t c; -+ size_t len; -+ -+ if (rdn == NULL) { -+ return NULL; -+ } -+ -+ p = strchr(rdn, '='); -+ if (p == NULL) { -+ return NULL; -+ } -+ -+ len = p - rdn; -+ if (len == 0) { -+ return NULL; -+ } -+ -+ for (c = 0; oid_attr_name_map[c].oid != NULL; c++) { -+ if (!oid_attr_name_map[c].nss_ad_differ) { -+ continue; -+ } -+ -+ if (strlen(oid_attr_name_map[c].nss) != len -+ || strncmp(rdn, oid_attr_name_map[c].nss, len) != 0) { -+ continue; -+ } -+ -+ return talloc_asprintf(mem_ctx, "%s%s", oid_attr_name_map[c].ad, p); -+ } -+ -+ return NULL; -+} -diff --git a/src/lib/certmap/sss_certmap_int.h b/src/lib/certmap/sss_certmap_int.h -new file mode 100644 -index 0000000000000000000000000000000000000000..28f1c596cfb5e78077b6a8e9baefa88b4900a022 ---- /dev/null -+++ b/src/lib/certmap/sss_certmap_int.h -@@ -0,0 +1,187 @@ -+/* -+ SSSD -+ -+ Library for rule based certificate to user mapping -+ -+ Authors: -+ Sumit Bose -+ -+ Copyright (C) 2017 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 -+ -+#ifndef __SSS_CERTMAP_INT_H__ -+#define __SSS_CERTMAP_INT_H__ -+ -+#define CM_DEBUG(cm_ctx, format, ...) do { \ -+ if (cm_ctx != NULL && cm_ctx->debug != NULL) { \ -+ cm_ctx->debug(cm_ctx->debug_priv, __FILE__, __LINE__, __FUNCTION__, \ -+ format, ##__VA_ARGS__); \ -+ } \ -+} while (0) -+ -+#define DEFAULT_MATCH_RULE "digitalSignatureclientAuth" -+#define DEFAULT_MAP_RULE "LDAP:(userCertificate;binary={cert!bin})" -+ -+enum san_opt { -+ SAN_OTHER_NAME = 0, -+ SAN_RFC822_NAME, -+ SAN_DNS_NAME, -+ SAN_X400_ADDRESS, -+ SAN_DIRECTORY_NAME, -+ SAN_EDIPART_NAME, -+ SAN_URI, -+ SAN_IP_ADDRESS, -+ SAN_REGISTERED_ID, -+ SAN_PKINIT, -+ SAN_NT, -+ SAN_PRINCIPAL, -+ SAN_STRING_OTHER_NAME, -+ -+ SAN_END, -+ SAN_INVALID -+}; -+ -+/* KRB5 matching rule */ -+enum relation_type { -+ relation_none = 0, -+ relation_and, -+ relation_or -+}; -+ -+struct component_list { -+ char *val; -+ regex_t regexp; -+ uint32_t ku; -+ const char **eku_oid_list; -+ enum san_opt san_opt; -+ char *str_other_name_oid; -+ uint8_t *bin_val; -+ size_t bin_val_len; -+ struct component_list *prev; -+ struct component_list *next; -+}; -+ -+struct krb5_match_rule { -+ enum relation_type r; -+ struct component_list *issuer; -+ struct component_list *subject; -+ struct component_list *ku; -+ struct component_list *eku; -+ struct component_list *san; -+}; -+ -+enum comp_type { -+ comp_none = 0, -+ comp_string, -+ comp_template -+}; -+ -+struct parsed_template { -+ char *name; -+ char *attr_name; -+ char *conversion; -+}; -+ -+struct ldap_mapping_rule_comp { -+ enum comp_type type; -+ char *val; -+ struct parsed_template *parsed_template; -+ struct ldap_mapping_rule_comp *prev; -+ struct ldap_mapping_rule_comp *next; -+}; -+ -+struct ldap_mapping_rule { -+ struct ldap_mapping_rule_comp *list; -+}; -+ -+struct match_map_rule { -+ uint32_t priority; -+ char *match_rule; -+ struct krb5_match_rule *parsed_match_rule; -+ char *map_rule; -+ struct ldap_mapping_rule *parsed_mapping_rule; -+ char **domains; -+ struct match_map_rule *prev; -+ struct match_map_rule *next; -+}; -+ -+struct priority_list { -+ uint32_t priority; -+ struct match_map_rule *rule_list; -+ struct priority_list *prev; -+ struct priority_list *next; -+}; -+ -+struct sss_certmap_ctx { -+ struct priority_list *prio_list; -+ sss_certmap_ext_debug *debug; -+ void *debug_priv; -+ struct ldap_mapping_rule *default_mapping_rule; -+}; -+ -+struct san_list { -+ enum san_opt san_opt; -+ char *val; -+ uint8_t *bin_val; -+ size_t bin_val_len; -+ char *other_name_oid; -+ char *short_name; -+ const char **rdn_list; -+ struct san_list *prev; -+ struct san_list *next; -+}; -+ -+/* key usage flags, see RFC 3280 section 4.2.1.3 */ -+#define SSS_KU_DIGITAL_SIGNATURE 0x0080 -+#define SSS_KU_NON_REPUDIATION 0x0040 -+#define SSS_KU_KEY_ENCIPHERMENT 0x0020 -+#define SSS_KU_DATA_ENCIPHERMENT 0x0010 -+#define SSS_KU_KEY_AGREEMENT 0x0008 -+#define SSS_KU_KEY_CERT_SIGN 0x0004 -+#define SSS_KU_CRL_SIGN 0x0002 -+#define SSS_KU_ENCIPHER_ONLY 0x0001 -+#define SSS_KU_DECIPHER_ONLY 0x8000 -+ -+struct sss_cert_content { -+ const char *issuer_str; -+ const char **issuer_rdn_list; -+ const char *subject_str; -+ const char **subject_rdn_list; -+ uint32_t key_usage; -+ const char **extended_key_usage_oids; -+ struct san_list *san_list; -+ -+ uint8_t *cert_der; -+ size_t cert_der_size; -+}; -+ -+int sss_cert_get_content(TALLOC_CTX *mem_ctx, -+ const uint8_t *der_blob, size_t der_size, -+ struct sss_cert_content **content); -+ -+char *check_ad_attr_name(TALLOC_CTX *mem_ctx, const char *rdn); -+ -+int parse_krb5_match_rule(struct sss_certmap_ctx *ctx, -+ const char *rule_start, -+ struct krb5_match_rule **match_rule); -+ -+int parse_ldap_mapping_rule(struct sss_certmap_ctx *ctx, -+ const char *rule_start, -+ struct ldap_mapping_rule **mapping_rule); -+#endif /* __SSS_CERTMAP_INT_H__ */ -diff --git a/src/lib/certmap/sss_certmap_krb5_match.c b/src/lib/certmap/sss_certmap_krb5_match.c -new file mode 100644 -index 0000000000000000000000000000000000000000..e40f17b8ace46e61087e0a2fa570a362a84cead2 ---- /dev/null -+++ b/src/lib/certmap/sss_certmap_krb5_match.c -@@ -0,0 +1,558 @@ -+/* -+ SSSD -+ -+ Library for rule based certificate to user mapping - KRB5 matching rules -+ -+ Authors: -+ Sumit Bose -+ -+ Copyright (C) 2017 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 "util/util.h" -+#include "util/cert.h" -+#include "util/crypto/sss_crypto.h" -+#include "lib/certmap/sss_certmap.h" -+#include "lib/certmap/sss_certmap_int.h" -+ -+static bool is_dotted_decimal(const char *s, size_t len) -+{ -+ size_t c = 0; -+ bool has_dot = false; -+ -+ if (s == NULL || !isdigit(s[c++])) { -+ return false; -+ } -+ -+ while ((len == 0 && s[c] != '\0') || (len != 0 && c < len)) { -+ if (s[c] != '.' && !isdigit(s[c])) { -+ return false; -+ } -+ if (!has_dot && s[c] == '.') { -+ has_dot = true; -+ } -+ c++; -+ } -+ -+ return (has_dot && isdigit(s[c - 1])); -+} -+ -+static int component_list_destructor(void *data) -+{ -+ struct component_list *comp = talloc_get_type(data, struct component_list); -+ -+ if (comp != NULL) { -+ regfree(&(comp->regexp)); -+ } -+ -+ return 0; -+} -+ -+/* -+ * The syntax of the MIT Kerberos style matching rules is: -+ * [KRB5:][relation-operator]component-rule ... -+ * -+ * where: -+ * -+ * relation-operator -+ * can be either &&, meaning all component rules must match, or ||, -+ * meaning only one component rule must match. The default is &&. -+ * -+ * component-rule -+ * can be one of the following. Note that there is no punctuation or whitespace between component rules. -+ * regular-expression -+ * regular-expression -+ * regular-expression -+ * extended-key-usage -+ * key-usage -+ * -+ * see man sss-certmap for more details -+ * -+ */ -+ -+static int get_comp_value(TALLOC_CTX *mem_ctx, -+ struct sss_certmap_ctx *ctx, -+ const char **cur, -+ struct component_list **_comp) -+ -+{ -+ struct component_list *comp = NULL; -+ const char *end; -+ int ret; -+ -+ comp = talloc_zero(mem_ctx, struct component_list); -+ if (comp == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ talloc_set_destructor((TALLOC_CTX *) comp, component_list_destructor); -+ -+ end = strchr(*cur, '<'); -+ -+ if (end == NULL) { -+ comp->val = talloc_strdup(comp, *cur); -+ } else { -+ comp->val = talloc_strndup(comp, *cur, end - *cur); -+ } -+ if (comp->val == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ if (*(comp->val) == '\0') { -+ CM_DEBUG(ctx, "Missing component value."); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ *cur += strlen(comp->val); -+ *_comp = comp; -+ ret = 0; -+ -+done: -+ if (ret != 0) { -+ talloc_free(comp); -+ } -+ -+ return ret; -+} -+ -+static int parse_krb5_get_eku_value(TALLOC_CTX *mem_ctx, -+ struct sss_certmap_ctx *ctx, -+ const char **cur, -+ struct component_list **_comp) -+{ -+ struct component_list *comp = NULL; -+ int ret; -+ char **eku_list; -+ size_t c; -+ size_t k; -+ const char *o; -+ size_t e = 0; -+ int eku_list_size; -+ -+ struct ext_key_usage { -+ const char *name; -+ const char *oid; -+ } ext_key_usage[] = { -+ /* RFC 3280 section 4.2.1.13 */ -+ {"serverAuth", "1.3.6.1.5.5.7.3.1"}, -+ {"clientAuth", "1.3.6.1.5.5.7.3.2"}, -+ {"codeSigning", "1.3.6.1.5.5.7.3.3"}, -+ {"emailProtection", "1.3.6.1.5.5.7.3.4"}, -+ {"timeStamping", "1.3.6.1.5.5.7.3.8"}, -+ {"OCSPSigning", "1.3.6.1.5.5.7.3.9"}, -+ -+ /* RFC 4556 section 3.2.2 */ -+ {"KPClientAuth", "1.3.6.1.5.2.3.4"}, -+ {"pkinit", "1.3.6.1.5.2.3.4"}, -+ -+ /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography*/ -+ {"msScLogin", "1.3.6.1.4.1.311.20.2.2"}, -+ -+ {NULL ,0} -+ }; -+ -+ ret = get_comp_value(mem_ctx, ctx, cur, &comp); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to parse regexp."); -+ goto done; -+ } -+ -+ ret = split_on_separator(mem_ctx, comp->val, ',', true, true, -+ &eku_list, &eku_list_size); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to split list."); -+ goto done; -+ } -+ -+ for (c = 0; eku_list[c] != NULL; c++) { -+ for (k = 0; ext_key_usage[k].name != NULL; k++) { -+CM_DEBUG(ctx, "[%s][%s].", eku_list[c], ext_key_usage[k].name); -+ if (strcasecmp(eku_list[c], ext_key_usage[k].name) == 0) { -+ if (comp->eku_oid_list == NULL) { -+ comp->eku_oid_list = talloc_zero_array(comp, const char *, -+ eku_list_size + 1); -+ if (comp->eku_oid_list == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list, -+ ext_key_usage[k].oid); -+ if (comp->eku_oid_list[e] == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ e++; -+ break; -+ } -+ } -+ -+ if (ext_key_usage[k].name == NULL) { -+ /* check for an dotted-decimal OID */ -+ if (*(eku_list[c]) != '.') { -+ o = eku_list[c]; -+ if (is_dotted_decimal(o, 0)) { -+ /* looks like a OID, only '.' and digits */ -+ comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list, -+ eku_list[c]); -+ if (comp->eku_oid_list[e] == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ e++; -+ continue; -+ } -+ } -+ CM_DEBUG(ctx, "No matching extended key usage found."); -+ ret = EINVAL; -+ goto done; -+ } -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *_comp = comp; -+ } else { -+ talloc_free(comp); -+ } -+ -+ return ret; -+} -+ -+static int parse_krb5_get_ku_value(TALLOC_CTX *mem_ctx, -+ struct sss_certmap_ctx *ctx, -+ const char **cur, -+ struct component_list **_comp) -+{ -+ struct component_list *comp = NULL; -+ int ret; -+ char **ku_list; -+ size_t c; -+ size_t k; -+ -+ struct key_usage { -+ const char *name; -+ uint32_t flag; -+ } key_usage[] = { -+ {"digitalSignature" , SSS_KU_DIGITAL_SIGNATURE}, -+ {"nonRepudiation" , SSS_KU_NON_REPUDIATION}, -+ {"keyEncipherment" , SSS_KU_KEY_ENCIPHERMENT}, -+ {"dataEncipherment" , SSS_KU_DATA_ENCIPHERMENT}, -+ {"keyAgreement" , SSS_KU_KEY_AGREEMENT}, -+ {"keyCertSign" , SSS_KU_KEY_CERT_SIGN}, -+ {"cRLSign" , SSS_KU_CRL_SIGN}, -+ {"encipherOnly" , SSS_KU_ENCIPHER_ONLY}, -+ {"decipherOnly" , SSS_KU_DECIPHER_ONLY}, -+ {NULL ,0} -+ }; -+ -+ -+ ret = get_comp_value(mem_ctx, ctx, cur, &comp); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to get value."); -+ goto done; -+ } -+ -+ ret = split_on_separator(mem_ctx, comp->val, ',', true, true, -+ &ku_list, NULL); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to split list."); -+ goto done; -+ } -+ -+ for (c = 0; ku_list[c] != NULL; c++) { -+ for (k = 0; key_usage[k].name != NULL; k++) { -+ if (strcasecmp(ku_list[c], key_usage[k].name) == 0) { -+ comp->ku |= key_usage[k].flag; -+ break; -+ } -+ } -+ -+ if (key_usage[k].name == NULL) { -+ /* FIXME: add check for numerical ku */ -+ CM_DEBUG(ctx, "No matching key usage found."); -+ ret = EINVAL; -+ goto done; -+ } -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *_comp = comp; -+ } else { -+ talloc_free(comp); -+ } -+ -+ return ret; -+} -+ -+static int parse_krb5_get_component_value(TALLOC_CTX *mem_ctx, -+ struct sss_certmap_ctx *ctx, -+ const char **cur, -+ struct component_list **_comp) -+{ -+ struct component_list *comp = NULL; -+ int ret; -+ -+ ret = get_comp_value(mem_ctx, ctx, cur, &comp); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to parse regexp."); -+ goto done; -+ } -+ -+ ret = regcomp(&(comp->regexp), comp->val, REG_EXTENDED); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to parse regexp."); -+ goto done; -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *_comp = comp; -+ } else { -+ talloc_free(comp); -+ } -+ -+ return ret; -+} -+ -+struct san_name { -+ const char *name; -+ enum san_opt san_opt; -+ bool is_string; -+} san_names[] = { -+ /* https://www.ietf.org/rfc/rfc3280.txt section 4.2.1.7 */ -+ {"otherName", SAN_OTHER_NAME, false}, -+ {"rfc822Name", SAN_RFC822_NAME,true}, -+ {"dNSName", SAN_DNS_NAME, true}, -+ {"x400Address", SAN_X400_ADDRESS, false}, -+ {"directoryName", SAN_DIRECTORY_NAME, true}, -+ {"ediPartyName", SAN_EDIPART_NAME, false}, -+ {"uniformResourceIdentifier", SAN_URI, true}, -+ {"iPAddress", SAN_IP_ADDRESS, true}, -+ {"registeredID", SAN_REGISTERED_ID, true}, -+ /* https://www.ietf.org/rfc/rfc4556.txt section 3.2.2 */ -+ {"pkinitSAN", SAN_PKINIT, true}, -+ /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography */ -+ {"ntPrincipalName", SAN_NT, true}, -+ /* both previous principal types */ -+ {"Principal", SAN_PRINCIPAL, true}, -+ {"stringOtherName", SAN_STRING_OTHER_NAME, true}, -+ {NULL, SAN_END, false} -+}; -+ -+static int parse_krb5_get_san_option(TALLOC_CTX *mem_ctx, -+ struct sss_certmap_ctx *ctx, -+ const char **cur, -+ enum san_opt *option, -+ char **str_other_name_oid) -+{ -+ char *end; -+ size_t c; -+ size_t len; -+ -+ end = strchr(*cur, '>'); -+ if (end == NULL) { -+ CM_DEBUG(ctx, "Failed to parse SAN option."); -+ return EINVAL; -+ } -+ -+ len = end - *cur; -+ -+ if (len == 0) { -+ c= SAN_PRINCIPAL; -+ } else { -+ for (c = 0; san_names[c].name != NULL; c++) { -+ if (strncasecmp(*cur, san_names[c].name, len) == 0) { -+ break; -+ } -+ } -+ if (san_names[c].name == NULL) { -+ if (is_dotted_decimal(*cur, len)) { -+ c = SAN_STRING_OTHER_NAME; -+ *str_other_name_oid = talloc_strndup(mem_ctx, *cur, len); -+ if (*str_other_name_oid == NULL) { -+ CM_DEBUG(ctx, "talloc_strndup failed."); -+ return ENOMEM; -+ } -+ } else { -+ CM_DEBUG(ctx, "Unknown SAN option."); -+ return EINVAL; -+ } -+ } -+ } -+ -+ *option = san_names[c].san_opt; -+ *cur = end + 1; -+ -+ return 0; -+} -+ -+static int parse_krb5_get_san_value(TALLOC_CTX *mem_ctx, -+ struct sss_certmap_ctx *ctx, -+ const char **cur, -+ struct component_list **_comp) -+{ -+ struct component_list *comp = NULL; -+ enum san_opt san_opt = SAN_PRINCIPAL; -+ int ret; -+ char *str_other_name_oid = NULL; -+ -+ if (*(*cur - 1) == ':') { -+ ret = parse_krb5_get_san_option(mem_ctx, ctx, cur, &san_opt, -+ &str_other_name_oid); -+ if (ret != 0) { -+ goto done; -+ } -+ } -+ -+ if (san_names[san_opt].is_string) { -+ ret = parse_krb5_get_component_value(mem_ctx, ctx, cur, &comp); -+ if (ret != 0) { -+ goto done; -+ } -+ } else { -+ ret = get_comp_value(mem_ctx, ctx, cur, &comp); -+ if (ret != 0) { -+ goto done; -+ } -+ -+ if (comp->val != NULL) { -+ comp->bin_val = sss_base64_decode(comp, comp->val, -+ &comp->bin_val_len); -+ /* for some reasons the NSS version of sss_base64_decode might -+ * return a non-NULL value on error but len is still 0, so better -+ * check both. */ -+ if (comp->bin_val == NULL || comp->bin_val_len == 0) { -+ CM_DEBUG(ctx, "Base64 decode failed."); -+ ret = EINVAL; -+ goto done; -+ } -+ } -+ } -+ comp->san_opt = san_opt; -+ -+done: -+ if (ret == 0) { -+ comp->str_other_name_oid = talloc_steal(comp, str_other_name_oid); -+ *_comp = comp; -+ } else { -+ talloc_free(comp); -+ talloc_free(str_other_name_oid); -+ } -+ -+ return ret; -+} -+ -+int parse_krb5_match_rule(struct sss_certmap_ctx *ctx, -+ const char *rule_start, -+ struct krb5_match_rule **match_rule) -+{ -+ const char *cur; -+ struct krb5_match_rule *rule; -+ struct component_list *comp; -+ int ret; -+ -+ rule = talloc_zero(ctx, struct krb5_match_rule); -+ if (rule == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ cur = rule_start; -+ /* check relation */ -+ if (strncmp(cur, "&&", 2) == 0) { -+ rule->r = relation_and; -+ cur += 2; -+ } else if (strncmp(cur, "||", 2) == 0) { -+ rule->r = relation_or; -+ cur += 2; -+ } else { -+ rule->r = relation_and; -+ } -+ -+ while (*cur != '\0') { -+ /* new component must start with '<' */ -+ if (*cur != '<') { -+ CM_DEBUG(ctx, "Invalid KRB5 matching rule."); -+ ret = EINVAL; -+ goto done; -+ } -+ cur++; -+ -+ if (strncmp(cur, "ISSUER>", 7) == 0) { -+ cur += 7; -+ ret = parse_krb5_get_component_value(rule, ctx, &cur, &comp); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(rule->issuer, comp); -+ } else if (strncmp(cur, "SUBJECT>", 8) == 0) { -+ cur += 8; -+ ret = parse_krb5_get_component_value(rule, ctx, &cur, &comp); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(rule->subject, comp); -+ } else if (strncmp(cur, "KU>", 3) == 0) { -+ cur += 3; -+ ret = parse_krb5_get_ku_value(rule, ctx, &cur, &comp); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(rule->ku, comp); -+ } else if (strncmp(cur, "EKU>", 4) == 0) { -+ cur += 4; -+ ret = parse_krb5_get_eku_value(rule, ctx, &cur, &comp); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(rule->eku, comp); -+ } else if (strncmp(cur, "SAN>", 4) == 0 -+ || strncmp(cur, "SAN:", 4) == 0) { -+ cur += 4; -+ ret = parse_krb5_get_san_value(rule, ctx, &cur, &comp); -+ if (ret != 0) { -+ goto done; -+ } -+ DLIST_ADD(rule->san, comp); -+ } else { -+ CM_DEBUG(ctx, "Invalid KRB5 matching rule."); -+ ret = EINVAL; -+ goto done; -+ } -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *match_rule = rule; -+ } else { -+ talloc_free(rule); -+ } -+ -+ return ret; -+} -diff --git a/src/lib/certmap/sss_certmap_ldap_mapping.c b/src/lib/certmap/sss_certmap_ldap_mapping.c -new file mode 100644 -index 0000000000000000000000000000000000000000..c64c05b311f043b4d70f98f718780601c3e6a002 ---- /dev/null -+++ b/src/lib/certmap/sss_certmap_ldap_mapping.c -@@ -0,0 +1,367 @@ -+/* -+ SSSD -+ -+ Library for rule based certificate to user mapping - LDAP mapping rules -+ -+ Authors: -+ Sumit Bose -+ -+ Copyright (C) 2017 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 "util/util.h" -+#include "util/cert.h" -+#include "util/crypto/sss_crypto.h" -+#include "lib/certmap/sss_certmap.h" -+#include "lib/certmap/sss_certmap_int.h" -+struct template_table { -+ const char *name; -+ const char **attr_name; -+ const char **conversion; -+}; -+ -+const char *empty[] = {NULL}; -+const char *name_attr[] = {"short_name", NULL}; -+const char *x500_conv[] = {"ad_x500", "ad", "ad_ldap", -+ "nss_x500", "nss", "nss_ldap", NULL}; -+const char *bin_conv[] = {"bin", "base64", NULL}; -+ -+struct template_table template_table[] = { -+ {"issuer_dn", empty, x500_conv}, -+ {"subject_dn", empty, x500_conv}, -+ {"cert", empty, bin_conv}, -+ {"subject_rfc822_name", name_attr, empty}, -+ {"subject_dns_name", name_attr, empty}, -+ {"subject_x400_address", empty, empty}, -+ {"subject_directory_name", empty, empty}, -+ {"subject_ediparty_name", empty, empty}, -+ {"subject_uri", empty, empty}, -+ {"subject_ip_address", empty, empty}, -+ {"subject_registered_id", empty, empty}, -+ {"subject_pkinit_principal", name_attr, empty}, -+ {"subject_nt_principal", name_attr, empty}, -+ {"subject_principal", name_attr, empty}, -+ {NULL, NULL, NULL}}; -+ -+static int check_parsed_template(struct sss_certmap_ctx *ctx, -+ struct parsed_template *parsed) -+{ -+ size_t n; -+ size_t a; -+ size_t c; -+ bool attr_name_valid = false; -+ bool conversion_valid = false; -+ -+ for (n = 0; template_table[n].name != NULL; n++) { -+ if (strcmp(template_table[n].name, parsed->name) != 0) { -+ continue; -+ } -+ -+ if (parsed->attr_name != NULL) { -+ for (a = 0; template_table[n].attr_name[a] != NULL; a++) { -+ if (strcmp(template_table[n].attr_name[a], -+ parsed->attr_name) == 0) { -+ attr_name_valid = true; -+ break; -+ } -+ } -+ } else { -+ attr_name_valid = true; -+ } -+ -+ if (parsed->conversion != NULL) { -+ for (c = 0; template_table[n].conversion[c] != NULL; c++) { -+ if (strcmp(template_table[n].conversion[c], -+ parsed->conversion) == 0) { -+ conversion_valid = true; -+ break; -+ } -+ } -+ } else { -+ conversion_valid = true; -+ } -+ -+ if (attr_name_valid && conversion_valid) { -+ return 0; -+ } -+ } -+ -+ return EINVAL; -+} -+ -+static int parse_template(TALLOC_CTX *mem_ctx, struct sss_certmap_ctx *ctx, -+ const char *template, -+ struct parsed_template **parsed_template) -+{ -+ int ret; -+ struct parsed_template *parsed = NULL; -+ const char *dot; -+ const char *excl; -+ const char *p; -+ -+ parsed = talloc_zero(mem_ctx, struct parsed_template); -+ if (parsed == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ dot = strchr(template, '.'); -+ if (dot != NULL) { -+ p = strchr(dot + 1, '.'); -+ if (p != NULL) { -+ CM_DEBUG(ctx, "Only one '.' allowed in template."); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ if (dot == template) { -+ CM_DEBUG(ctx, "Missing name in template."); -+ ret = EINVAL; -+ goto done; -+ } -+ } -+ -+ excl = strchr(template, '!'); -+ if (excl != NULL) { -+ p = strchr(excl + 1, '!'); -+ if (p != NULL) { -+ CM_DEBUG(ctx, "Only one '!' allowed in template."); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ if (excl == template) { -+ CM_DEBUG(ctx, "Missing name in template."); -+ ret = EINVAL; -+ goto done; -+ } -+ } -+ -+ if (excl != NULL && excl[1] != '\0') { -+ parsed->conversion = talloc_strdup(parsed, excl + 1); -+ if (parsed->conversion == NULL) { -+ CM_DEBUG(ctx, "Memory allocation failed."); -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ if (dot != NULL && dot[1] != '\0' && dot[1] != '!') { -+ if (excl == NULL) { -+ parsed->attr_name = talloc_strdup(parsed, dot + 1); -+ } else { -+ parsed->attr_name = talloc_strndup(parsed, dot + 1, -+ (excl - dot - 1)); -+ } -+ if (parsed->attr_name == NULL) { -+ CM_DEBUG(ctx, "Memory allocation failed."); -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ if (dot != NULL) { -+ parsed->name = talloc_strndup(parsed, template, (dot - template)); -+ } else if (excl != NULL) { -+ parsed->name = talloc_strndup(parsed, template, (excl - template)); -+ } else { -+ parsed->name = talloc_strdup(parsed, template); -+ } -+ if (parsed->name == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = check_parsed_template(ctx, parsed); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Parse template invalid."); -+ goto done; -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *parsed_template = parsed; -+ } else { -+ talloc_free(parsed); -+ } -+ -+ return ret; -+} -+ -+static int add_comp(struct sss_certmap_ctx *ctx, struct ldap_mapping_rule *rule, -+ const char *string, enum comp_type type) -+{ -+ int ret; -+ struct ldap_mapping_rule_comp *comp; -+ -+ comp = talloc_zero(rule, struct ldap_mapping_rule_comp); -+ if (comp == NULL) { -+ return ENOMEM; -+ } -+ -+ comp->type = type; -+ comp->val = talloc_strdup(comp, string); -+ if (comp->val == NULL) { -+ talloc_free(comp); -+ return ENOMEM; -+ } -+ -+ if (type == comp_template) { -+ ret = parse_template(comp, ctx, string, &comp->parsed_template); -+ if (ret != 0) { -+ talloc_free(comp); -+ return ret; -+ } -+ } -+ -+ DLIST_ADD_END(rule->list, comp, struct ldap_mapping_rule_comp *); -+ -+ return 0; -+} -+ -+static int add_string(struct sss_certmap_ctx *ctx, -+ struct ldap_mapping_rule *rule, const char *string) -+{ -+ return add_comp(ctx, rule, string, comp_string); -+} -+ -+static int add_template(struct sss_certmap_ctx *ctx, -+ struct ldap_mapping_rule *rule, const char *string) -+{ -+ return add_comp(ctx, rule, string, comp_template); -+} -+ -+int parse_ldap_mapping_rule(struct sss_certmap_ctx *ctx, -+ const char *rule_start, -+ struct ldap_mapping_rule **mapping_rule) -+{ -+ size_t c; -+ const char *cur; -+ char *tmp_string = NULL; -+ size_t tmp_string_size; -+ struct ldap_mapping_rule *rule = NULL; -+ int ret; -+ bool in_template = false; -+ -+ rule = talloc_zero(ctx, struct ldap_mapping_rule); -+ if (rule == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ tmp_string_size = strlen(rule_start) + 1; -+ tmp_string = talloc_zero_size(ctx, tmp_string_size); -+ if (tmp_string == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ cur = rule_start; -+ c = 0; -+ -+ while (*cur != '\0') { -+ if (c > tmp_string_size) { -+ CM_DEBUG(ctx, "Cannot parse mapping rule."); -+ ret = EIO; -+ goto done; -+ } -+ switch (*cur) { -+ case '{': -+ if (in_template) { -+ CM_DEBUG(ctx, "'{' not allowed in templates."); -+ ret = EINVAL; -+ goto done; -+ } -+ if (cur[1] == '{') { -+ /* Add only a single '{' to the output */ -+ tmp_string[c] = '{'; -+ c++; -+ cur += 2; -+ } else { -+ if (c != 0) { -+ ret = add_string(ctx, rule, tmp_string); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to add string."); -+ ret = EINVAL; -+ goto done; -+ } -+ memset(tmp_string, 0, tmp_string_size); -+ c = 0; -+ } -+ cur++; -+ in_template = true; -+ } -+ break; -+ case '}': -+ if (cur[1] == '}') { -+ if (in_template) { -+ CM_DEBUG(ctx, "'}}' not allowed in templates."); -+ ret = EINVAL; -+ goto done; -+ } else { -+ /* Add only a single '}' to the output */ -+ tmp_string[c] = '}'; -+ c++; -+ cur += 2; -+ } -+ } else { -+ ret = add_template(ctx, rule, tmp_string); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to add template."); -+ ret = EINVAL; -+ goto done; -+ } -+ memset(tmp_string, 0, tmp_string_size); -+ c = 0; -+ cur++; -+ in_template = false; -+ } -+ break; -+ default: -+ tmp_string[c] = *cur; -+ c++; -+ cur++; -+ } -+ } -+ if (in_template) { -+ CM_DEBUG(ctx, "Rule ended inside template."); -+ ret = EINVAL; -+ goto done; -+ } -+ if (c != 0) { -+ ret = add_string(ctx, rule, tmp_string); -+ if (ret != 0) { -+ CM_DEBUG(ctx, "Failed to add string."); -+ ret = EINVAL; -+ goto done; -+ } -+ } -+ -+ ret = 0; -+ -+done: -+ if (ret == 0) { -+ *mapping_rule = rule; -+ } else { -+ talloc_free(rule); -+ } -+ -+ talloc_free(tmp_string); -+ -+ return ret; -+} -diff --git a/src/man/Makefile.am b/src/man/Makefile.am -index 215ce693b56e74db394dbc238c03c87f5f6efe99..142d6e2743f814294e3d92c8342070b8230bb3e5 100644 ---- a/src/man/Makefile.am -+++ b/src/man/Makefile.am -@@ -59,7 +59,7 @@ man_MANS = \ - sss_useradd.8 sss_userdel.8 sss_usermod.8 \ - sss_groupadd.8 sss_groupdel.8 sss_groupmod.8 \ - sssd.8 sssd.conf.5 sssd-ldap.5 \ -- sssd-krb5.5 sssd-simple.5 \ -+ sssd-krb5.5 sssd-simple.5 sss-certmap.5 \ - sssd_krb5_locator_plugin.8 sss_groupshow.8 \ - pam_sss.8 sss_obfuscate.8 sss_cache.8 sss_debuglevel.8 sss_seed.8 \ - sss_override.8 idmap_sss.8 sssctl.8 \ -diff --git a/src/man/po/po4a.cfg b/src/man/po/po4a.cfg -index ffcf9a2793da3c0115bc846744ccb9592a9a68ef..d1f6ac39f841c61ae3d2393fb3402dc21b9cbd69 100644 ---- a/src/man/po/po4a.cfg -+++ b/src/man/po/po4a.cfg -@@ -6,6 +6,7 @@ - [type:docbook] pam_sss.8.xml $lang:$(builddir)/$lang/pam_sss.8.xml - [type:docbook] sssd_krb5_locator_plugin.8.xml $lang:$(builddir)/$lang/sssd_krb5_locator_plugin.8.xml - [type:docbook] sssd-simple.5.xml $lang:$(builddir)/$lang/sssd-simple.5.xml -+[type:docbook] sss-certmap.5.xml $lang:$(builddir)/$lang/sss-certmap.5.xml - [type:docbook] sssd-ipa.5.xml $lang:$(builddir)/$lang/sssd-ipa.5.xml - [type:docbook] sssd-ad.5.xml $lang:$(builddir)/$lang/sssd-ad.5.xml - [type:docbook] sssd-sudo.5.xml $lang:$(builddir)/$lang/sssd-sudo.5.xml -diff --git a/src/man/sss-certmap.5.xml b/src/man/sss-certmap.5.xml -new file mode 100644 -index 0000000000000000000000000000000000000000..bbe68509f2222613a7ed69599519d7fca0506df0 ---- /dev/null -+++ b/src/man/sss-certmap.5.xml -@@ -0,0 +1,600 @@ -+ -+ -+ -+SSSD Manual pages -+ -+ -+ -+ -+ sss-certmap -+ 5 -+ File Formats and Conventions -+ -+ -+ -+ sss-certmap -+ SSSD Certificate Matching and Mapping Rules -+ -+ -+ -+ DESCRIPTION -+ -+ The manual page describes the rules which can be used by SSSD and -+ other components to match X.509 certificates and map them to -+ accounts. -+ -+ -+ Each rule has four components, a priority, a -+ matching rule, a mapping rule and a -+ domain list. All components are optional. A missing -+ priority will add the rule with the lowest priority. -+ The default matching rule will match certificates with -+ the digitalSignature key usage and clientAuth extended key usage. If -+ the mapping rule is empty the certificates will be -+ searched in the userCertificate attribute as DER encoded binary. If -+ no domains are given only the local domain will be searched. -+ -+ -+ -+ -+ RULE COMPONENTS -+ -+ PRIORITY -+ -+ The rules are process by priority while the number '0' (zero) -+ indicates the highest priority. The higher the number the lower is -+ the priority. A missing value indicates the lowest priority. -+ -+ -+ Internally the priority is treated as unsigned 32bit integer, using -+ a priority value larger than 4294967295 will cause an error. -+ -+ -+ -+ MATCHING RULE -+ -+ The matching rule is used to select a certificate to which the -+ mapping rule should be applied. It uses a system similar to the one -+ used by pkinit_cert_match option of MIT Kerberos. It -+ consists of a keyword enclosed by '<' and '>' which identified -+ a certain part of the certificate and a pattern which should be -+ found for the rule to match. Multiple keyword pattern pairs can be -+ either joined with '&&' (and) or '||' (or). -+ -+ -+ The available options are: -+ -+ -+ <SUBJECT>regular-expression -+ -+ -+ With this a part or the whole subject name of the -+ certificate can be matched. For the matching POSIX -+ Extended Regular Expression syntax is used, see regex(7) -+ for details. -+ -+ -+ For the matching the subject name stored in the -+ certificate in DER encoded ASN.1 is converted into a -+ string according to RFC 4514. This means the most -+ specific name component comes first. Please note that -+ not all possible attribute names are covered by RFC -+ 4514. The names included are 'CN', 'L', 'ST', 'O', -+ 'OU', 'C', 'STREET', 'DC' and 'UID'. Other attribute -+ names might be shown differently on different platform -+ and by different tools. To avoid confusion those -+ attribute names are best not used or covered by a -+ suitable regular-expression. -+ -+ -+ Example: <SUBJECT>.*,DC=MY,DC=DOMAIN -+ -+ -+ -+ -+ <ISSUER>regular-expression -+ -+ -+ With this a part or the whole issuer name of the -+ certificate can be matched. All comments for -+ <SUBJECT> apply her as well. -+ -+ -+ Example: <ISSUER>^CN=My-CA,DC=MY,DC=DOMAIN$ -+ -+ -+ -+ -+ <KU>key-usage -+ -+ -+ This option can be used to specify which key usage -+ values the certificate should have. The following value -+ can be used in a comma separate list: -+ -+ digitalSignature -+ nonRepudiation -+ keyEncipherment -+ dataEncipherment -+ keyAgreement -+ keyCertSign -+ cRLSign -+ encipherOnly -+ decipherOnly -+ -+ -+ -+ A numerical value in the range of a 32bit unsigned -+ integer can be used as well to cover special use cases. -+ -+ -+ Example: <KU>digitalSignature,keyEncipherment -+ -+ -+ -+ -+ <EKU>extended-key-usage -+ -+ -+ This option can be used to specify which extended key -+ usage the certificate should have. The following value -+ can be used in a comma separated list: -+ -+ serverAuth -+ clientAuth -+ codeSigning -+ emailProtection -+ timeStamping -+ OCSPSigning -+ KPClientAuth -+ pkinit -+ msScLogin -+ -+ -+ -+ Extended key usages which are not listed above can be -+ specified with their OID in dotted-decimal notation. -+ -+ -+ Example: <EKU>clientAuth,1.3.6.1.5.2.3.4 -+ -+ -+ -+ -+ <SAN>regular-expression -+ -+ -+ To be compatible with the usage of MIT Kerberos this -+ option will match the Kerberos principals in the PKINIT -+ or AD NT Principal SAN as <SAN:Principal> does. -+ -+ -+ Example: <SAN>.*@MY\.REALM -+ -+ -+ -+ -+ <SAN:Principal>regular-expression -+ -+ -+ Match the Kerberos principals in the PKINIT or AD NT -+ Principal SAN. -+ -+ -+ Example: <SAN:Principal>.*@MY\.REALM -+ -+ -+ -+ -+ <SAN:ntPrincipalName>regular-expression -+ -+ -+ Match the Kerberos principals from the AD NT Principal -+ SAN. -+ -+ -+ Example: <SAN:ntPrincipalName>.*@MY.AD.REALM -+ -+ -+ -+ -+ <SAN:pkinit>regular-expression -+ -+ -+ Match the Kerberos principals from the PKINIT SAN. -+ -+ -+ Example: <SAN:ntPrincipalName>.*@MY\.PKINIT\.REALM -+ -+ -+ -+ -+ <SAN:dotted-decimal-oid>regular-expression -+ -+ -+ Take the value of the otherName SAN component given by -+ the OID in dotted-decimal notation, interpret it as -+ string and try to match it against the regular -+ expression. -+ -+ -+ Example: <SAN:1.2.3.4>test -+ -+ -+ -+ -+ <SAN:otherName>base64-string -+ -+ -+ Do a binary match with the base64 encoded blob against -+ all otherName SAN components. With this option it is -+ possible to match against custom otherName components -+ with special encodings which could not be treated as -+ strings. -+ -+ -+ Example: <SAN:otherName>MTIz -+ -+ -+ -+ -+ <SAN:rfc822Name>regular-expression -+ -+ -+ Match the value of the rfc822Name SAN. -+ -+ -+ Example: <SAN:rfc822Name>.*@email\.domain -+ -+ -+ -+ -+ <SAN:dNSName>regular-expression -+ -+ -+ Match the value of the dNSName SAN. -+ -+ -+ Example: <SAN:dNSName>.*\.my\.dns\.domain -+ -+ -+ -+ -+ <SAN:x400Address>base64-string -+ -+ -+ Binary match the value of the x400Address SAN. -+ -+ -+ Example: <SAN:x400Address>MTIz -+ -+ -+ -+ -+ <SAN:directoryName>regular-expression -+ -+ -+ Match the value of the directoryName SAN. The same -+ comments as given for <ISSUER> and <SUBJECT> -+ apply here as well. -+ -+ -+ Example: <SAN:directoryName>.*,DC=com -+ -+ -+ -+ -+ <SAN:ediPartyName>base64-string -+ -+ -+ Binary match the value of the ediPartyName SAN. -+ -+ -+ Example: <SAN:ediPartyName>MTIz -+ -+ -+ -+ -+ <SAN:uniformResourceIdentifier>regular-expression -+ -+ -+ Match the value of the uniformResourceIdentifier SAN. -+ -+ -+ Example: <SAN:uniformResourceIdentifier>URN:.* -+ -+ -+ -+ -+ <SAN:iPAddress>regular-expression -+ -+ -+ Match the value of the iPAddress SAN. -+ -+ -+ Example: <SAN:iPAddress>192\.168\..* -+ -+ -+ -+ -+ <SAN:registeredID>regular-expression -+ -+ -+ Match the value of the registeredID SAN as -+ dotted-decimal string. -+ -+ -+ Example: <SAN:registeredID>1\.2\.3\..* -+ -+ -+ -+ -+ -+ -+ -+ MAPPING RULE -+ -+ The mapping rule is used to associate a certificate with one or more -+ accounts. A Smartcard with the certificate and the matching private -+ key can then be used to authenticate as one of those accounts. -+ -+ -+ Currently SSSD basically only supports LDAP to lookup user -+ information (the exception is the proxy provider which is not of -+ relevance here). Because of this the mapping rule is based on LDAP -+ search filter syntax with templates to add certificate content to -+ the filter. It is expected that the filter will only contain the -+ specific data needed for the mapping an that the caller will embed -+ it in another filter to do the actual search. Because of this the -+ filter string should start and stop with '(' and ')' respectively. -+ -+ -+ In general it is recommended to use attributes from the certificate -+ and add them to special attributes to the LDAP user object. E.g. the -+ 'altSecurityIdentities' attribute in AD or the 'ipaCertMapData' -+ attribute for IPA can be used. -+ -+ -+ This should be preferred to read user specific data from the -+ certificate like e.g. an email address and search for it in the LDAP -+ server. The reason is that the user specific data in LDAP might -+ change for various reasons would would break the mapping. On the -+ other hand it would be hard to break the mapping on purpose for a -+ specific user. -+ -+ -+ The templates to add certificate data to the search filter are based -+ on Python-style formatting strings. They consists of a keyword in -+ curly braces with an optional sub-component specifier separated by a -+ '.' or an optional conversion/formatting option separated by a '!'. -+ Allowed values are: -+ -+ -+ {issuer_dn[!((ad|ad_x500)|ad_ldap|nss_x500|(nss|nss_ldap))]} -+ -+ -+ This template will add the full issuer DN converted to a -+ string according to RFC 4514. If X.500 ordering (most -+ specific RDN comes last) an option with the '_x500' -+ prefix should be used. -+ -+ -+ The conversion options starting with 'ad_' will use -+ attribute names as used by AD, e.g. 'S' instead of 'ST'. -+ -+ -+ The conversion options starting with 'nss_' will use -+ attribute names as used by NSS. -+ -+ -+ The default conversion option is 'nss', i.e. attribute -+ names according to NSS and LDAP/RFC 4514 ordering. -+ -+ -+ Example: (ipacertmapdata=X509:<I>{issuer_dn!ad}<S>{subject_dn!ad}) -+ -+ -+ -+ -+ {subject_dn[!((ad|ad_x500)|ad_ldap|nss_x500|(nss|nss_ldap))]} -+ -+ -+ This template will add the full subject DN converted to -+ string according to RFC 4514. If X.500 ordering (most -+ specific RDN comes last) an option with the '_x500' -+ prefix should be used. -+ -+ -+ The conversion options starting with 'ad_' will use -+ attribute names as used by AD, e.g. 'S' instead of 'ST'. -+ -+ -+ The conversion options starting with 'nss_' will use -+ attribute names as used by NSS. -+ -+ -+ The default conversion option is 'nss', i.e. attribute -+ names according to NSS and LDAP/RFC 4514 ordering. -+ -+ -+ Example: (ipacertmapdata=X509:<I>{issuer_dn!nss_x500}<S>{subject_dn!nss_x500}) -+ -+ -+ -+ -+ {cert[!(bin|base64)]} -+ -+ -+ This template will add the whole DER encoded certificate -+ as a string to the search filter. Depending on the -+ conversion option the binary certificate is either -+ converted to an escaped hex sequence '\xx' or base64. -+ The escaped hex sequence is the default and can e.g. be -+ used with the LDAP attribute 'userCertificate;binary'. -+ -+ -+ Example: (userCertificate;binary={cert!bin}) -+ -+ -+ -+ -+ {subject_principal[.short_name]} -+ -+ -+ This template will add the Kerberos principal which is -+ taken either from the SAN used by pkinit or the one used -+ by AD. The 'short_name' component represent the first -+ part of the principal before the '@' sign. -+ -+ -+ Example: (|(userPrincipal={subject_principal})(samAccountName={subject_principal.short_name})) -+ -+ -+ -+ -+ {subject_pkinit_principal[.short_name]} -+ -+ -+ This template will add the Kerberos principal which is -+ given by then SAN used by pkinit. The 'short_name' -+ component represent the first part of the principal -+ before the '@' sign. -+ -+ -+ Example: (|(userPrincipal={subject_pkinit_principal})(uid={subject_pkinit_principal.short_name})) -+ -+ -+ -+ -+ {subject_nt_principal[.short_name]} -+ -+ -+ This template will add the Kerberos principal which is -+ given by then SAN used by AD. The 'short_name' component -+ represent the first part of the principal before the '@' -+ sign. -+ -+ -+ Example: (|(userPrincipal={subject_principal})(samAccountName={subject_principal.short_name})) -+ -+ -+ -+ -+ {subject_rfc822_name[.short_name]} -+ -+ -+ This template will add the string which is stored in the -+ rfc822Name component of the SAN, typically an email -+ address. The 'short_name' component represent the first -+ part of the address before the '@' sign. -+ -+ -+ Example: (|(mail={subject_rfc822_name})(uid={subject_rfc822_name.short_name})) -+ -+ -+ -+ -+ {subject_dns_name[.short_name]} -+ -+ -+ This template will add the string which is stored in the -+ dNSName component of the SAN, typically a fully-qualified host name. -+ The 'short_name' component represent the first -+ part of the name before the first '.' sign. -+ -+ -+ Example: (|(fqdn={subject_dns_name})(host={subject_dns_name.short_name})) -+ -+ -+ -+ -+ {subject_uri} -+ -+ -+ This template will add the string which is stored in the -+ uniformResourceIdentifier component of the SAN. -+ -+ -+ Example: (uri={subject_uri}) -+ -+ -+ -+ -+ {subject_ip_address} -+ -+ -+ This template will add the string which is stored in the -+ iPAddress component of the SAN. -+ -+ -+ Example: (ip={subject_ip_address}) -+ -+ -+ -+ -+ {subject_x400_address} -+ -+ -+ This template will add the value which is stored in the -+ x400Address component of the SAN as escaped hex -+ sequence. -+ -+ -+ Example: (attr:binary={subject_x400_address}) -+ -+ -+ -+ -+ {subject_directory_name[!((ad|ad_x500)|ad_ldap|nss_x500|(nss|nss_ldap))]} -+ -+ -+ This template will add the DN string of the value which -+ is stored in the directoryName component of the SAN. -+ -+ -+ Example: (orig_dn={subject_directory_name}) -+ -+ -+ -+ -+ {subject_ediparty_name} -+ -+ -+ This template will add the value which is stored in the -+ ediPartyName component of the SAN as escaped hex -+ sequence. -+ -+ -+ Example: (attr:binary={subject_ediparty_name}) -+ -+ -+ -+ -+ {subject_registered_id} -+ -+ -+ This template will add the OID which is stored in the -+ registeredID component of the SAN as as dotted-decimal -+ string. -+ -+ -+ Example: (oid={subject_registered_id}) -+ -+ -+ -+ -+ -+ -+ -+ DOMAIN LIST -+ -+ If the domain list is not empty users mapped to a given certificate -+ are not only searched in the local domain but in the listed domains -+ as well as long as they are know by SSSD. Domains not know to SSSD -+ will be ignored. -+ -+ -+ -+ -+ -diff --git a/src/tests/cmocka/test_certmap.c b/src/tests/cmocka/test_certmap.c -new file mode 100644 -index 0000000000000000000000000000000000000000..c998443d086eaa72cc2a05c38ddfc5ba590a1ce7 ---- /dev/null -+++ b/src/tests/cmocka/test_certmap.c -@@ -0,0 +1,1443 @@ -+/* -+ SSSD -+ -+ certmap - Tests for SSSD's certificate mapping library -+ -+ Authors: -+ Sumit Bose -+ -+ Copyright (C) 2017 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 -+#include -+#include -+#include -+ -+#include "lib/certmap/sss_certmap.h" -+#include "lib/certmap/sss_certmap_int.h" -+ -+#include "util/crypto/sss_crypto.h" -+ -+#include "tests/cmocka/common_mock.h" -+#include "tests/common.h" -+ -+#ifdef HAVE_NSS -+#include "util/crypto/nss/nss_util.h" -+#endif -+ -+struct priv_sss_debug { -+ int level; -+}; -+ -+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); -+ } -+} -+ -+static void test_sss_certmap_init(void **state) -+{ -+ int ret; -+ struct sss_certmap_ctx *ctx; -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ -+ sss_certmap_free_ctx(ctx); -+} -+ -+static struct sss_certmap_ctx *setup_prio(const int *l) -+{ -+ int ret; -+ size_t c; -+ struct sss_certmap_ctx *ctx; -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ -+ for (c = 0; c < 10; c++) { -+ ret = sss_certmap_add_rule(ctx, l[c], NULL, NULL, NULL); -+ assert_int_equal(ret, EOK); -+ } -+ -+ return ctx; -+} -+ -+static void test_sss_certmap_add_rule(void **state) -+{ -+ struct sss_certmap_ctx *ctx; -+ int i; -+ struct priority_list *p; -+ struct priority_list *last; -+ size_t c; -+ -+ const int tests_a[][10] = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, -+ {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, -+ {1, 3, 5 ,7, 9, 0, 2, 4, 6, 8}, -+ {0, 2, 4, 6, 8, 1, 3, 5, 7, 9}, -+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -+ -+ const int tests_b[][10] = {{0, 0, 0, 0, 1, 1, 1, 2, 2, 2}, -+ {2, 2, 2, 1, 1, 1, 0, 0, 0, 0}, -+ {0, 1, 2, 0, 1, 2, 0, 1, 2, 0}, -+ {0, 2, 1, 0, 2, 1, 0, 2, 1, 0}, -+ {0, 1, 2, 0, 2, 1, 0, 0, 1, 2}, -+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -+ -+ for (c = 0; tests_a[c][0] != 0 || tests_a[c][9] != 0; c++) { -+ ctx = setup_prio(tests_a[0]); -+ assert_non_null(ctx); -+ i = 0; -+ for (p = ctx->prio_list; p != NULL; p = p->next) { -+ assert_int_equal(i, p->priority); -+ assert_non_null(p->rule_list); -+ assert_int_equal(i, p->rule_list->priority); -+ assert_null(p->rule_list->prev); -+ assert_null(p->rule_list->next); -+ i++; -+ } -+ -+ i = 9; -+ for (last = ctx->prio_list; last->next != NULL; last = last->next); -+ for (p = last; p != NULL; p = p->prev) { -+ assert_int_equal(i, p->priority); -+ assert_int_equal(i, p->rule_list->priority); -+ i--; -+ } -+ -+ sss_certmap_free_ctx(ctx); -+ } -+ for (c = 0; tests_b[c][0] != 0 || tests_b[c][9] != 0; c++) { -+ ctx = setup_prio(tests_b[0]); -+ assert_non_null(ctx); -+ i = 0; -+ for (p = ctx->prio_list; p != NULL; p = p->next) { -+ assert_int_equal(i, p->priority); -+ assert_non_null(p->rule_list); -+ assert_int_equal(i, p->rule_list->priority); -+ assert_null(p->rule_list->prev); -+ assert_non_null(p->rule_list->next); -+ assert_ptr_equal(p->rule_list, p->rule_list->next->prev); -+ assert_non_null(p->rule_list->next->next); -+ assert_ptr_equal(p->rule_list->next, -+ p->rule_list->next->next->prev); -+ if (i == 0) { -+ assert_non_null(p->rule_list->next->next->next); -+ assert_ptr_equal(p->rule_list->next->next, -+ p->rule_list->next->next->next->prev); -+ assert_null(p->rule_list->next->next->next->next); -+ } else { -+ assert_null(p->rule_list->next->next->next); -+ } -+ i++; -+ } -+ sss_certmap_free_ctx(ctx); -+ } -+} -+ -+static void test_sss_certmap_add_matching_rule(void **state) -+{ -+ struct sss_certmap_ctx *ctx; -+ int ret; -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "fsdf", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "FDSF:fsdf", NULL, NULL); -+ assert_int_equal(ret, ESRCH); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "ddqwdq", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "digitalSignature,dddq", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ -+ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "dwqwqw", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, ".", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, ".1.2.3", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "1.2.3.", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "1.a.3", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "prio_list); -+ -+ /* invalid base64 input */ -+ ret = sss_certmap_add_rule(ctx, 1, "...", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ /* invalid OID input */ -+ ret = sss_certmap_add_rule(ctx, 1, "dqq", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "dqq", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "dqq", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "dqq", NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "a", NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); -+ assert_string_equal("a", -+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); -+ talloc_free(ctx); -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ ret = sss_certmap_add_rule(ctx, 1, "&&a", NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); -+ assert_string_equal("a", -+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); -+ talloc_free(ctx); -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:||a", NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_or); -+ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); -+ assert_string_equal("a", -+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); -+ talloc_free(ctx); -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:ab", NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject); -+ assert_string_equal("b", -+ ctx->prio_list->rule_list->parsed_match_rule->subject->val); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); -+ assert_string_equal("a", -+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); -+ talloc_free(ctx); -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ ret = sss_certmap_add_rule(ctx, 1000, -+ "KRB5:abcd", -+ NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject); -+ assert_string_equal("d", -+ ctx->prio_list->rule_list->parsed_match_rule->subject->val); -+ assert_string_equal("b", -+ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); -+ assert_string_equal("c", -+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); -+ assert_string_equal("a", -+ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val); -+ -+ ret = sss_certmap_add_rule(ctx, 99, -+ "KRB5:ab" -+ "dataEncipherment,cRLSignc" -+ "d", -+ NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject); -+ assert_string_equal("d", -+ ctx->prio_list->rule_list->parsed_match_rule->subject->val); -+ assert_string_equal("b", -+ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); -+ assert_string_equal("c", -+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); -+ assert_string_equal("a", -+ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->ku); -+ assert_int_equal(SSS_KU_CRL_SIGN|SSS_KU_DATA_ENCIPHERMENT, -+ ctx->prio_list->rule_list->parsed_match_rule->ku->ku); -+ -+ ret = sss_certmap_add_rule(ctx, 98, -+ "KRB5:ab" -+ "dataEncipherment,cRLSignc" -+ "clientAuth,emailProtection" -+ "d", -+ NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject); -+ assert_string_equal("d", -+ ctx->prio_list->rule_list->parsed_match_rule->subject->val); -+ assert_string_equal("b", -+ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); -+ assert_string_equal("c", -+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); -+ assert_string_equal("a", -+ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->ku); -+ assert_int_equal(SSS_KU_CRL_SIGN|SSS_KU_DATA_ENCIPHERMENT, -+ ctx->prio_list->rule_list->parsed_match_rule->ku->ku); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->eku); -+ assert_true(string_in_list("1.3.6.1.5.5.7.3.2", -+ discard_const( -+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list), -+ true)); -+ assert_true(string_in_list("1.3.6.1.5.5.7.3.4", -+ discard_const( -+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list), -+ true)); -+ assert_null( -+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list[2]); -+ -+ ret = sss_certmap_add_rule(ctx, 97, -+ "KRB5:clientAuth,1.2.3,emailProtection", -+ NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->eku); -+ assert_true(string_in_list("1.3.6.1.5.5.7.3.2", -+ discard_const( -+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list), -+ true)); -+ assert_true(string_in_list("1.3.6.1.5.5.7.3.4", -+ discard_const( -+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list), -+ true)); -+ assert_true(string_in_list("1.2.3", -+ discard_const( -+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list), -+ true)); -+ assert_null( -+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list[3]); -+ -+ /* SAN tests */ -+ ret = sss_certmap_add_rule(ctx, 89, "KRB5:abc", NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt, -+ SAN_PRINCIPAL); -+ assert_string_equal(ctx->prio_list->rule_list->parsed_match_rule->san->val, -+ "abc"); -+ -+ ret = sss_certmap_add_rule(ctx, 88, "KRB5:def", NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt, -+ SAN_DNS_NAME); -+ assert_string_equal(ctx->prio_list->rule_list->parsed_match_rule->san->val, -+ "def"); -+ -+ ret = sss_certmap_add_rule(ctx, 87, "KRB5:aGlq", -+ NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt, -+ SAN_X400_ADDRESS); -+ assert_int_equal( -+ ctx->prio_list->rule_list->parsed_match_rule->san->bin_val_len, -+ 3); -+ assert_memory_equal( -+ ctx->prio_list->rule_list->parsed_match_rule->san->bin_val, -+ "hij", 3); -+ -+ ret = sss_certmap_add_rule(ctx, 86, "KRB5:klm", -+ NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt, -+ SAN_STRING_OTHER_NAME); -+ assert_string_equal(ctx->prio_list->rule_list->parsed_match_rule->san->val, -+ "klm"); -+ assert_string_equal("1.2.3.4", -+ ctx->prio_list->rule_list->parsed_match_rule->san->str_other_name_oid); -+ -+ talloc_free(ctx); -+} -+ -+static void test_check_ad_attr_name(void **state) -+{ -+ char *res; -+ -+ res = check_ad_attr_name(NULL, NULL); -+ assert_null(res); -+ -+ res = check_ad_attr_name(NULL, ""); -+ assert_null(res); -+ -+ res = check_ad_attr_name(NULL, "dsddqwdas"); -+ assert_null(res); -+ -+ res = check_ad_attr_name(NULL, "dsddq=wdas"); -+ assert_null(res); -+ -+ res = check_ad_attr_name(NULL, "CN=abc"); -+ assert_null(res); -+ -+ res = check_ad_attr_name(NULL, "O=xyz"); -+ assert_null(res); -+ -+ res = check_ad_attr_name(NULL, "ST=def"); -+ assert_non_null(res); -+ assert_string_equal(res, "S=def"); -+ talloc_free(res); -+} -+ -+const uint8_t test_cert_der[] = { -+0x30, 0x82, 0x04, 0x09, 0x30, 0x82, 0x02, 0xf1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x09, -+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, -+0x34, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x49, 0x50, 0x41, 0x2e, -+0x44, 0x45, 0x56, 0x45, 0x4c, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15, -+0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, -+0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x34, 0x32, 0x38, 0x31, -+0x30, 0x32, 0x31, 0x31, 0x31, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x34, 0x32, 0x38, 0x31, 0x30, -+0x32, 0x31, 0x31, 0x31, 0x5a, 0x30, 0x32, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, -+0x0c, 0x09, 0x49, 0x50, 0x41, 0x2e, 0x44, 0x45, 0x56, 0x45, 0x4c, 0x31, 0x1c, 0x30, 0x1a, 0x06, -+0x03, 0x55, 0x04, 0x03, 0x0c, 0x13, 0x69, 0x70, 0x61, 0x2d, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2e, -+0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, -+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, -+0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb2, 0x32, 0x92, 0xab, 0x47, 0xb8, -+0x0c, 0x13, 0x54, 0x4a, 0x1f, 0x1e, 0x29, 0x06, 0xff, 0xd0, 0x50, 0xcb, 0xf7, 0x5f, 0x79, 0x91, -+0x65, 0xb1, 0x39, 0x01, 0x83, 0x6a, 0xad, 0x9e, 0x77, 0x3b, 0xf3, 0x0d, 0xd7, 0xb9, 0xf6, 0xdc, -+0x9e, 0x4a, 0x49, 0xa7, 0xd0, 0x66, 0x72, 0xcc, 0xbf, 0x77, 0xd6, 0xde, 0xa9, 0xfe, 0x67, 0x96, -+0xcc, 0x49, 0xf1, 0x37, 0x23, 0x2e, 0xc4, 0x50, 0xf4, 0xeb, 0xba, 0x62, 0xd4, 0x23, 0x4d, 0xf3, -+0x37, 0x38, 0x82, 0xee, 0x3b, 0x3f, 0x2c, 0xd0, 0x80, 0x9b, 0x17, 0xaa, 0x9b, 0xeb, 0xa6, 0xdd, -+0xf6, 0x15, 0xff, 0x06, 0xb2, 0xce, 0xff, 0xdf, 0x8a, 0x9e, 0x95, 0x85, 0x49, 0x1f, 0x84, 0xfd, -+0x81, 0x26, 0xce, 0x06, 0x32, 0x0d, 0x36, 0xca, 0x7c, 0x15, 0x81, 0x68, 0x6b, 0x8f, 0x3e, 0xb3, -+0xa2, 0xfc, 0xae, 0xaf, 0xc2, 0x44, 0x58, 0x15, 0x95, 0x40, 0xfc, 0x56, 0x19, 0x91, 0x80, 0xed, -+0x42, 0x11, 0x66, 0x04, 0xef, 0x3c, 0xe0, 0x76, 0x33, 0x4b, 0x83, 0xfa, 0x7e, 0xb4, 0x47, 0xdc, -+0xfb, 0xed, 0x46, 0xa5, 0x8d, 0x0a, 0x66, 0x87, 0xa5, 0xef, 0x7b, 0x74, 0x62, 0xac, 0xbe, 0x73, -+0x36, 0xc9, 0xb4, 0xfe, 0x20, 0xc4, 0x81, 0xf3, 0xfe, 0x78, 0x19, 0xa8, 0xd0, 0xaf, 0x7f, 0x81, -+0x72, 0x24, 0x61, 0xd9, 0x76, 0x93, 0xe3, 0x0b, 0xd2, 0x4f, 0x19, 0x17, 0x33, 0x57, 0xd4, 0x82, -+0xb0, 0xf1, 0xa8, 0x03, 0xf6, 0x01, 0x99, 0xa9, 0xb8, 0x8c, 0x83, 0xc9, 0xba, 0x19, 0x87, 0xea, -+0xd6, 0x3b, 0x06, 0xeb, 0x4c, 0xf7, 0xf1, 0xe5, 0x28, 0xa9, 0x10, 0xb6, 0x46, 0xde, 0xe1, 0xe1, -+0x3f, 0xc1, 0xcc, 0x72, 0xbe, 0x2a, 0x43, 0xc6, 0xf6, 0xd0, 0xb5, 0xa0, 0xc4, 0x24, 0x6e, 0x4f, -+0xbd, 0xec, 0x22, 0x8a, 0x07, 0x11, 0x3d, 0xf9, 0xd3, 0x15, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, -+0x82, 0x01, 0x26, 0x30, 0x82, 0x01, 0x22, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, -+0x30, 0x16, 0x80, 0x14, 0xf2, 0x9d, 0x42, 0x4e, 0x0f, 0xc4, 0x48, 0x25, 0x58, 0x2f, 0x1c, 0xce, -+0x0f, 0xa1, 0x3f, 0x22, 0xc8, 0x55, 0xc8, 0x91, 0x30, 0x3b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, -+0x05, 0x07, 0x01, 0x01, 0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, -+0x05, 0x07, 0x30, 0x01, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x69, 0x70, 0x61, -+0x2d, 0x63, 0x61, 0x2e, 0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2f, 0x63, 0x61, -+0x2f, 0x6f, 0x63, 0x73, 0x70, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, -+0x04, 0x03, 0x02, 0x04, 0xf0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, -+0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, -+0x05, 0x07, 0x03, 0x02, 0x30, 0x74, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x6d, 0x30, 0x6b, 0x30, -+0x69, 0xa0, 0x31, 0xa0, 0x2f, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x69, 0x70, -+0x61, 0x2d, 0x63, 0x61, 0x2e, 0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2f, 0x69, -+0x70, 0x61, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x43, 0x52, 0x4c, -+0x2e, 0x62, 0x69, 0x6e, 0xa2, 0x34, 0xa4, 0x32, 0x30, 0x30, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, -+0x55, 0x04, 0x0a, 0x0c, 0x05, 0x69, 0x70, 0x61, 0x63, 0x61, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, -+0x55, 0x04, 0x03, 0x0c, 0x15, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, -+0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, -+0x0e, 0x04, 0x16, 0x04, 0x14, 0x2d, 0x2b, 0x3f, 0xcb, 0xf5, 0xb2, 0xff, 0x32, 0x2c, 0xa8, 0xc2, -+0x1c, 0xdd, 0xbd, 0x8c, 0x80, 0x1e, 0xdd, 0x31, 0x82, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, -+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x9a, 0x47, 0x2e, -+0x50, 0xa7, 0x4d, 0x1d, 0x53, 0x0f, 0xc9, 0x71, 0x42, 0x0c, 0xe5, 0xda, 0x7d, 0x49, 0x64, 0xe7, -+0xab, 0xc8, 0xdf, 0xdf, 0x02, 0xc1, 0x87, 0xd1, 0x5b, 0xde, 0xda, 0x6f, 0x2b, 0xe4, 0xf0, 0xbe, -+0xba, 0x09, 0xdf, 0x02, 0x85, 0x0b, 0x8a, 0xe6, 0x9b, 0x06, 0x7d, 0x69, 0x38, 0x6c, 0x72, 0xff, -+0x4c, 0x7b, 0x2a, 0x0d, 0x3f, 0x23, 0x2f, 0x16, 0x46, 0xff, 0x05, 0x93, 0xb0, 0xea, 0x24, 0x28, -+0xd7, 0x12, 0xa1, 0x57, 0xb8, 0x59, 0x19, 0x25, 0xf3, 0x43, 0x0a, 0xd3, 0xfd, 0x0f, 0x37, 0x8d, -+0xb8, 0xca, 0x15, 0xe7, 0x48, 0x8a, 0xa0, 0xc7, 0xc7, 0x4b, 0x7f, 0x01, 0x3c, 0x58, 0xd7, 0x37, -+0xe5, 0xff, 0x7d, 0x2b, 0x01, 0xac, 0x0d, 0x9f, 0x51, 0x6a, 0xe5, 0x40, 0x24, 0xe6, 0x5e, 0x55, -+0x0d, 0xf7, 0xb8, 0x2f, 0x42, 0xac, 0x6d, 0xe5, 0x29, 0x6b, 0xc6, 0x0b, 0xa4, 0xbf, 0x19, 0xbd, -+0x39, 0x27, 0xee, 0xfe, 0xc5, 0xb3, 0xdb, 0x62, 0xd4, 0xbe, 0xd2, 0x47, 0xba, 0x96, 0x30, 0x5a, -+0xfd, 0x62, 0x00, 0xb8, 0x27, 0x5d, 0x2f, 0x3a, 0x94, 0x0b, 0x95, 0x35, 0x85, 0x40, 0x2c, 0xbc, -+0x67, 0xdf, 0x8a, 0xf9, 0xf1, 0x7b, 0x19, 0x96, 0x3e, 0x42, 0x48, 0x13, 0x23, 0x04, 0x95, 0xa9, -+0x6b, 0x11, 0x33, 0x81, 0x47, 0x5a, 0x83, 0x72, 0xf6, 0x20, 0xfa, 0x8e, 0x41, 0x7b, 0x8f, 0x77, -+0x47, 0x7c, 0xc7, 0x5d, 0x46, 0xf4, 0x4f, 0xfd, 0x81, 0x0a, 0xae, 0x39, 0x27, 0xb6, 0x6a, 0x26, -+0x63, 0xb1, 0xd3, 0xbf, 0x55, 0x83, 0x82, 0x9b, 0x36, 0x6c, 0x33, 0x64, 0x0f, 0x50, 0xc0, 0x55, -+0x94, 0x13, 0xc3, 0x85, 0xf4, 0xd5, 0x71, 0x65, 0xd0, 0xc0, 0xdd, 0xfc, 0xe6, 0xec, 0x9c, 0x5b, -+0xf0, 0x11, 0xb5, 0x2c, 0xf3, 0x48, 0xc1, 0x36, 0x8c, 0xa2, 0x96, 0x48, 0x84}; -+ -+const uint8_t test_cert2_der[] = { -+0x30, 0x82, 0x06, 0x98, 0x30, 0x82, 0x05, 0x80, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x61, -+0x22, 0x88, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x02, 0xa6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, -+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x15, 0x30, 0x13, 0x06, 0x0a, -+0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x05, 0x64, 0x65, 0x76, 0x65, -+0x6c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, -+0x19, 0x16, 0x02, 0x61, 0x64, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, -+0x61, 0x64, 0x2d, 0x41, 0x44, 0x2d, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x2d, 0x43, 0x41, 0x30, -+0x1e, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x31, 0x31, 0x31, 0x31, 0x33, 0x35, 0x31, 0x31, 0x31, 0x5a, -+0x17, 0x0d, 0x31, 0x37, 0x31, 0x31, 0x31, 0x31, 0x31, 0x33, 0x35, 0x31, 0x31, 0x31, 0x5a, 0x30, -+0x70, 0x31, 0x15, 0x30, 0x13, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, -+0x19, 0x16, 0x05, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x0a, 0x09, 0x92, -+0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x02, 0x61, 0x64, 0x31, 0x0e, 0x30, 0x0c, -+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x31, 0x0c, 0x30, 0x0a, -+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x03, 0x74, 0x20, 0x75, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, -+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x16, 0x74, 0x65, 0x73, 0x74, 0x2e, -+0x75, 0x73, 0x65, 0x72, 0x40, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, -+0x6e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, -+0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, -+0x01, 0x00, 0x9c, 0xcf, 0x36, 0x99, 0xde, 0x63, 0x74, 0x2b, 0x77, 0x25, 0x9e, 0x24, 0xd9, 0x77, -+0x4b, 0x5f, 0x98, 0xc0, 0x8c, 0xd7, 0x20, 0x91, 0xc0, 0x1c, 0xe8, 0x37, 0x45, 0xbf, 0x3c, 0xd9, -+0x33, 0xbd, 0xe9, 0xde, 0xc9, 0x5d, 0xd4, 0xcd, 0x06, 0x0a, 0x0d, 0xd4, 0xf1, 0x7c, 0x74, 0x5b, -+0x29, 0xd5, 0x66, 0x9c, 0x2c, 0x9f, 0x6b, 0x1a, 0x0f, 0x0d, 0xe6, 0x6c, 0x62, 0xa5, 0x41, 0x4f, -+0xc3, 0xa4, 0x88, 0x27, 0x11, 0x5d, 0xb7, 0xb1, 0xfb, 0xf8, 0x8d, 0xee, 0x43, 0x8d, 0x93, 0xb5, -+0x8c, 0xb4, 0x34, 0x06, 0xf5, 0xe9, 0x2f, 0x5a, 0x26, 0x68, 0xd7, 0x43, 0x60, 0x82, 0x5e, 0x22, -+0xa7, 0xc6, 0x34, 0x40, 0x19, 0xa5, 0x8e, 0xf0, 0x58, 0x9f, 0x16, 0x2d, 0x43, 0x3f, 0x0c, 0xda, -+0xe2, 0x23, 0xf6, 0x09, 0x2a, 0x5e, 0xbd, 0x84, 0x27, 0xc8, 0xab, 0xd5, 0x70, 0xf8, 0x3d, 0x9c, -+0x14, 0xc2, 0xc2, 0xa2, 0x77, 0xe8, 0x44, 0x73, 0x10, 0x01, 0x34, 0x40, 0x1f, 0xc6, 0x2f, 0xa0, -+0x70, 0xee, 0x2f, 0xd5, 0x4b, 0xbe, 0x4c, 0xc7, 0x45, 0xf7, 0xac, 0x9c, 0xc3, 0x68, 0x5b, 0x1d, -+0x5a, 0x4b, 0x77, 0x65, 0x76, 0xe4, 0xb3, 0x92, 0xf4, 0x84, 0x0a, 0x9e, 0x6a, 0x9c, 0xc9, 0x53, -+0x42, 0x9f, 0x6d, 0xfe, 0xf9, 0xf5, 0xf2, 0x9a, 0x15, 0x50, 0x47, 0xef, 0xf4, 0x06, 0x59, 0xc8, -+0x50, 0x48, 0x4b, 0x46, 0x95, 0x68, 0x25, 0xc5, 0xbd, 0x4f, 0x65, 0x34, 0x00, 0xfc, 0x31, 0x69, -+0xf8, 0x3e, 0xe0, 0x20, 0x83, 0x41, 0x27, 0x0b, 0x5c, 0x46, 0x98, 0x14, 0xf0, 0x07, 0xde, 0x02, -+0x17, 0xb1, 0xd2, 0x9c, 0xbe, 0x1c, 0x0d, 0x56, 0x22, 0x1b, 0x02, 0xfe, 0xda, 0x69, 0xb9, 0xef, -+0x91, 0x37, 0x39, 0x7f, 0x24, 0xda, 0xc4, 0x81, 0x5e, 0x82, 0x31, 0x2f, 0x98, 0x1d, 0xf7, 0x73, -+0x5b, 0x23, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x03, 0x5d, 0x30, 0x82, 0x03, 0x59, 0x30, -+0x3d, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x07, 0x04, 0x30, 0x30, 0x2e, -+0x06, 0x26, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x08, 0x87, 0x85, 0xa1, 0x23, 0x84, -+0xc8, 0xb2, 0x26, 0x83, 0x9d, 0x9d, 0x21, 0x82, 0xd4, 0xa6, 0x1b, 0x86, 0xa3, 0xba, 0x37, 0x81, -+0x10, 0x85, 0x89, 0xd5, 0x02, 0xd6, 0x8f, 0x24, 0x02, 0x01, 0x64, 0x02, 0x01, 0x02, 0x30, 0x29, -+0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x22, 0x30, 0x20, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, -+0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x04, 0x06, 0x0a, 0x2b, -+0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0a, 0x03, 0x04, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, -+0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x35, 0x06, 0x09, 0x2b, 0x06, 0x01, -+0x04, 0x01, 0x82, 0x37, 0x15, 0x0a, 0x04, 0x28, 0x30, 0x26, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, -+0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, -+0x03, 0x04, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0a, 0x03, 0x04, -+0x30, 0x81, 0x94, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x0f, 0x04, 0x81, -+0x86, 0x30, 0x81, 0x83, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, -+0x2a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2d, 0x30, 0x0b, -+0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x16, 0x30, 0x0b, 0x06, 0x09, 0x60, -+0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x19, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, -+0x65, 0x03, 0x04, 0x01, 0x02, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, -+0x01, 0x05, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x07, 0x30, 0x07, -+0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x07, 0x30, 0x0e, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, -+0x0d, 0x03, 0x02, 0x02, 0x02, 0x00, 0x80, 0x30, 0x0e, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, -+0x0d, 0x03, 0x04, 0x02, 0x02, 0x02, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, -+0x04, 0x14, 0x49, 0xac, 0xad, 0xe0, 0x65, 0x30, 0xc4, 0xce, 0xa0, 0x09, 0x03, 0x5b, 0xad, 0x4a, -+0x7b, 0x49, 0x5e, 0xc9, 0x6c, 0xb4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, -+0x16, 0x80, 0x14, 0x62, 0x50, 0xb6, 0x8d, 0xa1, 0xe6, 0x2d, 0x91, 0xbf, 0xb0, 0x54, 0x4d, 0x8f, -+0xa8, 0xca, 0x10, 0xae, 0xb8, 0xdd, 0x54, 0x30, 0x81, 0xcc, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, -+0x81, 0xc4, 0x30, 0x81, 0xc1, 0x30, 0x81, 0xbe, 0xa0, 0x81, 0xbb, 0xa0, 0x81, 0xb8, 0x86, 0x81, -+0xb5, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x2f, 0x43, 0x4e, 0x3d, 0x61, 0x64, 0x2d, 0x41, -+0x44, 0x2d, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x2d, 0x43, 0x41, 0x2c, 0x43, 0x4e, 0x3d, 0x61, -+0x64, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2c, 0x43, 0x4e, 0x3d, 0x43, 0x44, 0x50, 0x2c, -+0x43, 0x4e, 0x3d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x25, 0x32, 0x30, 0x4b, 0x65, 0x79, 0x25, -+0x32, 0x30, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x65, -+0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, -+0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x44, 0x43, 0x3d, 0x61, 0x64, 0x2c, 0x44, 0x43, -+0x3d, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x3f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, -+0x74, 0x65, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, -+0x3f, 0x62, 0x61, 0x73, 0x65, 0x3f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6c, 0x61, 0x73, -+0x73, 0x3d, 0x63, 0x52, 0x4c, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, -+0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x30, 0x81, 0xbe, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, -+0x07, 0x01, 0x01, 0x04, 0x81, 0xb1, 0x30, 0x81, 0xae, 0x30, 0x81, 0xab, 0x06, 0x08, 0x2b, 0x06, -+0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x81, 0x9e, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, -+0x2f, 0x43, 0x4e, 0x3d, 0x61, 0x64, 0x2d, 0x41, 0x44, 0x2d, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, -+0x2d, 0x43, 0x41, 0x2c, 0x43, 0x4e, 0x3d, 0x41, 0x49, 0x41, 0x2c, 0x43, 0x4e, 0x3d, 0x50, 0x75, -+0x62, 0x6c, 0x69, 0x63, 0x25, 0x32, 0x30, 0x4b, 0x65, 0x79, 0x25, 0x32, 0x30, 0x53, 0x65, 0x72, -+0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, -+0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, -+0x6f, 0x6e, 0x2c, 0x44, 0x43, 0x3d, 0x61, 0x64, 0x2c, 0x44, 0x43, 0x3d, 0x64, 0x65, 0x76, 0x65, -+0x6c, 0x3f, 0x63, 0x41, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3f, -+0x62, 0x61, 0x73, 0x65, 0x3f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73, -+0x3d, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x75, -+0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x3f, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x38, -+0x30, 0x36, 0xa0, 0x1c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x03, -+0xa0, 0x0e, 0x0c, 0x0c, 0x74, 0x75, 0x31, 0x40, 0x61, 0x64, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, -+0x81, 0x16, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x40, 0x65, 0x6d, 0x61, 0x69, -+0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, -+0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x41, 0x45, 0x0a, 0x6d, -+0xbb, 0x7f, 0x5c, 0x07, 0x0c, 0xc9, 0xb0, 0x39, 0x55, 0x6d, 0x7c, 0xb5, 0x02, 0xcd, 0xe8, 0xb2, -+0xe5, 0x02, 0x94, 0x77, 0x60, 0xdb, 0xd1, 0xaf, 0x1d, 0xdb, 0x44, 0x5f, 0xce, 0x83, 0xdb, 0x80, -+0x2e, 0xe2, 0xb2, 0x08, 0x25, 0x82, 0x14, 0xcb, 0x48, 0x95, 0x20, 0x13, 0x6c, 0xa9, 0xaa, 0xf8, -+0x31, 0x56, 0xed, 0xc0, 0x3b, 0xd4, 0xae, 0x2e, 0xe3, 0x8f, 0x05, 0xfc, 0xab, 0x5f, 0x2a, 0x69, -+0x23, 0xbc, 0xb8, 0x8c, 0xec, 0x2d, 0xa9, 0x0b, 0x86, 0x95, 0x73, 0x73, 0xdb, 0x17, 0xce, 0xc6, -+0xae, 0xc5, 0xb4, 0xc1, 0x25, 0x87, 0x3b, 0x67, 0x43, 0x9e, 0x87, 0x5a, 0xe6, 0xb9, 0xa0, 0x28, -+0x12, 0x3d, 0xa8, 0x2e, 0xd7, 0x5e, 0xef, 0x65, 0x2d, 0xe6, 0xa5, 0x67, 0x84, 0xac, 0xfd, 0x31, -+0xc1, 0x78, 0xd8, 0x72, 0x51, 0xa2, 0x88, 0x55, 0x0f, 0x97, 0x47, 0x93, 0x07, 0xea, 0x8a, 0x53, -+0x27, 0x4e, 0x34, 0x54, 0x34, 0x1f, 0xa0, 0x6a, 0x03, 0x44, 0xfb, 0x23, 0x61, 0x8e, 0x87, 0x8e, -+0x3c, 0xd0, 0x8f, 0xae, 0xe4, 0xcf, 0xee, 0x65, 0xa8, 0xba, 0x96, 0x68, 0x08, 0x1c, 0x60, 0xe2, -+0x4e, 0x11, 0xa3, 0x74, 0xb8, 0xa5, 0x4e, 0xea, 0x6a, 0x82, 0x4c, 0xc2, 0x4d, 0x63, 0x8e, 0x9f, -+0x7c, 0x2f, 0xa8, 0xc0, 0x62, 0xf8, 0xf7, 0xd9, 0x25, 0xc4, 0x91, 0xab, 0x4d, 0x6a, 0x44, 0xaf, -+0x75, 0x93, 0x53, 0x03, 0xa4, 0x99, 0xc8, 0xcd, 0x91, 0x89, 0x60, 0x75, 0x30, 0x99, 0x76, 0x05, -+0x5a, 0xa0, 0x03, 0xa7, 0xa1, 0x2c, 0x03, 0x04, 0x8f, 0xd4, 0x5a, 0x31, 0x52, 0x28, 0x5a, 0xe6, -+0xa2, 0xd3, 0x43, 0x21, 0x5b, 0xdc, 0xa2, 0x1d, 0x55, 0xa9, 0x48, 0xc5, 0xc4, 0xaa, 0xf3, 0x8b, -+0xe6, 0x3e, 0x75, 0x96, 0xe4, 0x3e, 0x64, 0xaf, 0xe8, 0xa7, 0x6a, 0xb6}; -+ -+void test_sss_cert_get_content(void **state) -+{ -+ int ret; -+ struct sss_cert_content *content; -+ -+ ret = sss_cert_get_content(NULL, test_cert_der, sizeof(test_cert_der), -+ &content); -+ assert_int_equal(ret , 0); -+ assert_non_null(content); -+ assert_non_null(content->issuer_str); -+ assert_string_equal(content->issuer_str, "CN=Certificate Authority,O=IPA.DEVEL"); -+ assert_non_null(content->subject_str); -+ assert_string_equal(content->subject_str, "CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); -+ assert_int_equal(content->key_usage, SSS_KU_DIGITAL_SIGNATURE -+ |SSS_KU_NON_REPUDIATION -+ |SSS_KU_KEY_ENCIPHERMENT -+ |SSS_KU_DATA_ENCIPHERMENT); -+ assert_non_null(content->extended_key_usage_oids); -+ assert_non_null(content->extended_key_usage_oids[0]); -+ assert_true(string_in_list("1.3.6.1.5.5.7.3.1", -+ discard_const(content->extended_key_usage_oids), true)); -+ assert_true(string_in_list("1.3.6.1.5.5.7.3.2", -+ discard_const(content->extended_key_usage_oids), true)); -+ assert_null(content->extended_key_usage_oids[2]); -+ assert_int_equal(content->cert_der_size, sizeof(test_cert_der)); -+ assert_memory_equal(content->cert_der, test_cert_der, sizeof(test_cert_der)); -+ -+ assert_non_null(content->issuer_rdn_list); -+ assert_string_equal(content->issuer_rdn_list[0], "O=IPA.DEVEL"); -+ assert_string_equal(content->issuer_rdn_list[1], "CN=Certificate Authority"); -+ assert_null(content->issuer_rdn_list[2]); -+ -+ assert_non_null(content->subject_rdn_list); -+ assert_string_equal(content->subject_rdn_list[0], "O=IPA.DEVEL"); -+ assert_string_equal(content->subject_rdn_list[1], "CN=ipa-devel.ipa.devel"); -+ assert_null(content->subject_rdn_list[2]); -+ -+ -+ talloc_free(content); -+} -+ -+void test_sss_cert_get_content_2(void **state) -+{ -+ int ret; -+ struct sss_cert_content *content; -+ struct san_list *i; -+ -+ ret = sss_cert_get_content(NULL, test_cert2_der, sizeof(test_cert2_der), -+ &content); -+ assert_int_equal(ret, 0); -+ assert_non_null(content); -+ assert_non_null(content->issuer_str); -+ assert_string_equal(content->issuer_str, -+ "CN=ad-AD-SERVER-CA,DC=ad,DC=devel"); -+ assert_non_null(content->subject_str); -+#if 0 -+FIXME: -+ assert_string_equal(content->subject_str, -+ "E=test.user@email.domain,CN=t u,CN=Users,DC=ad,DC=devel,DC=ad,DC=devel"); -+ //"CN=t u/emailAddress=test.user@email.domain,DC=ad,DC=devel"); -+#endif -+ assert_int_equal(content->key_usage, SSS_KU_DIGITAL_SIGNATURE -+ |SSS_KU_KEY_ENCIPHERMENT); -+ assert_non_null(content->extended_key_usage_oids); -+ assert_non_null(content->extended_key_usage_oids[0]); -+ assert_true(string_in_list("1.3.6.1.5.5.7.3.2", -+ discard_const(content->extended_key_usage_oids), true)); -+ assert_true(string_in_list("1.3.6.1.5.5.7.3.4", -+ discard_const(content->extended_key_usage_oids), true)); -+ /* Can use Microsoft Encrypted File System OID */ -+ assert_true(string_in_list("1.3.6.1.4.1.311.10.3.4", -+ discard_const(content->extended_key_usage_oids), true)); -+ assert_null(content->extended_key_usage_oids[3]); -+ assert_int_equal(content->cert_der_size, sizeof(test_cert2_der)); -+ assert_memory_equal(content->cert_der, test_cert2_der, -+ sizeof(test_cert2_der)); -+ -+ assert_non_null(content->issuer_rdn_list); -+ assert_string_equal(content->issuer_rdn_list[0], "DC=devel"); -+ assert_string_equal(content->issuer_rdn_list[1], "DC=ad"); -+ assert_string_equal(content->issuer_rdn_list[2], "CN=ad-AD-SERVER-CA"); -+ assert_null(content->issuer_rdn_list[3]); -+ -+ assert_non_null(content->subject_rdn_list); -+ assert_string_equal(content->subject_rdn_list[0], "DC=devel"); -+ assert_string_equal(content->subject_rdn_list[1], "DC=ad"); -+ assert_string_equal(content->subject_rdn_list[2], "CN=Users"); -+ assert_string_equal(content->subject_rdn_list[3], "CN=t u"); -+ assert_string_equal(content->subject_rdn_list[4], -+ "E=test.user@email.domain"); -+ //"CN=t u/emailAddress=test.user@email.domain"); -+ assert_null(content->subject_rdn_list[5]); -+ -+ assert_non_null(content->san_list); -+ -+ DLIST_FOR_EACH(i, content->san_list) { -+ switch (i->san_opt) { -+ case SAN_RFC822_NAME: -+ assert_string_equal(i->val, "test.user@email.domain"); -+ assert_string_equal(i->short_name, "test.user"); -+ break; -+ case SAN_STRING_OTHER_NAME: -+ assert_string_equal(i->other_name_oid, "1.3.6.1.4.1.311.20.2.3"); -+ assert_int_equal(i->bin_val_len, 14); -+ assert_memory_equal(i->bin_val, "\f\ftu1@ad.devel", 14); -+ break; -+ case SAN_NT: -+ case SAN_PRINCIPAL: -+ assert_string_equal(i->val, "tu1@ad.devel"); -+ assert_string_equal(i->short_name, "tu1"); -+ break; -+ default: -+ assert_true(false); -+ } -+ } -+ -+ talloc_free(content); -+} -+ -+static void test_sss_certmap_match_cert(void **state) -+{ -+ struct sss_certmap_ctx *ctx; -+ int ret; -+ size_t c; -+ -+ struct match_tests { -+ const char *rule; -+ int result; -+ } match_tests[] = { -+ {"KRB5:digitalSignature", 0}, -+ {"KRB5:digitalSignature,nonRepudiation", 0}, -+ {"KRB5:digitalSignature,cRLSign", ENOENT}, -+ {"KRB5:clientAuth", 0}, -+ {"KRB5:clientAuth,OCSPSigning", ENOENT}, -+ {"KRB5:clientAuth,serverAuth", 0}, -+ {NULL, 0} -+ }; -+ -+ struct match_tests match_tests_2[] = { -+ {"KRB5:digitalSignature", 0}, -+ {"KRB5:keyEncipherment", 0}, -+ {"KRB5:digitalSignature,keyEncipherment", 0}, -+ {"KRB5:digitalSignature,keyEncipherment,cRLSign", ENOENT}, -+ {"KRB5:clientAuth", 0}, -+ {"KRB5:clientAuth,1.3.6.1.4.1.311.10.3.4", 0}, -+ {"KRB5:clientAuth,1.3.6.1.4.1.311.10.3.41", ENOENT}, -+ {"KRB5:tu1", 0}, -+ {"KRB5:tu1", 0}, -+ {"KRB5:tu1", 0}, -+ {"KRB5:tu1", ENOENT}, -+ {"KRB5:^tu1@ad.devel$", 0}, -+ {"KRB5:tu", ENOENT}, -+ {"KRB5:test.user", 0}, -+ {"KRB5:test.usertu1", 0}, -+ {"KRB5:||test.usertu1", 0}, -+ {"KRB5:&&tu1tu1", ENOENT}, -+ {"KRB5:||tu1tu1", 0}, -+ {"KRB5:MTIz", ENOENT}, /* 123 */ -+ {"KRB5:DAx0dTFAYWQuZGV2ZWw=", 0}, /* "\f\ftu1@ad.devel" */ -+ {"KRB5:DAx0dTFAYWQuZGV2ZWx4", ENOENT}, /* "\f\ftu1@ad.develx" */ -+ {"KRB5:dHUxQGFkLmRldmVs", 0}, /* "tu1@ad.devel" */ -+ {"KRB5:test", ENOENT}, -+ {"KRB5:tu1@ad", 0}, -+ /* Fails becasue the NT principal SAN starts with binary values */ -+ {"KRB5:^tu1@ad.devel$", ENOENT}, -+ {NULL, 0} -+ }; -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:xyzxyz", -+ NULL, NULL); -+ assert_int_equal(ret, EOK); -+ -+ ret = sss_certmap_match_cert(ctx, discard_const(test_cert_der), -+ sizeof(test_cert_der)); -+ assert_int_equal(ret, ENOENT); -+ -+ ret = sss_certmap_add_rule(ctx, 1, -+ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", -+ NULL, NULL); -+ assert_int_equal(ret, EOK); -+ -+ ret = sss_certmap_match_cert(ctx, discard_const(test_cert_der), -+ sizeof(test_cert_der)); -+ assert_int_equal(ret, 0); -+ -+ sss_certmap_free_ctx(ctx); -+ -+ for (c = 0; match_tests[c].rule != NULL; c++) { -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, match_tests[c].rule, NULL, NULL); -+ assert_int_equal(ret, EOK); -+ -+ ret = sss_certmap_match_cert(ctx, discard_const(test_cert_der), -+ sizeof(test_cert_der)); -+ assert_int_equal(ret, match_tests[c].result); -+ -+ sss_certmap_free_ctx(ctx); -+ } -+ -+ for (c = 0; match_tests_2[c].rule != NULL; c++) { -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ -+ print_error("Checking matching rule [%s]\n", match_tests_2[c].rule); -+ -+ ret = sss_certmap_add_rule(ctx, 1, match_tests_2[c].rule, NULL, NULL); -+ assert_int_equal(ret, EOK); -+ -+ ret = sss_certmap_match_cert(ctx, discard_const(test_cert2_der), -+ sizeof(test_cert2_der)); -+ assert_int_equal(ret, match_tests_2[c].result); -+ -+ sss_certmap_free_ctx(ctx); -+ } -+} -+ -+static void test_sss_certmap_add_mapping_rule(void **state) -+{ -+ struct sss_certmap_ctx *ctx; -+ int ret; -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 1, NULL, "FWEAWEF:fwefwe", NULL); -+ assert_int_equal(ret, ESRCH); -+ -+ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:abc", NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule); -+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list); -+ assert_int_equal(comp_string, -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type); -+ assert_string_equal("abc", -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val); -+ talloc_free(ctx); -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:abc{issuer_dn}", NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule); -+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list); -+ assert_int_equal(comp_string, -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type); -+ assert_string_equal("abc", -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val); -+ assert_int_equal(comp_template, -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type); -+ assert_string_equal("issuer_dn", -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val); -+ talloc_free(ctx); -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ ret = sss_certmap_add_rule(ctx, 1, NULL, "{issuer_dn}a:b{{c}}", NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule); -+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list); -+ assert_int_equal(comp_template, -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type); -+ assert_string_equal("issuer_dn", -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val); -+ assert_int_equal(comp_string, -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type); -+ assert_string_equal("a:b{c}", -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val); -+ talloc_free(ctx); -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:{issuer_dn}{subject_dn}", -+ NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule); -+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list); -+ assert_int_equal(comp_template, -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type); -+ assert_string_equal("issuer_dn", -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val); -+ assert_int_equal(comp_template, -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type); -+ assert_string_equal("subject_dn", -+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val); -+ talloc_free(ctx); -+} -+ -+#define TEST_CERT_BIN \ -+ "\\30\\82\\04\\09\\30\\82\\02\\f1\\a0\\03\\02\\01\\02\\02\\01\\09" \ -+ "\\30\\0d\\06\\09\\2a\\86\\48\\86\\f7\\0d\\01\\01\\0b\\05\\00\\30" \ -+ "\\34\\31\\12\\30\\10\\06\\03\\55\\04\\0a\\0c\\09\\49\\50\\41\\2e" \ -+ "\\44\\45\\56\\45\\4c\\31\\1e\\30\\1c\\06\\03\\55\\04\\03\\0c\\15" \ -+ "\\43\\65\\72\\74\\69\\66\\69\\63\\61\\74\\65\\20\\41\\75\\74\\68" \ -+ "\\6f\\72\\69\\74\\79\\30\\1e\\17\\0d\\31\\35\\30\\34\\32\\38\\31" \ -+ "\\30\\32\\31\\31\\31\\5a\\17\\0d\\31\\37\\30\\34\\32\\38\\31\\30" \ -+ "\\32\\31\\31\\31\\5a\\30\\32\\31\\12\\30\\10\\06\\03\\55\\04\\0a" \ -+ "\\0c\\09\\49\\50\\41\\2e\\44\\45\\56\\45\\4c\\31\\1c\\30\\1a\\06" \ -+ "\\03\\55\\04\\03\\0c\\13\\69\\70\\61\\2d\\64\\65\\76\\65\\6c\\2e" \ -+ "\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\30\\82\\01\\22\\30\\0d\\06" \ -+ "\\09\\2a\\86\\48\\86\\f7\\0d\\01\\01\\01\\05\\00\\03\\82\\01\\0f" \ -+ "\\00\\30\\82\\01\\0a\\02\\82\\01\\01\\00\\b2\\32\\92\\ab\\47\\b8" \ -+ "\\0c\\13\\54\\4a\\1f\\1e\\29\\06\\ff\\d0\\50\\cb\\f7\\5f\\79\\91" \ -+ "\\65\\b1\\39\\01\\83\\6a\\ad\\9e\\77\\3b\\f3\\0d\\d7\\b9\\f6\\dc" \ -+ "\\9e\\4a\\49\\a7\\d0\\66\\72\\cc\\bf\\77\\d6\\de\\a9\\fe\\67\\96" \ -+ "\\cc\\49\\f1\\37\\23\\2e\\c4\\50\\f4\\eb\\ba\\62\\d4\\23\\4d\\f3" \ -+ "\\37\\38\\82\\ee\\3b\\3f\\2c\\d0\\80\\9b\\17\\aa\\9b\\eb\\a6\\dd" \ -+ "\\f6\\15\\ff\\06\\b2\\ce\\ff\\df\\8a\\9e\\95\\85\\49\\1f\\84\\fd" \ -+ "\\81\\26\\ce\\06\\32\\0d\\36\\ca\\7c\\15\\81\\68\\6b\\8f\\3e\\b3" \ -+ "\\a2\\fc\\ae\\af\\c2\\44\\58\\15\\95\\40\\fc\\56\\19\\91\\80\\ed" \ -+ "\\42\\11\\66\\04\\ef\\3c\\e0\\76\\33\\4b\\83\\fa\\7e\\b4\\47\\dc" \ -+ "\\fb\\ed\\46\\a5\\8d\\0a\\66\\87\\a5\\ef\\7b\\74\\62\\ac\\be\\73" \ -+ "\\36\\c9\\b4\\fe\\20\\c4\\81\\f3\\fe\\78\\19\\a8\\d0\\af\\7f\\81" \ -+ "\\72\\24\\61\\d9\\76\\93\\e3\\0b\\d2\\4f\\19\\17\\33\\57\\d4\\82" \ -+ "\\b0\\f1\\a8\\03\\f6\\01\\99\\a9\\b8\\8c\\83\\c9\\ba\\19\\87\\ea" \ -+ "\\d6\\3b\\06\\eb\\4c\\f7\\f1\\e5\\28\\a9\\10\\b6\\46\\de\\e1\\e1" \ -+ "\\3f\\c1\\cc\\72\\be\\2a\\43\\c6\\f6\\d0\\b5\\a0\\c4\\24\\6e\\4f" \ -+ "\\bd\\ec\\22\\8a\\07\\11\\3d\\f9\\d3\\15\\02\\03\\01\\00\\01\\a3" \ -+ "\\82\\01\\26\\30\\82\\01\\22\\30\\1f\\06\\03\\55\\1d\\23\\04\\18" \ -+ "\\30\\16\\80\\14\\f2\\9d\\42\\4e\\0f\\c4\\48\\25\\58\\2f\\1c\\ce" \ -+ "\\0f\\a1\\3f\\22\\c8\\55\\c8\\91\\30\\3b\\06\\08\\2b\\06\\01\\05" \ -+ "\\05\\07\\01\\01\\04\\2f\\30\\2d\\30\\2b\\06\\08\\2b\\06\\01\\05" \ -+ "\\05\\07\\30\\01\\86\\1f\\68\\74\\74\\70\\3a\\2f\\2f\\69\\70\\61" \ -+ "\\2d\\63\\61\\2e\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\2f\\63\\61" \ -+ "\\2f\\6f\\63\\73\\70\\30\\0e\\06\\03\\55\\1d\\0f\\01\\01\\ff\\04" \ -+ "\\04\\03\\02\\04\\f0\\30\\1d\\06\\03\\55\\1d\\25\\04\\16\\30\\14" \ -+ "\\06\\08\\2b\\06\\01\\05\\05\\07\\03\\01\\06\\08\\2b\\06\\01\\05" \ -+ "\\05\\07\\03\\02\\30\\74\\06\\03\\55\\1d\\1f\\04\\6d\\30\\6b\\30" \ -+ "\\69\\a0\\31\\a0\\2f\\86\\2d\\68\\74\\74\\70\\3a\\2f\\2f\\69\\70" \ -+ "\\61\\2d\\63\\61\\2e\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\2f\\69" \ -+ "\\70\\61\\2f\\63\\72\\6c\\2f\\4d\\61\\73\\74\\65\\72\\43\\52\\4c" \ -+ "\\2e\\62\\69\\6e\\a2\\34\\a4\\32\\30\\30\\31\\0e\\30\\0c\\06\\03" \ -+ "\\55\\04\\0a\\0c\\05\\69\\70\\61\\63\\61\\31\\1e\\30\\1c\\06\\03" \ -+ "\\55\\04\\03\\0c\\15\\43\\65\\72\\74\\69\\66\\69\\63\\61\\74\\65" \ -+ "\\20\\41\\75\\74\\68\\6f\\72\\69\\74\\79\\30\\1d\\06\\03\\55\\1d" \ -+ "\\0e\\04\\16\\04\\14\\2d\\2b\\3f\\cb\\f5\\b2\\ff\\32\\2c\\a8\\c2" \ -+ "\\1c\\dd\\bd\\8c\\80\\1e\\dd\\31\\82\\30\\0d\\06\\09\\2a\\86\\48" \ -+ "\\86\\f7\\0d\\01\\01\\0b\\05\\00\\03\\82\\01\\01\\00\\9a\\47\\2e" \ -+ "\\50\\a7\\4d\\1d\\53\\0f\\c9\\71\\42\\0c\\e5\\da\\7d\\49\\64\\e7" \ -+ "\\ab\\c8\\df\\df\\02\\c1\\87\\d1\\5b\\de\\da\\6f\\2b\\e4\\f0\\be" \ -+ "\\ba\\09\\df\\02\\85\\0b\\8a\\e6\\9b\\06\\7d\\69\\38\\6c\\72\\ff" \ -+ "\\4c\\7b\\2a\\0d\\3f\\23\\2f\\16\\46\\ff\\05\\93\\b0\\ea\\24\\28" \ -+ "\\d7\\12\\a1\\57\\b8\\59\\19\\25\\f3\\43\\0a\\d3\\fd\\0f\\37\\8d" \ -+ "\\b8\\ca\\15\\e7\\48\\8a\\a0\\c7\\c7\\4b\\7f\\01\\3c\\58\\d7\\37" \ -+ "\\e5\\ff\\7d\\2b\\01\\ac\\0d\\9f\\51\\6a\\e5\\40\\24\\e6\\5e\\55" \ -+ "\\0d\\f7\\b8\\2f\\42\\ac\\6d\\e5\\29\\6b\\c6\\0b\\a4\\bf\\19\\bd" \ -+ "\\39\\27\\ee\\fe\\c5\\b3\\db\\62\\d4\\be\\d2\\47\\ba\\96\\30\\5a" \ -+ "\\fd\\62\\00\\b8\\27\\5d\\2f\\3a\\94\\0b\\95\\35\\85\\40\\2c\\bc" \ -+ "\\67\\df\\8a\\f9\\f1\\7b\\19\\96\\3e\\42\\48\\13\\23\\04\\95\\a9" \ -+ "\\6b\\11\\33\\81\\47\\5a\\83\\72\\f6\\20\\fa\\8e\\41\\7b\\8f\\77" \ -+ "\\47\\7c\\c7\\5d\\46\\f4\\4f\\fd\\81\\0a\\ae\\39\\27\\b6\\6a\\26" \ -+ "\\63\\b1\\d3\\bf\\55\\83\\82\\9b\\36\\6c\\33\\64\\0f\\50\\c0\\55" \ -+ "\\94\\13\\c3\\85\\f4\\d5\\71\\65\\d0\\c0\\dd\\fc\\e6\\ec\\9c\\5b" \ -+ "\\f0\\11\\b5\\2c\\f3\\48\\c1\\36\\8c\\a2\\96\\48\\84" -+ -+#define TEST_CERT2_BIN \ -+ "\\30\\82\\06\\98\\30\\82\\05\\80\\a0\\03\\02\\01\\02\\02\\0a\\61" \ -+ "\\22\\88\\c2\\00\\00\\00\\00\\02\\a6\\30\\0d\\06\\09\\2a\\86\\48" \ -+ "\\86\\f7\\0d\\01\\01\\05\\05\\00\\30\\45\\31\\15\\30\\13\\06\\0a" \ -+ "\\09\\92\\26\\89\\93\\f2\\2c\\64\\01\\19\\16\\05\\64\\65\\76\\65" \ -+ "\\6c\\31\\12\\30\\10\\06\\0a\\09\\92\\26\\89\\93\\f2\\2c\\64\\01" \ -+ "\\19\\16\\02\\61\\64\\31\\18\\30\\16\\06\\03\\55\\04\\03\\13\\0f" \ -+ "\\61\\64\\2d\\41\\44\\2d\\53\\45\\52\\56\\45\\52\\2d\\43\\41\\30" \ -+ "\\1e\\17\\0d\\31\\36\\31\\31\\31\\31\\31\\33\\35\\31\\31\\31\\5a" \ -+ "\\17\\0d\\31\\37\\31\\31\\31\\31\\31\\33\\35\\31\\31\\31\\5a\\30" \ -+ "\\70\\31\\15\\30\\13\\06\\0a\\09\\92\\26\\89\\93\\f2\\2c\\64\\01" \ -+ "\\19\\16\\05\\64\\65\\76\\65\\6c\\31\\12\\30\\10\\06\\0a\\09\\92" \ -+ "\\26\\89\\93\\f2\\2c\\64\\01\\19\\16\\02\\61\\64\\31\\0e\\30\\0c" \ -+ "\\06\\03\\55\\04\\03\\13\\05\\55\\73\\65\\72\\73\\31\\0c\\30\\0a" \ -+ "\\06\\03\\55\\04\\03\\13\\03\\74\\20\\75\\31\\25\\30\\23\\06\\09" \ -+ "\\2a\\86\\48\\86\\f7\\0d\\01\\09\\01\\16\\16\\74\\65\\73\\74\\2e" \ -+ "\\75\\73\\65\\72\\40\\65\\6d\\61\\69\\6c\\2e\\64\\6f\\6d\\61\\69" \ -+ "\\6e\\30\\82\\01\\22\\30\\0d\\06\\09\\2a\\86\\48\\86\\f7\\0d\\01" \ -+ "\\01\\01\\05\\00\\03\\82\\01\\0f\\00\\30\\82\\01\\0a\\02\\82\\01" \ -+ "\\01\\00\\9c\\cf\\36\\99\\de\\63\\74\\2b\\77\\25\\9e\\24\\d9\\77" \ -+ "\\4b\\5f\\98\\c0\\8c\\d7\\20\\91\\c0\\1c\\e8\\37\\45\\bf\\3c\\d9" \ -+ "\\33\\bd\\e9\\de\\c9\\5d\\d4\\cd\\06\\0a\\0d\\d4\\f1\\7c\\74\\5b" \ -+ "\\29\\d5\\66\\9c\\2c\\9f\\6b\\1a\\0f\\0d\\e6\\6c\\62\\a5\\41\\4f" \ -+ "\\c3\\a4\\88\\27\\11\\5d\\b7\\b1\\fb\\f8\\8d\\ee\\43\\8d\\93\\b5" \ -+ "\\8c\\b4\\34\\06\\f5\\e9\\2f\\5a\\26\\68\\d7\\43\\60\\82\\5e\\22" \ -+ "\\a7\\c6\\34\\40\\19\\a5\\8e\\f0\\58\\9f\\16\\2d\\43\\3f\\0c\\da" \ -+ "\\e2\\23\\f6\\09\\2a\\5e\\bd\\84\\27\\c8\\ab\\d5\\70\\f8\\3d\\9c" \ -+ "\\14\\c2\\c2\\a2\\77\\e8\\44\\73\\10\\01\\34\\40\\1f\\c6\\2f\\a0" \ -+ "\\70\\ee\\2f\\d5\\4b\\be\\4c\\c7\\45\\f7\\ac\\9c\\c3\\68\\5b\\1d" \ -+ "\\5a\\4b\\77\\65\\76\\e4\\b3\\92\\f4\\84\\0a\\9e\\6a\\9c\\c9\\53" \ -+ "\\42\\9f\\6d\\fe\\f9\\f5\\f2\\9a\\15\\50\\47\\ef\\f4\\06\\59\\c8" \ -+ "\\50\\48\\4b\\46\\95\\68\\25\\c5\\bd\\4f\\65\\34\\00\\fc\\31\\69" \ -+ "\\f8\\3e\\e0\\20\\83\\41\\27\\0b\\5c\\46\\98\\14\\f0\\07\\de\\02" \ -+ "\\17\\b1\\d2\\9c\\be\\1c\\0d\\56\\22\\1b\\02\\fe\\da\\69\\b9\\ef" \ -+ "\\91\\37\\39\\7f\\24\\da\\c4\\81\\5e\\82\\31\\2f\\98\\1d\\f7\\73" \ -+ "\\5b\\23\\02\\03\\01\\00\\01\\a3\\82\\03\\5d\\30\\82\\03\\59\\30" \ -+ "\\3d\\06\\09\\2b\\06\\01\\04\\01\\82\\37\\15\\07\\04\\30\\30\\2e" \ -+ "\\06\\26\\2b\\06\\01\\04\\01\\82\\37\\15\\08\\87\\85\\a1\\23\\84" \ -+ "\\c8\\b2\\26\\83\\9d\\9d\\21\\82\\d4\\a6\\1b\\86\\a3\\ba\\37\\81" \ -+ "\\10\\85\\89\\d5\\02\\d6\\8f\\24\\02\\01\\64\\02\\01\\02\\30\\29" \ -+ "\\06\\03\\55\\1d\\25\\04\\22\\30\\20\\06\\08\\2b\\06\\01\\05\\05" \ -+ "\\07\\03\\02\\06\\08\\2b\\06\\01\\05\\05\\07\\03\\04\\06\\0a\\2b" \ -+ "\\06\\01\\04\\01\\82\\37\\0a\\03\\04\\30\\0e\\06\\03\\55\\1d\\0f" \ -+ "\\01\\01\\ff\\04\\04\\03\\02\\05\\a0\\30\\35\\06\\09\\2b\\06\\01" \ -+ "\\04\\01\\82\\37\\15\\0a\\04\\28\\30\\26\\30\\0a\\06\\08\\2b\\06" \ -+ "\\01\\05\\05\\07\\03\\02\\30\\0a\\06\\08\\2b\\06\\01\\05\\05\\07" \ -+ "\\03\\04\\30\\0c\\06\\0a\\2b\\06\\01\\04\\01\\82\\37\\0a\\03\\04" \ -+ "\\30\\81\\94\\06\\09\\2a\\86\\48\\86\\f7\\0d\\01\\09\\0f\\04\\81" \ -+ "\\86\\30\\81\\83\\30\\0b\\06\\09\\60\\86\\48\\01\\65\\03\\04\\01" \ -+ "\\2a\\30\\0b\\06\\09\\60\\86\\48\\01\\65\\03\\04\\01\\2d\\30\\0b" \ -+ "\\06\\09\\60\\86\\48\\01\\65\\03\\04\\01\\16\\30\\0b\\06\\09\\60" \ -+ "\\86\\48\\01\\65\\03\\04\\01\\19\\30\\0b\\06\\09\\60\\86\\48\\01" \ -+ "\\65\\03\\04\\01\\02\\30\\0b\\06\\09\\60\\86\\48\\01\\65\\03\\04" \ -+ "\\01\\05\\30\\0a\\06\\08\\2a\\86\\48\\86\\f7\\0d\\03\\07\\30\\07" \ -+ "\\06\\05\\2b\\0e\\03\\02\\07\\30\\0e\\06\\08\\2a\\86\\48\\86\\f7" \ -+ "\\0d\\03\\02\\02\\02\\00\\80\\30\\0e\\06\\08\\2a\\86\\48\\86\\f7" \ -+ "\\0d\\03\\04\\02\\02\\02\\00\\30\\1d\\06\\03\\55\\1d\\0e\\04\\16" \ -+ "\\04\\14\\49\\ac\\ad\\e0\\65\\30\\c4\\ce\\a0\\09\\03\\5b\\ad\\4a" \ -+ "\\7b\\49\\5e\\c9\\6c\\b4\\30\\1f\\06\\03\\55\\1d\\23\\04\\18\\30" \ -+ "\\16\\80\\14\\62\\50\\b6\\8d\\a1\\e6\\2d\\91\\bf\\b0\\54\\4d\\8f" \ -+ "\\a8\\ca\\10\\ae\\b8\\dd\\54\\30\\81\\cc\\06\\03\\55\\1d\\1f\\04" \ -+ "\\81\\c4\\30\\81\\c1\\30\\81\\be\\a0\\81\\bb\\a0\\81\\b8\\86\\81" \ -+ "\\b5\\6c\\64\\61\\70\\3a\\2f\\2f\\2f\\43\\4e\\3d\\61\\64\\2d\\41" \ -+ "\\44\\2d\\53\\45\\52\\56\\45\\52\\2d\\43\\41\\2c\\43\\4e\\3d\\61" \ -+ "\\64\\2d\\73\\65\\72\\76\\65\\72\\2c\\43\\4e\\3d\\43\\44\\50\\2c" \ -+ "\\43\\4e\\3d\\50\\75\\62\\6c\\69\\63\\25\\32\\30\\4b\\65\\79\\25" \ -+ "\\32\\30\\53\\65\\72\\76\\69\\63\\65\\73\\2c\\43\\4e\\3d\\53\\65" \ -+ "\\72\\76\\69\\63\\65\\73\\2c\\43\\4e\\3d\\43\\6f\\6e\\66\\69\\67" \ -+ "\\75\\72\\61\\74\\69\\6f\\6e\\2c\\44\\43\\3d\\61\\64\\2c\\44\\43" \ -+ "\\3d\\64\\65\\76\\65\\6c\\3f\\63\\65\\72\\74\\69\\66\\69\\63\\61" \ -+ "\\74\\65\\52\\65\\76\\6f\\63\\61\\74\\69\\6f\\6e\\4c\\69\\73\\74" \ -+ "\\3f\\62\\61\\73\\65\\3f\\6f\\62\\6a\\65\\63\\74\\43\\6c\\61\\73" \ -+ "\\73\\3d\\63\\52\\4c\\44\\69\\73\\74\\72\\69\\62\\75\\74\\69\\6f" \ -+ "\\6e\\50\\6f\\69\\6e\\74\\30\\81\\be\\06\\08\\2b\\06\\01\\05\\05" \ -+ "\\07\\01\\01\\04\\81\\b1\\30\\81\\ae\\30\\81\\ab\\06\\08\\2b\\06" \ -+ "\\01\\05\\05\\07\\30\\02\\86\\81\\9e\\6c\\64\\61\\70\\3a\\2f\\2f" \ -+ "\\2f\\43\\4e\\3d\\61\\64\\2d\\41\\44\\2d\\53\\45\\52\\56\\45\\52" \ -+ "\\2d\\43\\41\\2c\\43\\4e\\3d\\41\\49\\41\\2c\\43\\4e\\3d\\50\\75" \ -+ "\\62\\6c\\69\\63\\25\\32\\30\\4b\\65\\79\\25\\32\\30\\53\\65\\72" \ -+ "\\76\\69\\63\\65\\73\\2c\\43\\4e\\3d\\53\\65\\72\\76\\69\\63\\65" \ -+ "\\73\\2c\\43\\4e\\3d\\43\\6f\\6e\\66\\69\\67\\75\\72\\61\\74\\69" \ -+ "\\6f\\6e\\2c\\44\\43\\3d\\61\\64\\2c\\44\\43\\3d\\64\\65\\76\\65" \ -+ "\\6c\\3f\\63\\41\\43\\65\\72\\74\\69\\66\\69\\63\\61\\74\\65\\3f" \ -+ "\\62\\61\\73\\65\\3f\\6f\\62\\6a\\65\\63\\74\\43\\6c\\61\\73\\73" \ -+ "\\3d\\63\\65\\72\\74\\69\\66\\69\\63\\61\\74\\69\\6f\\6e\\41\\75" \ -+ "\\74\\68\\6f\\72\\69\\74\\79\\30\\3f\\06\\03\\55\\1d\\11\\04\\38" \ -+ "\\30\\36\\a0\\1c\\06\\0a\\2b\\06\\01\\04\\01\\82\\37\\14\\02\\03" \ -+ "\\a0\\0e\\0c\\0c\\74\\75\\31\\40\\61\\64\\2e\\64\\65\\76\\65\\6c" \ -+ "\\81\\16\\74\\65\\73\\74\\2e\\75\\73\\65\\72\\40\\65\\6d\\61\\69" \ -+ "\\6c\\2e\\64\\6f\\6d\\61\\69\\6e\\30\\0d\\06\\09\\2a\\86\\48\\86" \ -+ "\\f7\\0d\\01\\01\\05\\05\\00\\03\\82\\01\\01\\00\\41\\45\\0a\\6d" \ -+ "\\bb\\7f\\5c\\07\\0c\\c9\\b0\\39\\55\\6d\\7c\\b5\\02\\cd\\e8\\b2" \ -+ "\\e5\\02\\94\\77\\60\\db\\d1\\af\\1d\\db\\44\\5f\\ce\\83\\db\\80" \ -+ "\\2e\\e2\\b2\\08\\25\\82\\14\\cb\\48\\95\\20\\13\\6c\\a9\\aa\\f8" \ -+ "\\31\\56\\ed\\c0\\3b\\d4\\ae\\2e\\e3\\8f\\05\\fc\\ab\\5f\\2a\\69" \ -+ "\\23\\bc\\b8\\8c\\ec\\2d\\a9\\0b\\86\\95\\73\\73\\db\\17\\ce\\c6" \ -+ "\\ae\\c5\\b4\\c1\\25\\87\\3b\\67\\43\\9e\\87\\5a\\e6\\b9\\a0\\28" \ -+ "\\12\\3d\\a8\\2e\\d7\\5e\\ef\\65\\2d\\e6\\a5\\67\\84\\ac\\fd\\31" \ -+ "\\c1\\78\\d8\\72\\51\\a2\\88\\55\\0f\\97\\47\\93\\07\\ea\\8a\\53" \ -+ "\\27\\4e\\34\\54\\34\\1f\\a0\\6a\\03\\44\\fb\\23\\61\\8e\\87\\8e" \ -+ "\\3c\\d0\\8f\\ae\\e4\\cf\\ee\\65\\a8\\ba\\96\\68\\08\\1c\\60\\e2" \ -+ "\\4e\\11\\a3\\74\\b8\\a5\\4e\\ea\\6a\\82\\4c\\c2\\4d\\63\\8e\\9f" \ -+ "\\7c\\2f\\a8\\c0\\62\\f8\\f7\\d9\\25\\c4\\91\\ab\\4d\\6a\\44\\af" \ -+ "\\75\\93\\53\\03\\a4\\99\\c8\\cd\\91\\89\\60\\75\\30\\99\\76\\05" \ -+ "\\5a\\a0\\03\\a7\\a1\\2c\\03\\04\\8f\\d4\\5a\\31\\52\\28\\5a\\e6" \ -+ "\\a2\\d3\\43\\21\\5b\\dc\\a2\\1d\\55\\a9\\48\\c5\\c4\\aa\\f3\\8b" \ -+ "\\e6\\3e\\75\\96\\e4\\3e\\64\\af\\e8\\a7\\6a\\b6" -+ -+static void test_sss_certmap_get_search_filter(void **state) -+{ -+ int ret; -+ struct sss_certmap_ctx *ctx; -+ char *filter; -+ char **domains; -+ const char *dom_list[] = {"test.dom", NULL}; -+ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ -+ ret = sss_certmap_add_rule(ctx, 100, -+ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", -+ "LDAP:rule100={issuer_dn}{subject_dn}", NULL); -+ assert_int_equal(ret, 0); -+ -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), -+ sizeof(test_cert_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "rule100=CN=Certificate Authority,O=IPA.DEVEL" -+ "CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); -+ assert_null(domains); -+ -+ ret = sss_certmap_add_rule(ctx, 99, -+ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", -+ "LDAP:rule99={issuer_dn}{subject_dn}", -+ dom_list); -+ assert_int_equal(ret, 0); -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), -+ sizeof(test_cert_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "rule99=CN=Certificate Authority,O=IPA.DEVEL" -+ "CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); -+ assert_non_null(domains); -+ assert_string_equal(domains[0], "test.dom"); -+ assert_null(domains[1]); -+ -+ ret = sss_certmap_add_rule(ctx, 98, -+ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", -+ "LDAP:rule98=userCertificate;binary={cert!bin}", -+ dom_list); -+ assert_int_equal(ret, 0); -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), -+ sizeof(test_cert_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "rule98=userCertificate;binary=" TEST_CERT_BIN); -+ assert_non_null(domains); -+ assert_string_equal(domains[0], "test.dom"); -+ assert_null(domains[1]); -+ -+ ret = sss_certmap_add_rule(ctx, 97, -+ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", -+ "LDAP:rule97={issuer_dn!nss_x500}{subject_dn}", -+ dom_list); -+ assert_int_equal(ret, 0); -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), -+ sizeof(test_cert_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "rule97=O=IPA.DEVEL,CN=Certificate Authority" -+ "CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); -+ assert_non_null(domains); -+ assert_string_equal(domains[0], "test.dom"); -+ assert_null(domains[1]); -+ -+ ret = sss_certmap_add_rule(ctx, 96, -+ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", -+ "LDAP:rule96={issuer_dn!nss_x500}{subject_dn!nss_x500}", -+ dom_list); -+ assert_int_equal(ret, 0); -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), -+ sizeof(test_cert_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "rule96=O=IPA.DEVEL,CN=Certificate Authority" -+ "O=IPA.DEVEL,CN=ipa-devel.ipa.devel"); -+ assert_non_null(domains); -+ assert_string_equal(domains[0], "test.dom"); -+ assert_null(domains[1]); -+ -+ ret = sss_certmap_add_rule(ctx, 95, -+ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", -+ NULL, NULL); -+ assert_int_equal(ret, 0); -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), -+ sizeof(test_cert_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "(userCertificate;binary=" TEST_CERT_BIN ")"); -+ assert_null(domains); -+ -+ ret = sss_certmap_add_rule(ctx, 94, -+ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", -+ "LDAP:rule94={issuer_dn!ad_x500}{subject_dn!ad_x500}", -+ dom_list); -+ assert_int_equal(ret, 0); -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), -+ sizeof(test_cert_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "rule94=O=IPA.DEVEL,CN=Certificate Authority" -+ "O=IPA.DEVEL,CN=ipa-devel.ipa.devel"); -+ assert_non_null(domains); -+ assert_string_equal(domains[0], "test.dom"); -+ assert_null(domains[1]); -+ -+ -+ ret = sss_certmap_add_rule(ctx, 89, NULL, -+ "(rule89={subject_nt_principal})", -+ NULL); -+ assert_int_equal(ret, 0); -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der), -+ sizeof(test_cert2_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "(rule89=tu1@ad.devel)"); -+ assert_null(domains); -+ -+ ret = sss_certmap_add_rule(ctx, 88, NULL, -+ "(rule88={subject_nt_principal.short_name})", -+ NULL); -+ assert_int_equal(ret, 0); -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der), -+ sizeof(test_cert2_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "(rule88=tu1)"); -+ assert_null(domains); -+ -+ ret = sss_certmap_add_rule(ctx, 87, NULL, -+ "LDAP:rule87={issuer_dn!nss_x500}{subject_dn!nss_x500}", -+ NULL); -+ assert_int_equal(ret, 0); -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der), -+ sizeof(test_cert2_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "rule87=DC=devel,DC=ad,CN=ad-AD-SERVER-CA" -+ "DC=devel,DC=ad,CN=Users,CN=t u,E=test.user@email.domain"); -+ assert_null(domains); -+ -+ ret = sss_certmap_add_rule(ctx, 86, NULL, -+ "LDAP:rule86={issuer_dn!ad_x500}{subject_dn!ad_x500}", -+ NULL); -+ assert_int_equal(ret, 0); -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der), -+ sizeof(test_cert2_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "rule86=DC=devel,DC=ad,CN=ad-AD-SERVER-CA" -+ "DC=devel,DC=ad,CN=Users,CN=t u,E=test.user@email.domain"); -+ assert_null(domains); -+ -+ -+ sss_certmap_free_ctx(ctx); -+ -+ /* check defaults when no rules are added yet */ -+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ctx); -+ assert_null(ctx->prio_list); -+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der), -+ sizeof(test_cert2_der), -+ &filter, &domains); -+ assert_int_equal(ret, 0); -+ assert_non_null(filter); -+ assert_string_equal(filter, "(userCertificate;binary=" TEST_CERT2_BIN")"); -+ assert_null(domains); -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ int rv; -+ poptContext pc; -+ int opt; -+ struct poptOption long_options[] = { -+ POPT_AUTOHELP -+ SSSD_DEBUG_OPTS -+ POPT_TABLEEND -+ }; -+ -+ const struct CMUnitTest tests[] = { -+ cmocka_unit_test(test_sss_certmap_init), -+ cmocka_unit_test(test_sss_certmap_add_rule), -+ cmocka_unit_test(test_sss_certmap_add_matching_rule), -+ cmocka_unit_test(test_check_ad_attr_name), -+ cmocka_unit_test(test_sss_cert_get_content), -+ cmocka_unit_test(test_sss_cert_get_content_2), -+ cmocka_unit_test(test_sss_certmap_match_cert), -+ cmocka_unit_test(test_sss_certmap_add_mapping_rule), -+ cmocka_unit_test(test_sss_certmap_get_search_filter), -+ }; -+ -+ /* Set debug level to invalid value so we can deside if -d 0 was used. */ -+ debug_level = SSSDBG_INVALID; -+ -+ pc = poptGetContext(argv[0], argc, argv, long_options, 0); -+ while((opt = poptGetNextOpt(pc)) != -1) { -+ switch(opt) { -+ default: -+ fprintf(stderr, "\nInvalid option %s: %s\n\n", -+ poptBadOption(pc, 0), poptStrerror(opt)); -+ poptPrintUsage(pc, stderr, 0); -+ return 1; -+ } -+ } -+ poptFreeContext(pc); -+ -+ DEBUG_CLI_INIT(debug_level); -+ -+#ifdef HAVE_NSS -+ nspr_nss_init(); -+#endif -+ -+ tests_set_cwd(); -+ rv = cmocka_run_group_tests(tests, NULL, NULL); -+ -+#ifdef HAVE_NSS -+ /* Cleanup NSS and NSPR to make valgrind happy. */ -+ nspr_nss_cleanup(); -+#endif -+ -+ return rv; -+} -diff --git a/src/tests/dlopen-tests.c b/src/tests/dlopen-tests.c -index 419857cc739d197493e46629d00aa5fb6cfde824..3914317de90f870fab42d2d72d8e2eb5ea8d9e14 100644 ---- a/src/tests/dlopen-tests.c -+++ b/src/tests/dlopen-tests.c -@@ -45,6 +45,7 @@ struct so { - { "libsss_idmap.so", { LIBPFX"libsss_idmap.so", NULL } }, - { "libsss_nss_idmap.so", { LIBPFX"libsss_nss_idmap.so", NULL } }, - { "libnss_sss.so", { LIBPFX"libnss_sss.so", NULL } }, -+ { "libsss_certmap.so", { LIBPFX"libsss_certmap.so", NULL } }, - { "pam_sss.so", { LIBPFX"pam_sss.so", NULL } }, - #ifdef BUILD_LIBWBCLIENT - { "libwbclient.so", { LIBPFX"libwbclient.so", NULL } }, --- -2.9.3 - diff --git a/SOURCES/0005-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch b/SOURCES/0005-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch new file mode 100644 index 0000000..017e97c --- /dev/null +++ b/SOURCES/0005-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch @@ -0,0 +1,33 @@ +From 8e4858a044391cdfd7b6eae327daf043225c4536 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Oct 2017 12:36:02 +0200 +Subject: [PATCH 05/21] CONFDB: Remove the obsolete option magic_private_groups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since this confdb definition was completely unused across the codebase, +this patch just removes the definition. + +Reviewed-by: Pavel Březina +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 8fab9d6fa88824b20d3febe697147c407d31c160) +--- + src/confdb/confdb.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 2539b906993edbceb38aac9265e04deed69cf2e4..1471949623e9dd7a8536e3ac3048a10227a5d857 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -197,7 +197,6 @@ + "cache_credentials_minimal_first_factor_length" + #define CONFDB_DEFAULT_CACHE_CREDS_MIN_FF_LENGTH 8 + #define CONFDB_DOMAIN_LEGACY_PASS "store_legacy_passwords" +-#define CONFDB_DOMAIN_MPG "magic_private_groups" + #define CONFDB_DOMAIN_AUTO_UPG "auto_private_groups" + #define CONFDB_DOMAIN_FQ "use_fully_qualified_names" + #define CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT "entry_cache_timeout" +-- +2.13.5 + diff --git a/SOURCES/0005-certmap-add-placeholder-for-OpenSSL-implementation.patch b/SOURCES/0005-certmap-add-placeholder-for-OpenSSL-implementation.patch deleted file mode 100644 index 99a2bd8..0000000 --- a/SOURCES/0005-certmap-add-placeholder-for-OpenSSL-implementation.patch +++ /dev/null @@ -1,151 +0,0 @@ -From b1336bdfeacf904c8fdec04e06d8b90ef9ad15b3 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 15 Mar 2017 10:57:09 +0100 -Subject: [PATCH 05/15] certmap: add placeholder for OpenSSL implementation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - Makefile.am | 30 +++++++++++++++++++++-------- - src/lib/certmap/sss_cert_content_crypto.c | 32 +++++++++++++++++++++++++++++++ - src/lib/certmap/sss_certmap_int.h | 8 +++++--- - 3 files changed, 59 insertions(+), 11 deletions(-) - create mode 100644 src/lib/certmap/sss_cert_content_crypto.c - -diff --git a/Makefile.am b/Makefile.am -index 8ca12c10d2713b6a72361d84b25486500c79f407..7947b7a5fbe3ca1034baac1c13c53300994b1bf8 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -278,9 +278,12 @@ if HAVE_CMOCKA - simple-access-tests \ - krb5_common_test \ - test_iobuf \ -- sss_certmap_test \ - $(NULL) - -+if HAVE_NSS -+non_interactive_cmocka_based_tests += sss_certmap_test -+endif #HAVE_NSS -+ - if HAVE_LIBRESOLV - non_interactive_cmocka_based_tests += test_resolv_fake - endif # HAVE_LIBRESOLV -@@ -1715,7 +1718,6 @@ sssd_check_socket_activated_responders_LDADD = \ - $(NULL) - endif - --if HAVE_NSS - pkgconfig_DATA += src/lib/certmap/sss_certmap.pc - libsss_certmap_la_DEPENDENCIES = src/lib/certmap/sss_certmap.exports - libsss_certmap_la_SOURCES = \ -@@ -1726,26 +1728,38 @@ libsss_certmap_la_SOURCES = \ - src/lib/certmap/sss_certmap_ldap_mapping.c \ - src/util/util_ext.c \ - src/util/cert/cert_common.c \ -- src/util/crypto/nss/nss_base64.c \ -- src/util/cert/nss/cert.c \ -- src/util/crypto/nss/nss_util.c \ - $(NULL) - libsss_certmap_la_CFLAGS = \ - $(AM_CFLAGS) \ - $(TALLOC_CFLAGS) \ -- $(NSS_CFLAGS) \ - $(NULL) - libsss_certmap_la_LIBADD = \ - $(TALLOC_LIBS) \ -- $(NSS_LIBS) \ - $(NULL) - libsss_certmap_la_LDFLAGS = \ - -Wl,--version-script,$(srcdir)/src/lib/certmap/sss_certmap.exports \ - -version-info 0:0:0 - -+if HAVE_NSS -+libsss_certmap_la_SOURCES += \ -+ src/util/crypto/nss/nss_base64.c \ -+ src/util/cert/nss/cert.c \ -+ src/util/crypto/nss/nss_util.c \ -+ $(NULL) -+libsss_certmap_la_CFLAGS += $(NSS_CFLAGS) -+libsss_certmap_la_LIBADD += $(NSS_LIBS) -+else -+libsss_certmap_la_SOURCES += \ -+ src/util/crypto/libcrypto/crypto_base64.c \ -+ src/util/cert/libcrypto/cert.c \ -+ $(NULL) -+ -+libsss_certmap_la_CFLAGS += $(CRYPTO_CFLAGS) -+libsss_certmap_la_LIBADD += $(CRYPTO_LIBS) -+endif -+ - dist_noinst_DATA += src/lib/certmap/sss_certmap.exports - dist_noinst_HEADERS += src/lib/certmap/sss_certmap_int.h --endif - - ################# - # Feature Tests # -diff --git a/src/lib/certmap/sss_cert_content_crypto.c b/src/lib/certmap/sss_cert_content_crypto.c -new file mode 100644 -index 0000000000000000000000000000000000000000..bddcf9bce986bd986aa0aa5f16a0744a97ab36d6 ---- /dev/null -+++ b/src/lib/certmap/sss_cert_content_crypto.c -@@ -0,0 +1,32 @@ -+/* -+ SSSD - certificate handling utils - OpenSSL version -+ The calls defined here should be useable outside of SSSD as well, e.g. in -+ libsss_certmap. -+ -+ Copyright (C) Sumit Bose 2017 -+ -+ 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 "lib/certmap/sss_certmap.h" -+#include "lib/certmap/sss_certmap_int.h" -+ -+int sss_cert_get_content(TALLOC_CTX *mem_ctx, -+ const uint8_t *der_blob, size_t der_size, -+ struct sss_cert_content **content) -+{ -+ return EINVAL; -+} -diff --git a/src/lib/certmap/sss_certmap_int.h b/src/lib/certmap/sss_certmap_int.h -index 28f1c596cfb5e78077b6a8e9baefa88b4900a022..0b4cda73639be9b323ac3388f97be90bc1a771f2 100644 ---- a/src/lib/certmap/sss_certmap_int.h -+++ b/src/lib/certmap/sss_certmap_int.h -@@ -22,12 +22,14 @@ - along with this program. If not, see . - */ - --#include --#include -- - #ifndef __SSS_CERTMAP_INT_H__ - #define __SSS_CERTMAP_INT_H__ - -+#include -+#include -+#include -+#include -+ - #define CM_DEBUG(cm_ctx, format, ...) do { \ - if (cm_ctx != NULL && cm_ctx->debug != NULL) { \ - cm_ctx->debug(cm_ctx->debug_priv, __FILE__, __LINE__, __FUNCTION__, \ --- -2.9.3 - diff --git a/SOURCES/0006-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch b/SOURCES/0006-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch new file mode 100644 index 0000000..29bb20b --- /dev/null +++ b/SOURCES/0006-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch @@ -0,0 +1,167 @@ +From c28d61203655dd41cd8eb69752e435d3241e63b2 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Oct 2017 12:34:49 +0200 +Subject: [PATCH 06/21] SDAP: Allow the mpg flag for the main domain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit allows saving the users in the MPG domain in the SDAP +layer. + +The commit contains the following changes: + - abstracts the change where if the primary GID exists in the original + object, it is saved instead as the SYSDB_PRIMARY_GROUP_GIDNUM attribute, + which will allow the original primary GID to be exposed as a + secondary group + + - if the primary GID does not exist, no SYSDB_PRIMARY_GROUP_GIDNUM + is added. This will allow to handle LDAP objects that only contain + the UID but no GID. Since this is a new use-case, a test is added + later + + - a branch that handles the above is added to sdap_save_user() also + for joined domains that set the MPG flag. Previously, only + subdomains were handled. + + - to allow passing GID=0 to the sysdb layer, the range check is + relaxed. + +Related: + https://pagure.io/SSSD/sssd/issue/1872 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +(cherry picked from commit cdb74b2cc6cc3fe52969712907c9eb4026c7a44f) +--- + src/providers/ldap/sdap_async_users.c | 83 +++++++++++++++++++++++++++++++---- + 1 file changed, 75 insertions(+), 8 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c +index 09d096e84cac6c9d52bcde0e1587c47dbd88b504..7338b4a15694b1d0a16723990130a23a7280af5f 100644 +--- a/src/providers/ldap/sdap_async_users.c ++++ b/src/providers/ldap/sdap_async_users.c +@@ -136,6 +136,38 @@ static errno_t sdap_set_non_posix_flag(struct sysdb_attrs *attrs, + return EOK; + } + ++static int sdap_user_set_mpg(struct sysdb_attrs *user_attrs, ++ gid_t *_gid) ++{ ++ errno_t ret; ++ ++ if (_gid == NULL) { ++ return EINVAL; ++ } ++ ++ if (*_gid == 0) { ++ /* The original entry had no GID number. This is OK, we just won't add ++ * the SYSDB_PRIMARY_GROUP_GIDNUM attribute ++ */ ++ return EOK; ++ } ++ ++ ret = sysdb_attrs_add_uint32(user_attrs, ++ SYSDB_PRIMARY_GROUP_GIDNUM, ++ (uint32_t) *_gid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_uint32 failed.\n"); ++ return ret; ++ } ++ ++ /* We won't really store gidNumber=0, but the zero value tells ++ * the sysdb layer that no GID is set, which sysdb requires for ++ * MPG-enabled domains ++ */ ++ *_gid = 0; ++ return EOK; ++} ++ + /* FIXME: support storing additional attributes */ + int sdap_save_user(TALLOC_CTX *memctx, + struct sdap_options *opts, +@@ -357,7 +389,7 @@ int sdap_save_user(TALLOC_CTX *memctx, + goto done; + } + +- if (IS_SUBDOMAIN(dom)) { ++ if (IS_SUBDOMAIN(dom) || dom->mpg == true) { + /* For subdomain users, only create the private group as + * the subdomain is an MPG domain. + * But we have to save the GID of the original primary group +@@ -365,14 +397,13 @@ int sdap_save_user(TALLOC_CTX *memctx, + * typically (Unix and AD) the user is not listed in his primary + * group as a member. + */ +- ret = sysdb_attrs_add_uint32(user_attrs, SYSDB_PRIMARY_GROUP_GIDNUM, +- (uint32_t) gid); ++ ret = sdap_user_set_mpg(user_attrs, &gid); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_uint32 failed.\n"); ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sdap_user_set_mpg failed [%d]: %s\n", ret, ++ sss_strerror(ret)); + goto done; + } +- +- gid = 0; + } + + /* Store the GID in the ldap_attrs so it doesn't get +@@ -380,6 +411,41 @@ int sdap_save_user(TALLOC_CTX *memctx, + */ + ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, gid); + if (ret != EOK) goto done; ++ } else if (dom->mpg) { ++ /* Likewise, if a domain is set to contain 'magic private groups', do ++ * not process the real GID, but save it in the cache as originalGID ++ * (if available) ++ */ ++ ret = sysdb_attrs_get_uint32_t(attrs, ++ opts->user_map[SDAP_AT_USER_GID].sys_name, ++ &gid); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Missing GID, won't save the %s attribute\n", ++ SYSDB_PRIMARY_GROUP_GIDNUM); ++ ++ /* Store the UID as GID (since we're in a MPG domain so that it doesn't ++ * get treated as a missing attribute and removed ++ */ ++ ret = sdap_replace_id(attrs, SYSDB_GIDNUM, uid); ++ if (ret) { ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot set the id-mapped UID\n"); ++ goto done; ++ } ++ gid = 0; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot retrieve GID, won't save the %s attribute\n", ++ SYSDB_PRIMARY_GROUP_GIDNUM); ++ gid = 0; ++ } ++ ++ ret = sdap_user_set_mpg(user_attrs, &gid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sdap_user_set_mpg failed [%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } + } else { + ret = sysdb_attrs_get_uint32_t(attrs, + opts->user_map[SDAP_AT_USER_GID].sys_name, +@@ -403,8 +469,9 @@ int sdap_save_user(TALLOC_CTX *memctx, + } + + /* check that the gid is valid for this domain */ +- if (is_posix == true && IS_SUBDOMAIN(dom) == false && +- OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) { ++ if (is_posix == true && IS_SUBDOMAIN(dom) == false ++ && dom->mpg == false ++ && OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) { + DEBUG(SSSDBG_CRIT_FAILURE, + "User [%s] filtered out! (primary gid out of range)\n", + user_name); +-- +2.13.5 + diff --git a/SOURCES/0006-sysdb-add-sysdb_attrs_copy.patch b/SOURCES/0006-sysdb-add-sysdb_attrs_copy.patch deleted file mode 100644 index f41c5e7..0000000 --- a/SOURCES/0006-sysdb-add-sysdb_attrs_copy.patch +++ /dev/null @@ -1,173 +0,0 @@ -From cae55d342a5f5c5ac22ac913b9251c2112b22c42 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 21 Sep 2015 12:32:48 +0200 -Subject: [PATCH 06/15] sysdb: add sysdb_attrs_copy() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - src/db/sysdb.c | 24 ++++++++++++++ - src/db/sysdb.h | 1 + - src/tests/sysdb-tests.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 112 insertions(+) - -diff --git a/src/db/sysdb.c b/src/db/sysdb.c -index 5160e3df3810a113d4ec1371350e51a074aaa146..98b7afbfab5141fa9b63a4aab31c620545b3c1f2 100644 ---- a/src/db/sysdb.c -+++ b/src/db/sysdb.c -@@ -752,6 +752,30 @@ done: - return ret; - } - -+errno_t sysdb_attrs_copy(struct sysdb_attrs *src, struct sysdb_attrs *dst) -+{ -+ int ret; -+ size_t c; -+ size_t d; -+ -+ if (src == NULL || dst == NULL) { -+ return EINVAL; -+ } -+ -+ for (c = 0; c < src->num; c++) { -+ for (d = 0; d < src->a[c].num_values; d++) { -+ ret = sysdb_attrs_add_val_safe(dst, src->a[c].name, -+ &src->a[c].values[d]); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n"); -+ return ret; -+ } -+ } -+ } -+ -+ return EOK; -+} -+ - int sysdb_attrs_users_from_str_list(struct sysdb_attrs *attrs, - const char *attr_name, - const char *domain, -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 83d0d794c737c094d1fd52e7cc7f2113b5d9a7a0..c677957bb639e40db2f985205160612094302e78 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -352,6 +352,7 @@ int sysdb_attrs_add_lc_name_alias_safe(struct sysdb_attrs *attrs, - int sysdb_attrs_copy_values(struct sysdb_attrs *src, - struct sysdb_attrs *dst, - const char *name); -+errno_t sysdb_attrs_copy(struct sysdb_attrs *src, struct sysdb_attrs *dst); - int sysdb_attrs_get_el(struct sysdb_attrs *attrs, const char *name, - struct ldb_message_element **el); - int sysdb_attrs_get_el_ext(struct sysdb_attrs *attrs, const char *name, -diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c -index 013b01a9a68d9de87d796d3aff41d98cef8cccc3..c343c734a27a335303974b6866a5d9e88d4c307e 100644 ---- a/src/tests/sysdb-tests.c -+++ b/src/tests/sysdb-tests.c -@@ -4997,6 +4997,92 @@ START_TEST(test_sysdb_attrs_add_string_safe) - } - END_TEST - -+START_TEST(test_sysdb_attrs_copy) -+{ -+ int ret; -+ struct sysdb_attrs *src; -+ struct sysdb_attrs *dst; -+ TALLOC_CTX *tmp_ctx; -+ const char *val; -+ const char **array; -+ -+ ret = sysdb_attrs_copy(NULL, NULL); -+ fail_unless(ret == EINVAL, "Wrong return code"); -+ -+ tmp_ctx = talloc_new(NULL); -+ fail_unless(tmp_ctx != NULL, "talloc_new failed"); -+ -+ src = sysdb_new_attrs(tmp_ctx); -+ fail_unless(src != NULL, "sysdb_new_attrs failed"); -+ -+ ret = sysdb_attrs_copy(src, NULL); -+ fail_unless(ret == EINVAL, "Wrong return code"); -+ -+ dst = sysdb_new_attrs(tmp_ctx); -+ fail_unless(dst != NULL, "sysdb_new_attrs failed"); -+ -+ ret = sysdb_attrs_copy(NULL, dst); -+ fail_unless(ret == EINVAL, "Wrong return code"); -+ -+ ret = sysdb_attrs_copy(src, dst); -+ fail_unless(ret == EOK, "sysdb_attrs_copy failed"); -+ fail_unless(dst->num == 0, "Wrong number of elements"); -+ -+ ret = sysdb_attrs_add_string(src, TEST_ATTR_NAME, TEST_ATTR_VALUE); -+ fail_unless(ret == EOK, "sysdb_attrs_add_val failed."); -+ -+ ret = sysdb_attrs_copy(src, dst); -+ fail_unless(ret == EOK, "sysdb_attrs_copy failed"); -+ fail_unless(dst->num == 1, "Wrong number of elements"); -+ ret = sysdb_attrs_get_string(dst, TEST_ATTR_NAME, &val); -+ fail_unless(ret == EOK, "sysdb_attrs_get_string failed.\n"); -+ fail_unless(strcmp(val, TEST_ATTR_VALUE) == 0, "Wrong attribute value."); -+ -+ /* Make sure the same entry is not copied twice */ -+ ret = sysdb_attrs_copy(src, dst); -+ fail_unless(ret == EOK, "sysdb_attrs_copy failed"); -+ fail_unless(dst->num == 1, "Wrong number of elements"); -+ ret = sysdb_attrs_get_string(dst, TEST_ATTR_NAME, &val); -+ fail_unless(ret == EOK, "sysdb_attrs_get_string failed.\n"); -+ fail_unless(strcmp(val, TEST_ATTR_VALUE) == 0, "Wrong attribute value."); -+ -+ /* Add new value to existing attribute */ -+ ret = sysdb_attrs_add_string(src, TEST_ATTR_NAME, TEST_ATTR_VALUE"_2nd"); -+ fail_unless(ret == EOK, "sysdb_attrs_add_val failed."); -+ -+ ret = sysdb_attrs_copy(src, dst); -+ fail_unless(ret == EOK, "sysdb_attrs_copy failed"); -+ fail_unless(dst->num == 1, "Wrong number of elements"); -+ ret = sysdb_attrs_get_string_array(dst, TEST_ATTR_NAME, tmp_ctx, &array); -+ fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed.\n"); -+ fail_unless(strcmp(array[0], TEST_ATTR_VALUE) == 0, -+ "Wrong attribute value."); -+ fail_unless(strcmp(array[1], TEST_ATTR_VALUE"_2nd") == 0, -+ "Wrong attribute value."); -+ fail_unless(array[2] == NULL, "Wrong number of values."); -+ -+ /* Add new attribute */ -+ ret = sysdb_attrs_add_string(src, TEST_ATTR_NAME"_2nd", TEST_ATTR_VALUE); -+ fail_unless(ret == EOK, "sysdb_attrs_add_val failed."); -+ -+ ret = sysdb_attrs_copy(src, dst); -+ fail_unless(ret == EOK, "sysdb_attrs_copy failed"); -+ fail_unless(dst->num == 2, "Wrong number of elements"); -+ ret = sysdb_attrs_get_string_array(dst, TEST_ATTR_NAME, tmp_ctx, &array); -+ fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed.\n"); -+ fail_unless(strcmp(array[0], TEST_ATTR_VALUE) == 0, -+ "Wrong attribute value."); -+ fail_unless(strcmp(array[1], TEST_ATTR_VALUE"_2nd") == 0, -+ "Wrong attribute value."); -+ fail_unless(array[2] == NULL, "Wrong number of values."); -+ ret = sysdb_attrs_get_string(dst, TEST_ATTR_NAME"_2nd", &val); -+ fail_unless(ret == EOK, "sysdb_attrs_get_string failed.\n"); -+ fail_unless(strcmp(val, TEST_ATTR_VALUE) == 0, "Wrong attribute value."); -+ -+ talloc_free(tmp_ctx); -+} -+END_TEST -+ - START_TEST (test_sysdb_search_return_ENOENT) - { - struct sysdb_test_ctx *test_ctx; -@@ -6995,6 +7081,7 @@ Suite *create_sysdb_suite(void) - tcase_add_test(tc_sysdb, test_sysdb_attrs_add_val); - tcase_add_test(tc_sysdb, test_sysdb_attrs_add_val_safe); - tcase_add_test(tc_sysdb, test_sysdb_attrs_add_string_safe); -+ tcase_add_test(tc_sysdb, test_sysdb_attrs_copy); - - /* ===== Test search return empty result ===== */ - tcase_add_test(tc_sysdb, test_sysdb_search_return_ENOENT); --- -2.9.3 - diff --git a/SOURCES/0007-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch b/SOURCES/0007-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch new file mode 100644 index 0000000..12745ce --- /dev/null +++ b/SOURCES/0007-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch @@ -0,0 +1,222 @@ +From f048f210112a2ca6df52f10f9e47afac5996fc09 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Oct 2017 14:31:18 +0200 +Subject: [PATCH 07/21] LDAP: Turn group request into user request for MPG + domains if needed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the primary group GID or the group name is requested before the user +is, we need to also search the user space to save the user in the back +end which then allows the responder to generate the group from the +user entry. + +Related: + https://pagure.io/SSSD/sssd/issue/1872 + +Reviewed-by: Pavel Březina +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 057e8af379aa32f7d9ea48bfff22a3304c59444b) +--- + src/providers/ldap/ldap_id.c | 162 +++++++++++++++++++++++++++++++------------ + 1 file changed, 118 insertions(+), 44 deletions(-) + +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index 93204d35ea3782c9aa5d622a962c295869472631..e89fc6133316f684810afe4c1a0731b8a04f2931 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -694,6 +694,8 @@ struct groups_get_state { + static int groups_get_retry(struct tevent_req *req); + static void groups_get_connect_done(struct tevent_req *subreq); + static void groups_get_posix_check_done(struct tevent_req *subreq); ++static void groups_get_mpg_done(struct tevent_req *subreq); ++static errno_t groups_get_handle_no_group(struct tevent_req *req); + static void groups_get_search(struct tevent_req *req); + static void groups_get_done(struct tevent_req *subreq); + +@@ -1051,8 +1053,6 @@ static void groups_get_done(struct tevent_req *subreq) + struct tevent_req); + struct groups_get_state *state = tevent_req_data(req, + struct groups_get_state); +- char *endptr; +- gid_t gid; + int dp_error = DP_ERR_FATAL; + int ret; + +@@ -1078,49 +1078,33 @@ static void groups_get_done(struct tevent_req *subreq) + return; + } + +- if (ret == ENOENT && state->noexist_delete == true) { +- switch (state->filter_type) { +- case BE_FILTER_ENUM: +- tevent_req_error(req, ret); ++ if (ret == ENOENT ++ && state->domain->mpg == true) { ++ /* The requested filter did not find a group. Before giving up, we must ++ * also check if the GID can be resolved through a primary group of a ++ * user ++ */ ++ subreq = users_get_send(state, ++ state->ev, ++ state->ctx, ++ state->sdom, ++ state->conn, ++ state->filter_value, ++ state->filter_type, ++ NULL, ++ state->noexist_delete); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); + return; +- case BE_FILTER_NAME: +- ret = sysdb_delete_group(state->domain, state->filter_value, 0); +- if (ret != EOK && ret != ENOENT) { +- tevent_req_error(req, ret); +- return; +- } +- break; +- +- case BE_FILTER_IDNUM: +- gid = (gid_t) strtouint32(state->filter_value, &endptr, 10); +- if (errno || *endptr || (state->filter_value == endptr)) { +- tevent_req_error(req, errno ? errno : EINVAL); +- return; +- } +- +- ret = sysdb_delete_group(state->domain, NULL, gid); +- if (ret != EOK && ret != ENOENT) { +- tevent_req_error(req, ret); +- return; +- } +- break; +- +- case BE_FILTER_SECID: +- case BE_FILTER_UUID: +- /* Since it is not clear if the SID/UUID belongs to a user or a +- * group we have nothing to do here. */ +- break; +- +- case BE_FILTER_WILDCARD: +- /* We can't know if all groups are up-to-date, especially in +- * a large environment. Do not delete any records, let the +- * responder fetch the entries they are requested in. +- */ +- break; +- +- +- default: +- tevent_req_error(req, EINVAL); ++ } ++ tevent_req_set_callback(subreq, groups_get_mpg_done, req); ++ return; ++ } else if (ret == ENOENT && state->noexist_delete == true) { ++ ret = groups_get_handle_no_group(req); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not delete group [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); + return; + } + } +@@ -1129,6 +1113,96 @@ static void groups_get_done(struct tevent_req *subreq) + tevent_req_done(req); + } + ++static void groups_get_mpg_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct groups_get_state *state = tevent_req_data(req, ++ struct groups_get_state); ++ ++ ret = users_get_recv(subreq, &state->dp_error, &state->sdap_ret); ++ talloc_zfree(subreq); ++ ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (state->sdap_ret == ENOENT && state->noexist_delete == true) { ++ ret = groups_get_handle_no_group(req); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not delete group [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ } ++ ++ /* GID resolved to a user private group, done */ ++ tevent_req_done(req); ++ return; ++} ++ ++static errno_t groups_get_handle_no_group(struct tevent_req *req) ++{ ++ struct groups_get_state *state = tevent_req_data(req, ++ struct groups_get_state); ++ errno_t ret; ++ char *endptr; ++ gid_t gid; ++ ++ switch (state->filter_type) { ++ case BE_FILTER_ENUM: ++ ret = ENOENT; ++ break; ++ case BE_FILTER_NAME: ++ ret = sysdb_delete_group(state->domain, state->filter_value, 0); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot delete group %s [%d]: %s\n", ++ state->filter_value, ret, sss_strerror(ret)); ++ return ret; ++ } ++ ret = EOK; ++ break; ++ case BE_FILTER_IDNUM: ++ gid = (gid_t) strtouint32(state->filter_value, &endptr, 10); ++ if (errno || *endptr || (state->filter_value == endptr)) { ++ ret = errno ? errno : EINVAL; ++ break; ++ } ++ ++ ret = sysdb_delete_group(state->domain, NULL, gid); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot delete group %"SPRIgid" [%d]: %s\n", ++ gid, ret, sss_strerror(ret)); ++ return ret; ++ } ++ ret = EOK; ++ break; ++ case BE_FILTER_SECID: ++ case BE_FILTER_UUID: ++ /* Since it is not clear if the SID/UUID belongs to a user or a ++ * group we have nothing to do here. */ ++ ret = EOK; ++ break; ++ case BE_FILTER_WILDCARD: ++ /* We can't know if all groups are up-to-date, especially in ++ * a large environment. Do not delete any records, let the ++ * responder fetch the entries they are requested in. ++ */ ++ ret = EOK; ++ break; ++ default: ++ ret = EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ + int groups_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret) + { + struct groups_get_state *state = tevent_req_data(req, +-- +2.13.5 + diff --git a/SOURCES/0007-sdap_get_users_send-new-argument-mapped_attrs.patch b/SOURCES/0007-sdap_get_users_send-new-argument-mapped_attrs.patch deleted file mode 100644 index 9292f78..0000000 --- a/SOURCES/0007-sdap_get_users_send-new-argument-mapped_attrs.patch +++ /dev/null @@ -1,316 +0,0 @@ -From af96fbe97576133ca6077c47f39b812e7e289040 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Sun, 12 Mar 2017 18:31:03 +0100 -Subject: [PATCH 07/15] sdap_get_users_send(): new argument mapped_attrs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -mapped_attrs can be a list of sysdb_attrs which are not available on -the server side but should be store with the cached user entry. This is -needed e.g. when the input to look up the user in LDAP is not an -attribute which is stored in LDAP but some data where LDAP attributes -are extracted from. The current use case is the certificate mapping -library which can create LDAP search filters based on content of the -certificate. To allow upcoming cache lookup to use the input directly it -is stored in the user object in the cache. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - src/db/sysdb.h | 3 ++ - src/db/sysdb_ops.c | 61 ++++++++++++++++++++++++++++++ - src/providers/ldap/ldap_id.c | 4 +- - src/providers/ldap/sdap_async.h | 3 +- - src/providers/ldap/sdap_async_enum.c | 2 +- - src/providers/ldap/sdap_async_initgroups.c | 2 +- - src/providers/ldap/sdap_async_private.h | 1 + - src/providers/ldap/sdap_async_users.c | 41 +++++++++++++++++++- - src/providers/ldap/sdap_users.h | 1 + - 9 files changed, 111 insertions(+), 7 deletions(-) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index c677957bb639e40db2f985205160612094302e78..098f47f91187aac75c58c02f0af738c344765762 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -1246,6 +1246,9 @@ errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx, - errno_t sysdb_remove_cert(struct sss_domain_info *domain, - const char *cert); - -+errno_t sysdb_remove_mapped_data(struct sss_domain_info *domain, -+ struct sysdb_attrs *mapped_attr); -+ - /* === Functions related to GPOs === */ - - #define SYSDB_GPO_CONTAINER "cn=gpos,cn=ad,cn=custom" -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 242d3ce3bb795691e329790a07c3493672e8f523..6c2254df2b75d3d3419528523103ad9cddb40c9d 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -4685,6 +4685,67 @@ errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx, - return sysdb_search_object_by_cert(mem_ctx, domain, cert, user_attrs, res); - } - -+errno_t sysdb_remove_mapped_data(struct sss_domain_info *domain, -+ struct sysdb_attrs *mapped_attr) -+{ -+ int ret; -+ char *val; -+ char *filter; -+ const char *attrs[] = {SYSDB_NAME, NULL}; -+ struct ldb_result *res = NULL; -+ size_t c; -+ bool all_ok = true; -+ -+ if (mapped_attr->num != 1 || mapped_attr->a[0].num_values != 1) { -+ DEBUG(SSSDBG_OP_FAILURE, "Unsupported number of attributes.\n"); -+ return EINVAL; -+ } -+ -+ ret = bin_to_ldap_filter_value(NULL, mapped_attr->a[0].values[0].data, -+ mapped_attr->a[0].values[0].length, &val); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "bin_to_ldap_filter_value failed.\n"); -+ return ret; -+ } -+ -+ filter = talloc_asprintf(NULL, "(&("SYSDB_UC")(%s=%s))", -+ mapped_attr->a[0].name, val); -+ talloc_free(val); -+ if (filter == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -+ return ENOMEM; -+ } -+ -+ ret = sysdb_search_object_attr(NULL, domain, filter, attrs, false, &res); -+ talloc_free(filter); -+ if (ret == ENOENT || res == NULL) { -+ DEBUG(SSSDBG_TRACE_ALL, "Mapped data not found.\n"); -+ talloc_free(res); -+ return EOK; -+ } else if (ret != EOK) { -+ talloc_free(res); -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_object_attr failed.\n"); -+ return ret; -+ } -+ -+ for (c = 0; c < res->count; c++) { -+ DEBUG(SSSDBG_TRACE_ALL, "Removing mapped data from [%s].\n", -+ ldb_dn_get_linearized(res->msgs[c]->dn)); -+ /* The timestamp cache is skipped on purpose here. */ -+ ret = sysdb_set_cache_entry_attr(domain->sysdb->ldb, res->msgs[c]->dn, -+ mapped_attr, SYSDB_MOD_DEL); -+ if (ret != EOK) { -+ all_ok = false; -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to remove mapped data from [%s], skipping.\n", -+ ldb_dn_get_linearized(res->msgs[c]->dn)); -+ } -+ } -+ talloc_free(res); -+ -+ return (all_ok ? EOK : EIO); -+} -+ - errno_t sysdb_remove_cert(struct sss_domain_info *domain, - const char *cert) - { -diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c -index e9455b538daa2d65d944dbb68022a2773623d7b7..898ddb18689d55fcc3fdf021b38df0e574003eb2 100644 ---- a/src/providers/ldap/ldap_id.c -+++ b/src/providers/ldap/ldap_id.c -@@ -442,7 +442,7 @@ static void users_get_search(struct tevent_req *req) - state->attrs, state->filter, - dp_opt_get_int(state->ctx->opts->basic, - SDAP_SEARCH_TIMEOUT), -- lookup_type); -+ lookup_type, NULL); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; -@@ -507,7 +507,7 @@ static void users_get_done(struct tevent_req *subreq) - ret = sdap_fallback_local_user(state, state->shortname, uid, &usr_attrs); - if (ret == EOK) { - ret = sdap_save_user(state, state->ctx->opts, state->domain, -- usr_attrs[0], NULL, 0); -+ usr_attrs[0], NULL, NULL, 0); - } - } - } -diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h -index 2ebde6b83646408e446c91cb324809cb767b2617..6e5800b42ba4a045fa7985b09a80b6b86b8c6055 100644 ---- a/src/providers/ldap/sdap_async.h -+++ b/src/providers/ldap/sdap_async.h -@@ -90,7 +90,8 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, - const char **attrs, - const char *filter, - int timeout, -- enum sdap_entry_lookup_type lookup_type); -+ enum sdap_entry_lookup_type lookup_type, -+ struct sysdb_attrs *mapped_attrs); - int sdap_get_users_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, char **timestamp); - -diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c -index 387e53155b567ce106cc68009c7cb99e27d24a17..3f65059e18d5c8b548da0babec867d27c3a64198 100644 ---- a/src/providers/ldap/sdap_async_enum.c -+++ b/src/providers/ldap/sdap_async_enum.c -@@ -635,7 +635,7 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx, - state->attrs, state->filter, - dp_opt_get_int(state->ctx->opts->basic, - SDAP_ENUM_SEARCH_TIMEOUT), -- SDAP_LOOKUP_ENUMERATE); -+ SDAP_LOOKUP_ENUMERATE, NULL); - if (!subreq) { - ret = ENOMEM; - goto fail; -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index 8c7a65bf36abf341e077cf9eac18a234d3a07c07..79af7a3eda3fe8533933535c98c2b4b4698dfda2 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -2991,7 +2991,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) - DEBUG(SSSDBG_TRACE_ALL, "Storing the user\n"); - - ret = sdap_save_user(state, state->opts, state->dom, state->orig_user, -- NULL, 0); -+ NULL, NULL, 0); - if (ret) { - goto fail; - } -diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h -index 266bc03115e2bdd6a283f5f7da565fd00d3a77be..72507442a9ffd5c0e24ccbd95d75d3ebf9bf0940 100644 ---- a/src/providers/ldap/sdap_async_private.h -+++ b/src/providers/ldap/sdap_async_private.h -@@ -94,6 +94,7 @@ int sdap_save_users(TALLOC_CTX *memctx, - struct sdap_options *opts, - struct sysdb_attrs **users, - int num_users, -+ struct sysdb_attrs *mapped_attrs, - char **_usn_value); - - int sdap_initgr_common_store(struct sysdb_ctx *sysdb, -diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c -index 87d91d8247c37a4c6a1d83b7189399056528fc90..3d957ab584865f74499bc732395388a78965fe5f 100644 ---- a/src/providers/ldap/sdap_async_users.c -+++ b/src/providers/ldap/sdap_async_users.c -@@ -117,6 +117,7 @@ int sdap_save_user(TALLOC_CTX *memctx, - struct sdap_options *opts, - struct sss_domain_info *dom, - struct sysdb_attrs *attrs, -+ struct sysdb_attrs *mapped_attrs, - char **_usn_value, - time_t now) - { -@@ -511,6 +512,11 @@ int sdap_save_user(TALLOC_CTX *memctx, - user_attrs, missing, cache_timeout, now); - if (ret) goto done; - -+ if (mapped_attrs != NULL) { -+ ret = sysdb_set_user_attr(dom, user_name, mapped_attrs, SYSDB_MOD_ADD); -+ if (ret) return ret; -+ } -+ - if (_usn_value) { - *_usn_value = talloc_steal(memctx, usn_value); - } -@@ -537,6 +543,7 @@ int sdap_save_users(TALLOC_CTX *memctx, - struct sdap_options *opts, - struct sysdb_attrs **users, - int num_users, -+ struct sysdb_attrs *mapped_attrs, - char **_usn_value) - { - TALLOC_CTX *tmpctx; -@@ -565,11 +572,20 @@ int sdap_save_users(TALLOC_CTX *memctx, - } - in_transaction = true; - -+ if (mapped_attrs != NULL) { -+ ret = sysdb_remove_mapped_data(dom, mapped_attrs); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_remove_mapped_data failed, " -+ "some cached entries might contain invalid mapping data.\n"); -+ } -+ } -+ - now = time(NULL); - for (i = 0; i < num_users; i++) { - usn_value = NULL; - -- ret = sdap_save_user(tmpctx, opts, dom, users[i], &usn_value, now); -+ ret = sdap_save_user(tmpctx, opts, dom, users[i], mapped_attrs, -+ &usn_value, now); - - /* Do not fail completely on errors. - * Just report the failure to save and go on */ -@@ -868,6 +884,7 @@ struct sdap_get_users_state { - - char *higher_usn; - struct sysdb_attrs **users; -+ struct sysdb_attrs *mapped_attrs; - size_t count; - }; - -@@ -883,7 +900,8 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, - const char **attrs, - const char *filter, - int timeout, -- enum sdap_entry_lookup_type lookup_type) -+ enum sdap_entry_lookup_type lookup_type, -+ struct sysdb_attrs *mapped_attrs) - { - errno_t ret; - struct tevent_req *req; -@@ -900,6 +918,23 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, - state->filter = filter; - PROBE(SDAP_SEARCH_USER_SEND, state->filter); - -+ if (mapped_attrs == NULL) { -+ state->mapped_attrs = NULL; -+ } else { -+ state->mapped_attrs = sysdb_new_attrs(state); -+ if (state->mapped_attrs == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sysdb_attrs_copy(mapped_attrs, state->mapped_attrs); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_copy failed.\n"); -+ goto done; -+ } -+ } -+ - subreq = sdap_search_user_send(state, ev, dom, opts, search_bases, - sh, attrs, filter, timeout, lookup_type); - if (subreq == NULL) { -@@ -938,9 +973,11 @@ static void sdap_get_users_done(struct tevent_req *subreq) - } - - PROBE(SDAP_SEARCH_USER_SAVE_BEGIN, state->filter); -+ - ret = sdap_save_users(state, state->sysdb, - state->dom, state->opts, - state->users, state->count, -+ state->mapped_attrs, - &state->higher_usn); - PROBE(SDAP_SEARCH_USER_SAVE_END, state->filter); - if (ret) { -diff --git a/src/providers/ldap/sdap_users.h b/src/providers/ldap/sdap_users.h -index 78dafb31a2a07e7289055daec77c5dc5da1bdeef..a6d088a6d7114db75b0f0ea22ef85c57da6fab0f 100644 ---- a/src/providers/ldap/sdap_users.h -+++ b/src/providers/ldap/sdap_users.h -@@ -34,6 +34,7 @@ int sdap_save_user(TALLOC_CTX *memctx, - struct sdap_options *opts, - struct sss_domain_info *dom, - struct sysdb_attrs *attrs, -+ struct sysdb_attrs *mapped_attrs, - char **_usn_value, - time_t now); - --- -2.9.3 - diff --git a/SOURCES/0008-LDAP-always-store-the-certificate-from-the-request.patch b/SOURCES/0008-LDAP-always-store-the-certificate-from-the-request.patch deleted file mode 100644 index 108254d..0000000 --- a/SOURCES/0008-LDAP-always-store-the-certificate-from-the-request.patch +++ /dev/null @@ -1,178 +0,0 @@ -From a3cc501e36f5cf1e4a8187d723b53111f5481b36 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 30 Nov 2015 12:14:55 +0100 -Subject: [PATCH 08/15] LDAP: always store the certificate from the request -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Store the certificate used to lookup a user as mapped attribute in the -cached user object. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - src/db/sysdb.h | 1 + - src/db/sysdb_ops.c | 4 ++-- - src/providers/ldap/ldap_id.c | 19 ++++++++++++++++++- - src/tests/cmocka/test_nss_srv.c | 2 +- - src/tests/cmocka/test_pam_srv.c | 6 +++--- - src/tests/sysdb-tests.c | 4 ++-- - 6 files changed, 27 insertions(+), 9 deletions(-) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 098f47f91187aac75c58c02f0af738c344765762..3db22b3689bf6ffd9a48e29c229916e3fac9ca1b 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -139,6 +139,7 @@ - - #define SYSDB_AUTH_TYPE "authType" - #define SYSDB_USER_CERT "userCertificate" -+#define SYSDB_USER_MAPPED_CERT "userMappedCertificate" - #define SYSDB_USER_EMAIL "mail" - - #define SYSDB_SUBDOMAIN_REALM "realmName" -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 6c2254df2b75d3d3419528523103ad9cddb40c9d..8ae25764478e522255b177f9e8de1d3ca1ad43fd 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -4660,7 +4660,7 @@ errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx, - int ret; - char *user_filter; - -- ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_CERT, -+ ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_MAPPED_CERT, - &user_filter); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n"); -@@ -4749,7 +4749,7 @@ errno_t sysdb_remove_mapped_data(struct sss_domain_info *domain, - errno_t sysdb_remove_cert(struct sss_domain_info *domain, - const char *cert) - { -- struct ldb_message_element el = { 0, SYSDB_USER_CERT, 0, NULL }; -+ struct ldb_message_element el = { 0, SYSDB_USER_MAPPED_CERT, 0, NULL }; - struct sysdb_attrs del_attrs = { 1, &el }; - const char *attrs[] = {SYSDB_NAME, NULL}; - struct ldb_result *res = NULL; -diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c -index 898ddb18689d55fcc3fdf021b38df0e574003eb2..a8b4bc2cfc6e9d4e0d74b0e3e036afbcbf7eb26e 100644 ---- a/src/providers/ldap/ldap_id.c -+++ b/src/providers/ldap/ldap_id.c -@@ -60,6 +60,7 @@ struct users_get_state { - int dp_error; - int sdap_ret; - bool noexist_delete; -+ struct sysdb_attrs *extra_attrs; - }; - - static int users_get_retry(struct tevent_req *req); -@@ -99,6 +100,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - state->conn = conn; - state->dp_error = DP_ERR_FATAL; - state->noexist_delete = noexist_delete; -+ state->extra_attrs = NULL; - - state->op = sdap_id_op_create(state, state->conn->conn_cache); - if (!state->op) { -@@ -251,6 +253,21 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - "sss_cert_derb64_to_ldap_filter failed.\n"); - goto done; - } -+ -+ state->extra_attrs = sysdb_new_attrs(state); -+ if (state->extra_attrs == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sysdb_attrs_add_base64_blob(state->extra_attrs, -+ SYSDB_USER_MAPPED_CERT, filter_value); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_base64_blob failed.\n"); -+ goto done; -+ } -+ - break; - default: - ret = EINVAL; -@@ -442,7 +459,7 @@ static void users_get_search(struct tevent_req *req) - state->attrs, state->filter, - dp_opt_get_int(state->ctx->opts->basic, - SDAP_SEARCH_TIMEOUT), -- lookup_type, NULL); -+ lookup_type, state->extra_attrs); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 72bbaf9bf35ebb3fc4208afaa3c7af95922afcb0..76b9c6fb05673130de0957e93291919c263a28f3 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -3508,7 +3508,7 @@ static void test_nss_getnamebycert(void **state) - der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size); - assert_non_null(der); - -- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); -+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); - talloc_free(der); - assert_int_equal(ret, EOK); - -diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c -index ae2e555f7024027d1c0063031f8882bf81a31905..847419658bb983e6548722d6fa6fb22c63ee86b8 100644 ---- a/src/tests/cmocka/test_pam_srv.c -+++ b/src/tests/cmocka/test_pam_srv.c -@@ -1598,7 +1598,7 @@ static int test_lookup_by_cert_cb(void *pvt) - der = sss_base64_decode(pam_test_ctx, pvt, &der_size); - assert_non_null(der); - -- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); -+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); - talloc_free(der); - assert_int_equal(ret, EOK); - -@@ -1630,7 +1630,7 @@ static int test_lookup_by_cert_double_cb(void *pvt) - der = sss_base64_decode(pam_test_ctx, pvt, &der_size); - assert_non_null(der); - -- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); -+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); - talloc_free(der); - assert_int_equal(ret, EOK); - -@@ -1658,7 +1658,7 @@ static int test_lookup_by_cert_wrong_user_cb(void *pvt) - der = sss_base64_decode(pam_test_ctx, pvt, &der_size); - assert_non_null(der); - -- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); -+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); - talloc_free(der); - assert_int_equal(ret, EOK); - -diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c -index c343c734a27a335303974b6866a5d9e88d4c307e..5bdd631fbfa1b4463fb169e5f07b65fb2c784096 100644 ---- a/src/tests/sysdb-tests.c -+++ b/src/tests/sysdb-tests.c -@@ -5721,7 +5721,7 @@ START_TEST(test_sysdb_search_user_by_cert) - val.data = sss_base64_decode(test_ctx, TEST_USER_CERT_DERB64, &val.length); - fail_unless(val.data != NULL, "sss_base64_decode failed."); - -- ret = sysdb_attrs_add_val(data->attrs, SYSDB_USER_CERT, &val); -+ ret = sysdb_attrs_add_val(data->attrs, SYSDB_USER_MAPPED_CERT, &val); - fail_unless(ret == EOK, "sysdb_attrs_add_val failed with [%d][%s].", - ret, strerror(ret)); - -@@ -5750,7 +5750,7 @@ START_TEST(test_sysdb_search_user_by_cert) - data2 = test_data_new_user(test_ctx, 2345671); - fail_if(data2 == NULL); - -- ret = sysdb_attrs_add_val(data2->attrs, SYSDB_USER_CERT, &val); -+ ret = sysdb_attrs_add_val(data2->attrs, SYSDB_USER_MAPPED_CERT, &val); - fail_unless(ret == EOK, "sysdb_attrs_add_val failed with [%d][%s].", - ret, strerror(ret)); - --- -2.9.3 - diff --git a/SOURCES/0008-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch b/SOURCES/0008-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch new file mode 100644 index 0000000..b8d60e1 --- /dev/null +++ b/SOURCES/0008-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch @@ -0,0 +1,97 @@ +From d75b796151973a5d94a79f5577c15cda6eecb5ee Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Thu, 19 Oct 2017 17:18:15 +0200 +Subject: [PATCH 08/21] SYSDB: Prevent users and groups ID collision in MPG + domains except for id_provider=local +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit makes the check when adding an object in a MPG domain +stricter in the sense that not only same names are allowed in a MPG +domain, but also the same groups are not allowed either. + +This commit is a backwards-incompatible change, but one that is needed, +otherwise requesting the duplicate group first and then requesting the +user entry would yield two object when searching by GID. + +In order to keep backwards-compatibility, this uniqueness is NOT +enforced with id_provider=local. This constraint can be removed in +the future (or the local provider can be dropped altogether) + +Reviewed-by: Pavel Březina +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit ac962e2b286988d8666b3b81bf8b55b1705b9ac0) +--- + src/db/sysdb_ops.c | 41 ++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 38 insertions(+), 3 deletions(-) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 0e39a629a5823ff49ed02ec4c08a21b66119f06f..2f8e36c6c9a2c2cefe4af5fb78957763304d989a 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -1960,16 +1960,34 @@ int sysdb_add_user(struct sss_domain_info *domain, + } + + if (domain->mpg) { +- /* In MPG domains you can't have groups with the same name as users, +- * search if a group with the same name exists. ++ /* In MPG domains you can't have groups with the same name or GID ++ * as users, search if a group with the same name exists. + * Don't worry about users, if we try to add a user with the same + * name the operation will fail */ + + ret = sysdb_search_group_by_name(tmp_ctx, domain, name, NULL, &msg); + if (ret != ENOENT) { +- if (ret == EOK) ret = EEXIST; ++ if (ret == EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Group named %s already exists in an MPG domain\n", ++ name); ++ ret = EEXIST; ++ } + goto done; + } ++ ++ if (strcasecmp(domain->provider, "local") != 0) { ++ ret = sysdb_search_group_by_gid(tmp_ctx, domain, uid, NULL, &msg); ++ if (ret != ENOENT) { ++ if (ret == EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Group with GID [%"SPRIgid"] already exists in an " ++ "MPG domain\n", gid); ++ ret = EEXIST; ++ } ++ goto done; ++ } ++ } + } + + /* check no other user with the same uid exist */ +@@ -2177,6 +2195,23 @@ int sysdb_add_group(struct sss_domain_info *domain, + } + goto done; + } ++ ++ if (strcasecmp(domain->provider, "local") != 0) { ++ ret = sysdb_search_user_by_uid(tmp_ctx, domain, gid, NULL, &msg); ++ if (ret != ENOENT) { ++ if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "User with the same UID exists in MPG domain: " ++ "[%"SPRIgid"].\n", gid); ++ ret = EEXIST; ++ } else { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "sysdb_search_user_by_uid failed for gid: " ++ "[%"SPRIgid"].\n", gid); ++ } ++ goto done; ++ } ++ } + } + + /* check no other groups with the same gid exist */ +-- +2.13.5 + diff --git a/SOURCES/0009-TESTS-Add-integration-tests-for-the-auto_private_gro.patch b/SOURCES/0009-TESTS-Add-integration-tests-for-the-auto_private_gro.patch new file mode 100644 index 0000000..a9c1356 --- /dev/null +++ b/SOURCES/0009-TESTS-Add-integration-tests-for-the-auto_private_gro.patch @@ -0,0 +1,346 @@ +From 95053cd058a9045c45c59e002fd6078048fdca76 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Oct 2017 16:55:40 +0200 +Subject: [PATCH 09/21] TESTS: Add integration tests for the + auto_private_groups option +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: + https://pagure.io/SSSD/sssd/issue/1872 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +(cherry picked from commit 6c802b2009c1b6dd0c3306ba97056e64acc0ec9e) +--- + src/tests/intg/test_enumeration.py | 79 +++++++++++++- + src/tests/intg/test_ldap.py | 214 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 290 insertions(+), 3 deletions(-) + +diff --git a/src/tests/intg/test_enumeration.py b/src/tests/intg/test_enumeration.py +index fdb8d376879f756957f8f25fd28b37d7178aeff5..c7d78155c64dc6c85cb4dc070b205bdcfceff6af 100644 +--- a/src/tests/intg/test_enumeration.py ++++ b/src/tests/intg/test_enumeration.py +@@ -237,9 +237,7 @@ def sanity_rfc2307(request, ldap_conn): + create_sssd_fixture(request) + return None + +- +-@pytest.fixture +-def sanity_rfc2307_bis(request, ldap_conn): ++def populate_rfc2307bis(request, ldap_conn): + ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) + ent_list.add_user("user1", 1001, 2001) + ent_list.add_user("user2", 1002, 2002) +@@ -266,6 +264,11 @@ def sanity_rfc2307_bis(request, ldap_conn): + [], ["one_user_group1", "one_user_group2"]) + + create_ldap_fixture(request, ldap_conn, ent_list) ++ ++ ++@pytest.fixture ++def sanity_rfc2307_bis(request, ldap_conn): ++ populate_rfc2307bis(request, ldap_conn) + conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + create_conf_fixture(request, conf) + create_sssd_fixture(request) +@@ -695,3 +698,73 @@ def test_vetoed_shells(vetoed_shells): + shell="/bin/default") + ) + ) ++ ++ ++@pytest.fixture ++def sanity_rfc2307_bis_mpg(request, ldap_conn): ++ populate_rfc2307bis(request, ldap_conn) ++ ++ ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) ++ ent_list.add_group_bis("conflict1", 1001) ++ ent_list.add_group_bis("conflict2", 1002) ++ create_ldap_fixture(request, ldap_conn, ent_list) ++ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \ ++ unindent(""" ++ [domain/LDAP] ++ auto_private_groups = True ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ ++def test_ldap_auto_private_groups_enumerate(ldap_conn, ++ sanity_rfc2307_bis_mpg): ++ """ ++ Test the auto_private_groups together with enumeration ++ """ ++ passwd_pattern = ent.contains_only( ++ dict(name='user1', passwd='*', uid=1001, gid=1001, gecos='1001', ++ dir='/home/user1', shell='/bin/bash'), ++ dict(name='user2', passwd='*', uid=1002, gid=1002, gecos='1002', ++ dir='/home/user2', shell='/bin/bash'), ++ dict(name='user3', passwd='*', uid=1003, gid=1003, gecos='1003', ++ dir='/home/user3', shell='/bin/bash') ++ ) ++ ent.assert_passwd(passwd_pattern) ++ ++ group_pattern = ent.contains_only( ++ dict(name='user1', passwd='*', gid=1001, mem=ent.contains_only()), ++ dict(name='user2', passwd='*', gid=1002, mem=ent.contains_only()), ++ dict(name='user3', passwd='*', gid=1003, mem=ent.contains_only()), ++ dict(name='group1', passwd='*', gid=2001, mem=ent.contains_only()), ++ dict(name='group2', passwd='*', gid=2002, mem=ent.contains_only()), ++ dict(name='group3', passwd='*', gid=2003, mem=ent.contains_only()), ++ dict(name='empty_group1', passwd='*', gid=2010, ++ mem=ent.contains_only()), ++ dict(name='empty_group2', passwd='*', gid=2011, ++ mem=ent.contains_only()), ++ dict(name='two_user_group', passwd='*', gid=2012, ++ mem=ent.contains_only("user1", "user2")), ++ dict(name='group_empty_group', passwd='*', gid=2013, ++ mem=ent.contains_only()), ++ dict(name='group_two_empty_groups', passwd='*', gid=2014, ++ mem=ent.contains_only()), ++ dict(name='one_user_group1', passwd='*', gid=2015, ++ mem=ent.contains_only("user1")), ++ dict(name='one_user_group2', passwd='*', gid=2016, ++ mem=ent.contains_only("user2")), ++ dict(name='group_one_user_group', passwd='*', gid=2017, ++ mem=ent.contains_only("user1")), ++ dict(name='group_two_user_group', passwd='*', gid=2018, ++ mem=ent.contains_only("user1", "user2")), ++ dict(name='group_two_one_user_groups', passwd='*', gid=2019, ++ mem=ent.contains_only("user1", "user2")) ++ ) ++ ent.assert_group(group_pattern) ++ ++ with pytest.raises(KeyError): ++ grp.getgrnam("conflict1") ++ ent.assert_group_by_gid(1002, dict(name="user2", mem=ent.contains_only())) +diff --git a/src/tests/intg/test_ldap.py b/src/tests/intg/test_ldap.py +index f2467f1ffe9890049ad73bba6432102d029510e8..a6659b1b78df4d72eb98c208d67ee5d10c9c88ea 100644 +--- a/src/tests/intg/test_ldap.py ++++ b/src/tests/intg/test_ldap.py +@@ -1169,3 +1169,217 @@ def test_nss_filters_cached(ldap_conn, sanity_nss_filter_cached): + + res, _ = call_sssd_getgrgid(0) + assert res == NssReturnCode.NOTFOUND ++ ++ ++@pytest.fixture ++def mpg_setup(request, ldap_conn): ++ ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) ++ ent_list.add_user("user1", 1001, 2001) ++ ent_list.add_user("user2", 1002, 2002) ++ ent_list.add_user("user3", 1003, 2003) ++ ++ ent_list.add_group_bis("group1", 2001) ++ ent_list.add_group_bis("group2", 2002) ++ ent_list.add_group_bis("group3", 2003) ++ ++ ent_list.add_group_bis("two_user_group", 2012, ["user1", "user2"]) ++ ent_list.add_group_bis("one_user_group1", 2015, ["user1"]) ++ ent_list.add_group_bis("one_user_group2", 2016, ["user2"]) ++ ++ create_ldap_entries(ldap_conn, ent_list) ++ create_ldap_cleanup(request, ldap_conn, None) ++ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \ ++ unindent(""" ++ [domain/LDAP] ++ auto_private_groups = True ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ ++def test_ldap_auto_private_groups_direct(ldap_conn, mpg_setup): ++ """ ++ Integration test for auto_private_groups ++ ++ See also ticket https://pagure.io/SSSD/sssd/issue/1872 ++ """ ++ # Make sure the user's GID is taken from their uidNumber ++ ent.assert_passwd_by_name("user1", dict(name="user1", uid=1001, gid=1001)) ++ # Make sure the private group is resolvable by name and by GID ++ ent.assert_group_by_name("user1", dict(gid=1001, mem=ent.contains_only())) ++ ent.assert_group_by_gid(1001, dict(name="user1", mem=ent.contains_only())) ++ ++ # The group referenced in user's gidNumber attribute should be still ++ # visible, but it's fine that it doesn't contain the user as a member ++ # as the group is currently added during the initgroups operation only ++ ent.assert_group_by_name("group1", dict(gid=2001, mem=ent.contains_only())) ++ ent.assert_group_by_gid(2001, dict(name="group1", mem=ent.contains_only())) ++ ++ # The user's secondary groups list must be correct as well ++ # Note that the original GID is listed as well -- this is correct and expected ++ # because we save the original GID in the SYSDB_PRIMARY_GROUP_GIDNUM attribute ++ user1_expected_gids = [1001, 2001, 2012, 2015] ++ (res, errno, gids) = sssd_id.call_sssd_initgroups("user1", 1001) ++ assert res == sssd_id.NssReturnCode.SUCCESS ++ ++ assert sorted(gids) == sorted(user1_expected_gids), \ ++ "result: %s\n expected %s" % ( ++ ", ".join(["%s" % s for s in sorted(gids)]), ++ ", ".join(["%s" % s for s in sorted(user1_expected_gids)]) ++ ) ++ ++ # Request user2's private group by GID without resolving the user first. ++ # This must trigger user resolution through by-GID resolution, since the GID ++ # doesn't exist on its own in LDAP ++ ent.assert_group_by_gid(1002, dict(name="user2", mem=ent.contains_only())) ++ ++ # Test supplementary groups for user2 as well ++ user1_expected_gids = [1002, 2002, 2012, 2016] ++ (res, errno, gids) = sssd_id.call_sssd_initgroups("user2", 1002) ++ assert res == sssd_id.NssReturnCode.SUCCESS ++ ++ assert sorted(gids) == sorted(user1_expected_gids), \ ++ "result: %s\n expected %s" % ( ++ ", ".join(["%s" % s for s in sorted(gids)]), ++ ", ".join(["%s" % s for s in sorted(user1_expected_gids)]) ++ ) ++ ++ # Request user3's private group by name without resolving the user first ++ # This must trigger user resolution through by-name resolution, since the ++ # name doesn't exist on its own in LDAP ++ ent.assert_group_by_name("user3", dict(gid=1003, mem=ent.contains_only())) ++ ++ # Remove entries and request them again to make sure they are not ++ # resolvable anymore ++ cleanup_ldap_entries(ldap_conn, None) ++ ++ if subprocess.call(["sss_cache", "-GU"]) != 0: ++ raise Exception("sssd_cache failed") ++ ++ with pytest.raises(KeyError): ++ pwd.getpwnam("user1") ++ with pytest.raises(KeyError): ++ grp.getgrnam("user1") ++ with pytest.raises(KeyError): ++ grp.getgrgid(1002) ++ with pytest.raises(KeyError): ++ grp.getgrnam("user3") ++ ++ ++@pytest.fixture ++def mpg_setup_conflict(request, ldap_conn): ++ ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) ++ ent_list.add_user("user1", 1001, 2001) ++ ent_list.add_user("user2", 1002, 2002) ++ ent_list.add_user("user3", 1003, 1003) ++ ent_list.add_group_bis("group1", 1001) ++ ent_list.add_group_bis("group2", 1002) ++ ent_list.add_group_bis("group3", 1003) ++ ent_list.add_group_bis("supp_group", 2015, ["user3"]) ++ create_ldap_fixture(request, ldap_conn, ent_list) ++ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \ ++ unindent(""" ++ [domain/LDAP] ++ auto_private_groups = True ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ ++def test_ldap_auto_private_groups_conflict(ldap_conn, mpg_setup_conflict): ++ """ ++ Make sure that conflicts between groups that are auto-created with the ++ help of the auto_private_groups option and between 'real' LDAP groups ++ are handled in a predictable manner. ++ """ ++ # Make sure the user's GID is taken from their uidNumber ++ ent.assert_passwd_by_name("user1", dict(name="user1", uid=1001, gid=1001)) ++ # Make sure the private group is resolvable by name and by GID ++ ent.assert_group_by_name("user1", dict(gid=1001, mem=ent.contains_only())) ++ ent.assert_group_by_gid(1001, dict(name="user1", mem=ent.contains_only())) ++ ++ # Let's request the group with the same ID as user2's private group ++ # The request should match the 'real' group ++ ent.assert_group_by_gid(1002, dict(name="group2", mem=ent.contains_only())) ++ # But because of the GID conflict, the user cannot be resolved ++ with pytest.raises(KeyError): ++ pwd.getpwnam("user2") ++ ++ # This user's GID is the same as the UID in this entry. The most important ++ # thing here is that the supplementary groups are correct and the GID ++ # resolves to the private group (as long as the user was requested first) ++ user3_expected_gids = [1003, 2015] ++ ent.assert_passwd_by_name("user3", dict(name="user3", uid=1003, gid=1003)) ++ (res, errno, gids) = sssd_id.call_sssd_initgroups("user3", 1003) ++ assert res == sssd_id.NssReturnCode.SUCCESS ++ ++ assert sorted(gids) == sorted(user3_expected_gids), \ ++ "result: %s\n expected %s" % ( ++ ", ".join(["%s" % s for s in sorted(gids)]), ++ ", ".join(["%s" % s for s in sorted(user3_expected_gids)]) ++ ) ++ # Make sure the private group is resolvable by name and by GID ++ ent.assert_group_by_gid(1003, dict(name="user3", mem=ent.contains_only())) ++ ent.assert_group_by_name("user3", dict(gid=1003, mem=ent.contains_only())) ++ ++ ++@pytest.fixture ++def mpg_setup_no_gid(request, ldap_conn): ++ ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) ++ ent_list.add_user("user1", 1001, 2001) ++ ++ ent_list.add_group_bis("group1", 2001) ++ ent_list.add_group_bis("one_user_group1", 2015, ["user1"]) ++ ++ create_ldap_entries(ldap_conn, ent_list) ++ create_ldap_cleanup(request, ldap_conn, None) ++ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \ ++ unindent(""" ++ [domain/LDAP] ++ auto_private_groups = True ++ ldap_user_gid_number = no_such_attribute ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ ++def test_ldap_auto_private_groups_direct_no_gid(ldap_conn, mpg_setup_no_gid): ++ """ ++ Integration test for auto_private_groups - test that even a user with ++ no GID assigned at all can be resolved including their autogenerated ++ primary group. ++ ++ See also ticket https://pagure.io/SSSD/sssd/issue/1872 ++ """ ++ # Make sure the user's GID is taken from their uidNumber ++ ent.assert_passwd_by_name("user1", dict(name="user1", uid=1001, gid=1001)) ++ # Make sure the private group is resolvable by name and by GID ++ ent.assert_group_by_name("user1", dict(gid=1001, mem=ent.contains_only())) ++ ent.assert_group_by_gid(1001, dict(name="user1", mem=ent.contains_only())) ++ ++ # The group referenced in user's gidNumber attribute should be still ++ # visible, but shouldn't have any relation to the user ++ ent.assert_group_by_name("group1", dict(gid=2001, mem=ent.contains_only())) ++ ent.assert_group_by_gid(2001, dict(name="group1", mem=ent.contains_only())) ++ ++ # The user's secondary groups list must be correct as well. This time only ++ # the generated group and the explicit secondary group are added, since ++ # there is no original GID ++ user1_expected_gids = [1001, 2015] ++ (res, errno, gids) = sssd_id.call_sssd_initgroups("user1", 1001) ++ assert res == sssd_id.NssReturnCode.SUCCESS ++ ++ assert sorted(gids) == sorted(user1_expected_gids), \ ++ "result: %s\n expected %s" % ( ++ ", ".join(["%s" % s for s in sorted(gids)]), ++ ", ".join(["%s" % s for s in sorted(user1_expected_gids)]) ++ ) +-- +2.13.5 + diff --git a/SOURCES/0009-sss_cert_derb64_to_ldap_filter-add-sss_certmap-suppo.patch b/SOURCES/0009-sss_cert_derb64_to_ldap_filter-add-sss_certmap-suppo.patch deleted file mode 100644 index d53da7d..0000000 --- a/SOURCES/0009-sss_cert_derb64_to_ldap_filter-add-sss_certmap-suppo.patch +++ /dev/null @@ -1,235 +0,0 @@ -From 2e12cbdc8e2676b045a972045e9dae75b232dc76 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 2 Feb 2017 16:34:32 +0100 -Subject: [PATCH 09/15] sss_cert_derb64_to_ldap_filter: add sss_certmap support -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use certificate mapping library if available to lookup a user by -certificate in LDAP. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - Makefile.am | 1 + - src/db/sysdb_ops.c | 2 +- - src/db/sysdb_views.c | 4 +- - src/providers/ipa/ipa_views.c | 2 +- - src/providers/ldap/ldap_id.c | 2 +- - src/tests/cmocka/test_cert_utils.c | 4 +- - src/util/cert.h | 3 ++ - src/util/cert/cert_common.c | 76 ++++++++++++++++++++++++++++++++------ - 8 files changed, 76 insertions(+), 18 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index 7947b7a5fbe3ca1034baac1c13c53300994b1bf8..f262cc24832358910dbb92ccd46f93c9eda8a295 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -952,6 +952,7 @@ libsss_cert_la_LIBADD = \ - $(TALLOC_LIBS) \ - libsss_crypt.la \ - libsss_debug.la \ -+ libsss_certmap.la \ - $(NULL) - libsss_cert_la_LDFLAGS = \ - -avoid-version \ -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 8ae25764478e522255b177f9e8de1d3ca1ad43fd..919f22370ff87eff2bf0bb569ca90f1ee699a61e 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -4661,7 +4661,7 @@ errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx, - char *user_filter; - - ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_MAPPED_CERT, -- &user_filter); -+ NULL, NULL, &user_filter); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n"); - return ret; -diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c -index 9dc48f5b6c414bbc7c64bcd1fe73553f388588bd..1c416dd14049237e9f35d52f154035e3ff861469 100644 ---- a/src/db/sysdb_views.c -+++ b/src/db/sysdb_views.c -@@ -862,8 +862,8 @@ errno_t sysdb_search_override_by_cert(TALLOC_CTX *mem_ctx, - goto done; - } - -- ret = sss_cert_derb64_to_ldap_filter(tmp_ctx, cert, SYSDB_USER_CERT, -- &cert_filter); -+ ret = sss_cert_derb64_to_ldap_filter(tmp_ctx, cert, SYSDB_USER_CERT, NULL, -+ NULL, &cert_filter); - - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n"); -diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c -index 29f589ec1fd05f59175dcc4592e6395941e6e034..5b6fcbc9b7c6f2ea7dbeecb01a5a3fd11b8a6854 100644 ---- a/src/providers/ipa/ipa_views.c -+++ b/src/providers/ipa/ipa_views.c -@@ -156,7 +156,7 @@ static errno_t dp_id_data_to_override_filter(TALLOC_CTX *mem_ctx, - if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_BY_CERT) { - ret = sss_cert_derb64_to_ldap_filter(mem_ctx, ar->filter_value, - ipa_opts->override_map[IPA_AT_OVERRIDE_USER_CERT].name, -- &cert_filter); -+ NULL, NULL, &cert_filter); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "sss_cert_derb64_to_ldap_filter failed.\n"); -diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c -index a8b4bc2cfc6e9d4e0d74b0e3e036afbcbf7eb26e..8e60769d09383ac8ebe33e5f64fd4fd9788e82cd 100644 ---- a/src/providers/ldap/ldap_id.c -+++ b/src/providers/ldap/ldap_id.c -@@ -247,7 +247,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - } - - ret = sss_cert_derb64_to_ldap_filter(state, filter_value, attr_name, -- &user_filter); -+ NULL, NULL, &user_filter); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "sss_cert_derb64_to_ldap_filter failed.\n"); -diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c -index 35e8cb7513968079861048a7e8b0631229f202c0..5830131754e4cf318273151b586ef36d6a349829 100644 ---- a/src/tests/cmocka/test_cert_utils.c -+++ b/src/tests/cmocka/test_cert_utils.c -@@ -297,11 +297,11 @@ void test_sss_cert_derb64_to_ldap_filter(void **state) - struct test_state *ts = talloc_get_type_abort(*state, struct test_state); - assert_non_null(ts); - -- ret = sss_cert_derb64_to_ldap_filter(ts, NULL, NULL, NULL); -+ ret = sss_cert_derb64_to_ldap_filter(ts, NULL, NULL, NULL, NULL, NULL); - assert_int_equal(ret, EINVAL); - - ret = sss_cert_derb64_to_ldap_filter(ts, "AAECAwQFBgcICQ==", "attrName", -- &filter); -+ NULL, NULL, &filter); - assert_int_equal(ret, EOK); - assert_string_equal(filter, - "(attrName=\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09)"); -diff --git a/src/util/cert.h b/src/util/cert.h -index bb64d0d7a0a48207df60f6e6e554da5e16a16b03..4598aa8df0cd860fed71d9cd2e4beec7f1910578 100644 ---- a/src/util/cert.h -+++ b/src/util/cert.h -@@ -21,6 +21,7 @@ - #include - - #include "util/util.h" -+#include "lib/certmap/sss_certmap.h" - - #ifndef __CERT_H__ - #define __CERT_H__ -@@ -39,6 +40,8 @@ errno_t sss_cert_pem_to_derb64(TALLOC_CTX *mem_ctx, const char *pem, - - errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64, - const char *attr_name, -+ struct sss_certmap_ctx *certmap_ctx, -+ struct sss_domain_info *dom, - char **ldap_filter); - - errno_t bin_to_ldap_filter_value(TALLOC_CTX *mem_ctx, -diff --git a/src/util/cert/cert_common.c b/src/util/cert/cert_common.c -index a29696ed3cd9f2168f47323fac97d44e9b49f921..766877089429ff1c01000a3986316c74583e3fa4 100644 ---- a/src/util/cert/cert_common.c -+++ b/src/util/cert/cert_common.c -@@ -72,12 +72,17 @@ errno_t sss_cert_pem_to_derb64(TALLOC_CTX *mem_ctx, const char *pem, - - errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64, - const char *attr_name, -+ struct sss_certmap_ctx *certmap_ctx, -+ struct sss_domain_info *dom, - char **ldap_filter) - { - int ret; - unsigned char *der; - size_t der_size; - char *val; -+ char *filter = NULL; -+ char **domains = NULL; -+ size_t c; - - if (derb64 == NULL || attr_name == NULL) { - return EINVAL; -@@ -89,18 +94,67 @@ errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64, - return EINVAL; - } - -- ret = bin_to_ldap_filter_value(mem_ctx, der, der_size, &val); -- talloc_free(der); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "bin_to_ldap_filter_value failed.\n"); -- return ret; -- } -+ if (certmap_ctx == NULL) { -+ ret = bin_to_ldap_filter_value(mem_ctx, der, der_size, &val); -+ talloc_free(der); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "bin_to_ldap_filter_value failed.\n"); -+ return ret; -+ } - -- *ldap_filter = talloc_asprintf(mem_ctx, "(%s=%s)", attr_name, val); -- talloc_free(val); -- if (*ldap_filter == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -- return ENOMEM; -+ *ldap_filter = talloc_asprintf(mem_ctx, "(%s=%s)", attr_name, val); -+ talloc_free(val); -+ if (*ldap_filter == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -+ return ENOMEM; -+ } -+ } else { -+ ret = sss_certmap_get_search_filter(certmap_ctx, der, der_size, -+ &filter, &domains); -+ talloc_free(der); -+ if (ret != 0) { -+ if (ret == ENOENT) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Certificate does not match matching-rules.\n"); -+ } else { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sss_certmap_get_search_filter failed.\n"); -+ } -+ } else { -+ if (domains == NULL) { -+ if (IS_SUBDOMAIN(dom)) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Rule applies only to local domain.\n"); -+ ret = ENOENT; -+ } -+ } else { -+ for (c = 0; domains[c] != NULL; c++) { -+ if (strcasecmp(dom->name, domains[c]) == 0) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Rule applies to current domain [%s].\n", -+ dom->name); -+ ret = EOK; -+ break; -+ } -+ } -+ if (domains[c] == NULL) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Rule does not apply to current domain [%s].\n", -+ dom->name); -+ ret = ENOENT; -+ } -+ } -+ } -+ -+ if (ret == EOK) { -+ *ldap_filter = talloc_strdup(mem_ctx, filter); -+ if (*ldap_filter == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ } -+ } -+ sss_certmap_free_filter_and_domains(filter, domains); -+ return ret; - } - - return EOK; --- -2.9.3 - diff --git a/SOURCES/0010-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch b/SOURCES/0010-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch new file mode 100644 index 0000000..39c79de --- /dev/null +++ b/SOURCES/0010-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch @@ -0,0 +1,142 @@ +From ec3334b5a09328de492804c391654073553ff7e7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Fri, 20 Oct 2017 09:26:43 +0200 +Subject: [PATCH 10/21] CACHE_REQ: Copy the cr_domain list for each request +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let's copy the cr_domain list for each request as this list may be +free'd due to a refresh domains request. + +Resolves: https://pagure.io/SSSD/sssd/issue/3551 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit 0f44eefe2ce75a0814c8688495477f6c57f3d39a) +--- + src/responder/common/cache_req/cache_req.c | 14 +++++++-- + src/responder/common/cache_req/cache_req_domain.c | 38 +++++++++++++++++++++++ + src/responder/common/cache_req/cache_req_domain.h | 5 +++ + 3 files changed, 55 insertions(+), 2 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index abcb9cba351b06e833bacde26a504e5ee3445528..5fed7a2ab8beded2fee91f679a12f9a0ff6013ec 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -699,6 +699,7 @@ struct cache_req_state { + const char *domain_name; + + /* work data */ ++ struct cache_req_domain *cr_domains; + struct cache_req_result **results; + size_t num_results; + bool first_iteration; +@@ -953,6 +954,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req, + bool bypass_cache; + bool bypass_dp; + bool search; ++ errno_t ret; + + state = tevent_req_data(req, struct cache_req_state); + +@@ -964,12 +966,20 @@ static errno_t cache_req_select_domains(struct tevent_req *req, + return EOK; + } + ++ ret = cache_req_domain_copy_cr_domains(state, ++ state->cr->rctx->cr_domains, ++ &state->cr_domains); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_copy_cr_domains() failed\n"); ++ return EINVAL; ++ } ++ + if (domain_name != NULL) { + CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, + "Performing a single domain search\n"); + + cr_domain = cache_req_domain_get_domain_by_name( +- state->cr->rctx->cr_domains, domain_name); ++ state->cr_domains, domain_name); + if (cr_domain == NULL) { + return ERR_DOMAIN_NOT_FOUND; + } +@@ -978,7 +988,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req, + CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, + "Performing a multi-domain search\n"); + +- cr_domain = state->cr->rctx->cr_domains; ++ cr_domain = state->cr_domains; + check_next = true; + } + +diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c +index 7b58f7c94a77881429f870bc5162fb2fe0aa57c6..15893ba548f6d0e3979010d6d5bbf27441d5fa97 100644 +--- a/src/responder/common/cache_req/cache_req_domain.c ++++ b/src/responder/common/cache_req/cache_req_domain.c +@@ -47,6 +47,44 @@ cache_req_domain_get_domain_by_name(struct cache_req_domain *domains, + return ret; + } + ++errno_t ++cache_req_domain_copy_cr_domains(TALLOC_CTX *mem_ctx, ++ struct cache_req_domain *src, ++ struct cache_req_domain **_dest) ++{ ++ struct cache_req_domain *cr_domains = NULL; ++ struct cache_req_domain *cr_domain; ++ struct cache_req_domain *iter; ++ errno_t ret; ++ ++ if (src == NULL) { ++ return EINVAL; ++ } ++ ++ DLIST_FOR_EACH(iter, src) { ++ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain); ++ if (cr_domain == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ cr_domain->domain = iter->domain; ++ cr_domain->fqnames = iter->fqnames; ++ ++ DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *); ++ } ++ ++ *_dest = cr_domains; ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ cache_req_domain_list_zfree(&cr_domains); ++ } ++ ++ return ret; ++} ++ + void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains) + { + struct cache_req_domain *p, *q, *r; +diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h +index 3780a5d8d88d76e100738d28d1dd0e697edf5eae..ebdc71dd635d5d8a5d06e30e96c5d4101b6d98bf 100644 +--- a/src/responder/common/cache_req/cache_req_domain.h ++++ b/src/responder/common/cache_req/cache_req_domain.h +@@ -50,6 +50,11 @@ cache_req_domain_new_list_from_domain_resolution_order( + const char *domain_resolution_order, + struct cache_req_domain **_cr_domains); + ++errno_t ++cache_req_domain_copy_cr_domains(TALLOC_CTX *mem_ctx, ++ struct cache_req_domain *src, ++ struct cache_req_domain **_dest); ++ + void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains); + + +-- +2.13.5 + diff --git a/SOURCES/0010-sysdb-add-certmap-related-calls.patch b/SOURCES/0010-sysdb-add-certmap-related-calls.patch deleted file mode 100644 index 5b33d5f..0000000 --- a/SOURCES/0010-sysdb-add-certmap-related-calls.patch +++ /dev/null @@ -1,846 +0,0 @@ -From cfb6a115568ab24fe5df365d1436419b504111ec Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 6 Feb 2017 10:27:22 +0100 -Subject: [PATCH 10/15] sysdb: add certmap related calls -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add sysdb calls to write and read data for the certificate mapping -library to the cache. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - Makefile.am | 17 ++ - src/db/sysdb.h | 27 +++ - src/db/sysdb_certmap.c | 425 ++++++++++++++++++++++++++++++++++ - src/tests/cmocka/test_sysdb_certmap.c | 260 +++++++++++++++++++++ - 4 files changed, 729 insertions(+) - create mode 100644 src/db/sysdb_certmap.c - create mode 100644 src/tests/cmocka/test_sysdb_certmap.c - -diff --git a/Makefile.am b/Makefile.am -index f262cc24832358910dbb92ccd46f93c9eda8a295..bd0ca0d303e1742ad26c7648cd24e2c0135af34e 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -254,6 +254,7 @@ if HAVE_CMOCKA - test_sysdb_ts_cache \ - test_sysdb_views \ - test_sysdb_subdomains \ -+ test_sysdb_certmap \ - test_sysdb_sudo \ - test_sysdb_utils \ - test_wbc_calls \ -@@ -974,6 +975,7 @@ libsss_util_la_SOURCES = \ - src/db/sysdb_ranges.c \ - src/db/sysdb_idmap.c \ - src/db/sysdb_gpo.c \ -+ src/db/sysdb_certmap.c \ - src/monitor/monitor_sbus.c \ - src/providers/dp_auth_util.c \ - src/providers/dp_pam_data_util.c \ -@@ -2773,6 +2775,21 @@ test_sysdb_subdomains_LDADD = \ - libsss_test_common.la \ - $(NULL) - -+test_sysdb_certmap_SOURCES = \ -+ src/tests/cmocka/test_sysdb_certmap.c \ -+ $(NULL) -+test_sysdb_certmap_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(NULL) -+test_sysdb_certmap_LDADD = \ -+ $(CMOCKA_LIBS) \ -+ $(LDB_LIBS) \ -+ $(POPT_LIBS) \ -+ $(TALLOC_LIBS) \ -+ $(SSSD_INTERNAL_LTLIBS) \ -+ libsss_test_common.la \ -+ $(NULL) -+ - test_sysdb_sudo_SOURCES = \ - src/tests/cmocka/test_sysdb_sudo.c \ - $(NULL) -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 3db22b3689bf6ffd9a48e29c229916e3fac9ca1b..0cbb2c5c02355e9e9a4e73b075f92d16e4855045 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -39,6 +39,7 @@ - #define SYSDB_NETGROUP_CONTAINER "cn=Netgroups" - #define SYSDB_RANGE_CONTAINER "cn=ranges" - #define SYSDB_VIEW_CONTAINER "cn=views" -+#define SYSDB_CERTMAP_CONTAINER "cn=certmap" - #define SYSDB_TMPL_USER_BASE SYSDB_USERS_CONTAINER","SYSDB_DOM_BASE - #define SYSDB_TMPL_GROUP_BASE SYSDB_GROUPS_CONTAINER","SYSDB_DOM_BASE - #define SYSDB_TMPL_CUSTOM_BASE SYSDB_CUSTOM_CONTAINER","SYSDB_DOM_BASE -@@ -46,6 +47,7 @@ - #define SYSDB_TMPL_RANGE_BASE SYSDB_RANGE_CONTAINER","SYSDB_BASE - #define SYSDB_TMPL_VIEW_BASE SYSDB_VIEW_CONTAINER","SYSDB_BASE - #define SYSDB_TMPL_VIEW_SEARCH_BASE "cn=%s,"SYSDB_TMPL_VIEW_BASE -+#define SYSDB_TMPL_CERTMAP_BASE SYSDB_CERTMAP_CONTAINER","SYSDB_BASE - - #define SYSDB_SUBDOMAIN_CLASS "subdomain" - #define SYSDB_USER_CLASS "user" -@@ -58,6 +60,7 @@ - #define SYSDB_ID_RANGE_CLASS "idRange" - #define SYSDB_DOMAIN_ID_RANGE_CLASS "domainIDRange" - #define SYSDB_TRUSTED_AD_DOMAIN_RANGE_CLASS "TrustedADDomainRange" -+#define SYSDB_CERTMAP_CLASS "certificateMappingRule" - - #define SYSDB_DN "dn" - #define SYSDB_NAME "name" -@@ -158,6 +161,12 @@ - #define SYSDB_DOMAIN_ID "domainID" - #define SYSDB_ID_RANGE_TYPE "idRangeType" - -+#define SYSDB_CERTMAP_PRIORITY "priority" -+#define SYSDB_CERTMAP_MATCHING_RULE "matchingRule" -+#define SYSDB_CERTMAP_MAPPING_RULE "mappingRule" -+#define SYSDB_CERTMAP_DOMAINS "domains" -+#define SYSDB_CERTMAP_USER_NAME_HINT "userNameHint" -+ - #define ORIGINALAD_PREFIX "originalAD" - #define OVERRIDE_PREFIX "override" - #define SYSDB_DEFAULT_OVERRIDE_NAME "defaultOverrideName" -@@ -264,6 +273,7 @@ - #define SYSDB_TMPL_CUSTOM SYSDB_NAME"=%s,cn=%s,"SYSDB_TMPL_CUSTOM_BASE - #define SYSDB_TMPL_RANGE SYSDB_NAME"=%s,"SYSDB_TMPL_RANGE_BASE - #define SYSDB_TMPL_OVERRIDE SYSDB_OVERRIDE_ANCHOR_UUID"=%s,"SYSDB_TMPL_VIEW_SEARCH_BASE -+#define SYSDB_TMPL_CERTMAP SYSDB_NAME"=%s,"SYSDB_TMPL_CERTMAP_BASE - - #define SYSDB_MOD_ADD LDB_FLAG_MOD_ADD - #define SYSDB_MOD_DEL LDB_FLAG_MOD_DELETE -@@ -320,6 +330,15 @@ struct range_info { - char *range_type; - }; - -+struct certmap_info { -+ char *name; -+ uint32_t priority; -+ char *match_rule; -+ char *map_rule; -+ const char **domains; -+}; -+ -+ - /* These attributes are stored in the timestamp cache */ - extern const char *sysdb_ts_cache_attrs[]; - -@@ -619,6 +638,14 @@ uint64_t sss_view_ldb_msg_find_attr_as_uint64(struct sss_domain_info *dom, - const char *attr_name, - uint64_t default_value); - -+errno_t sysdb_update_certmap(struct sysdb_ctx *sysdb, -+ struct certmap_info **certmaps, -+ bool user_name_hint); -+ -+errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, -+ struct certmap_info ***certmaps, -+ bool *user_name_hint); -+ - /* Sysdb initialization. - * call this function *only* once to initialize the database and get - * the sysdb ctx */ -diff --git a/src/db/sysdb_certmap.c b/src/db/sysdb_certmap.c -new file mode 100644 -index 0000000000000000000000000000000000000000..4917796b11c3967b4d147ebee7c7e83f09b872ce ---- /dev/null -+++ b/src/db/sysdb_certmap.c -@@ -0,0 +1,425 @@ -+/* -+ SSSD -+ -+ System Database - certificate mapping rules related calls -+ -+ Copyright (C) 2017 Sumit Bose -+ -+ 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 "util/util.h" -+#include "db/sysdb_private.h" -+ -+static errno_t sysdb_create_certmap_container(struct sysdb_ctx *sysdb, -+ bool user_name_hint) -+{ -+ struct ldb_message *msg = NULL; -+ errno_t ret; -+ -+ msg = ldb_msg_new(sysdb); -+ if (msg == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ msg->dn = ldb_dn_new(msg, sysdb->ldb, SYSDB_TMPL_CERTMAP_BASE); -+ if (msg->dn == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ ret = ldb_msg_add_string(msg, "cn", "certmap"); -+ if (ret != LDB_SUCCESS) { -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ -+ ret = ldb_msg_add_string(msg, SYSDB_CERTMAP_USER_NAME_HINT, -+ user_name_hint ? "TRUE" : "FALSE"); -+ if (ret != LDB_SUCCESS) { -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ -+ /* do a synchronous add */ -+ ret = ldb_add(sysdb->ldb, msg); -+ if (ret != LDB_SUCCESS) { -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "Failed to add certmap container (%d, [%s])!\n", -+ ret, ldb_errstring(sysdb->ldb)); -+ ret = EIO; -+ goto done; -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_free(msg); -+ -+ return ret; -+} -+ -+static errno_t sysdb_certmap_add(struct sysdb_ctx *sysdb, -+ struct certmap_info *certmap) -+{ -+ struct ldb_message *msg; -+ struct ldb_message_element *el; -+ int ret; -+ TALLOC_CTX *tmp_ctx; -+ size_t c; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed"); -+ return ENOMEM; -+ } -+ -+ msg = ldb_msg_new(tmp_ctx); -+ if (msg == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ msg->dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, -+ SYSDB_TMPL_CERTMAP, certmap->name); -+ if (msg->dn == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sysdb_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_CERTMAP_CLASS); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n"); -+ goto done; -+ } -+ -+ ret = sysdb_add_string(msg, SYSDB_NAME, certmap->name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n"); -+ goto done; -+ } -+ -+ if (certmap->map_rule != NULL) { -+ ret = sysdb_add_string(msg, SYSDB_CERTMAP_MAPPING_RULE, -+ certmap->map_rule); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n"); -+ goto done; -+ } -+ } -+ -+ if (certmap->match_rule != NULL) { -+ ret = sysdb_add_string(msg, SYSDB_CERTMAP_MATCHING_RULE, -+ certmap->match_rule); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n"); -+ goto done; -+ } -+ } -+ -+ if (certmap->domains != NULL) { -+ for (c = 0; certmap->domains[c] != NULL; c++); -+ el = talloc_zero(tmp_ctx, struct ldb_message_element); -+ if (el == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ el->name = talloc_strdup(el, SYSDB_CERTMAP_DOMAINS); -+ if(el->name == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ el->num_values = c; -+ el->values = talloc_zero_array(el, struct ldb_val, c + 1); -+ if (el->values == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ for (c = 0; certmap->domains[c] != NULL; c++) { -+ el->values[c].data = (uint8_t *) talloc_strdup(el->values, -+ certmap->domains[c]); -+ if (el->values[c].data == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ el->values[c].length = strlen(certmap->domains[c]); -+ } -+ -+ ret = ldb_msg_add(msg, el, LDB_FLAG_MOD_ADD); -+ if (ret != LDB_SUCCESS) { -+ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add failed.\n"); -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ } -+ -+ ret = sysdb_add_ulong(msg, SYSDB_CERTMAP_PRIORITY, -+ (unsigned long)certmap->priority); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_ulong failed.\n"); -+ goto done; -+ } -+ -+ ret = ldb_add(sysdb->ldb, msg); -+ if (ret != LDB_SUCCESS) { -+ DEBUG(SSSDBG_OP_FAILURE, "ldb_add failed.\n"); -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ -+ ret = EOK; -+ -+done: -+ if (ret) { -+ DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, sss_strerror(ret)); -+ } -+ talloc_zfree(tmp_ctx); -+ return ret; -+} -+ -+errno_t sysdb_update_certmap(struct sysdb_ctx *sysdb, -+ struct certmap_info **certmaps, -+ bool user_name_hint) -+{ -+ size_t c; -+ struct ldb_dn *container_dn = NULL; -+ bool in_transaction = false; -+ int ret; -+ int sret; -+ -+ if (certmaps == NULL) { -+ return EINVAL; -+ } -+ -+ container_dn = ldb_dn_new(sysdb, sysdb->ldb, SYSDB_TMPL_CERTMAP_BASE); -+ if (container_dn == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n"); -+ return ENOMEM; -+ } -+ -+ ret = sysdb_transaction_start(sysdb); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_start failed.\n"); -+ goto done; -+ } -+ in_transaction = true; -+ -+ ret = sysdb_delete_recursive(sysdb, container_dn, true); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_recursive failed.\n"); -+ goto done; -+ } -+ ret = sysdb_create_certmap_container(sysdb, user_name_hint); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_create_certmap_container failed.\n"); -+ goto done; -+ } -+ -+ for (c = 0; certmaps[c] != NULL; c++) { -+ ret = sysdb_certmap_add(sysdb, certmaps[c]); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_certmap_add failed.\n"); -+ goto done; -+ } -+ } -+ -+ ret = sysdb_transaction_commit(sysdb); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_transaction_commit failed.\n"); -+ goto done; -+ } -+ in_transaction = false; -+ -+done: -+ if (in_transaction) { -+ sret = sysdb_transaction_cancel(sysdb); -+ if (sret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction.\n"); -+ } -+ } -+ -+ talloc_free(container_dn); -+ -+ 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; -+ 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_DOMAINS, -+ NULL}; -+ const char *config_attrs[] = {SYSDB_CERTMAP_USER_NAME_HINT, -+ NULL}; -+ size_t num_values; -+ bool hint = false; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ container_dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_TMPL_CERTMAP_BASE); -+ if (container_dn == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, container_dn, LDB_SCOPE_BASE, -+ config_attrs, SYSDB_CERTMAP_USER_NAME_HINT"=*"); -+ if (ret != LDB_SUCCESS || res->count != 1) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to read certmap config, skipping.\n"); -+ } else { -+ hint = ldb_msg_find_attr_as_bool(res->msgs[0], -+ SYSDB_CERTMAP_USER_NAME_HINT, false); -+ } -+ -+ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, -+ container_dn, LDB_SCOPE_SUBTREE, -+ attrs, "objectclass=%s", SYSDB_CERTMAP_CLASS); -+ if (ret != LDB_SUCCESS) { -+ DEBUG(SSSDBG_OP_FAILURE, "ldb_search failed.\n"); -+ ret = EIO; -+ goto done; -+ } -+ -+ if (res->count == 0) { -+ DEBUG(SSSDBG_TRACE_FUNC, "No certificate maps found.\n"); -+ ret = ENOENT; -+ goto done; -+ } -+ -+ maps = talloc_zero_array(tmp_ctx, struct certmap_info *, res->count + 1); -+ if (maps == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ 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; -+ 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; -+ } -+ } -+ } -+ -+ *certmaps = talloc_steal(mem_ctx, maps); -+ *user_name_hint = hint; -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ -+ return ret; -+} -diff --git a/src/tests/cmocka/test_sysdb_certmap.c b/src/tests/cmocka/test_sysdb_certmap.c -new file mode 100644 -index 0000000000000000000000000000000000000000..fb07165561779226935f436c308c85abfc305635 ---- /dev/null -+++ b/src/tests/cmocka/test_sysdb_certmap.c -@@ -0,0 +1,260 @@ -+/* -+ SSSD -+ -+ sysdb_certmap - Tests for sysdb certmap realted calls -+ -+ Authors: -+ Jakub Hrozek -+ -+ Copyright (C) 2017 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 -+#include -+#include -+#include -+ -+#include "tests/cmocka/common_mock.h" -+#include "tests/common.h" -+ -+#define TESTS_PATH "certmap_" BASE_FILE_STEM -+#define TEST_CONF_DB "test_sysdb_certmap.ldb" -+#define TEST_ID_PROVIDER "ldap" -+#define TEST_DOM_NAME "certmap_test" -+ -+struct certmap_test_ctx { -+ struct sss_test_ctx *tctx; -+}; -+ -+static int test_sysdb_setup(void **state) -+{ -+ struct certmap_test_ctx *test_ctx; -+ struct sss_test_conf_param params[] = { -+ { NULL, NULL }, /* Sentinel */ -+ }; -+ -+ assert_true(leak_check_setup()); -+ -+ test_ctx = talloc_zero(global_talloc_context, -+ struct certmap_test_ctx); -+ assert_non_null(test_ctx); -+ check_leaks_push(test_ctx); -+ -+ test_dom_suite_setup(TESTS_PATH); -+ -+ test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, -+ TEST_CONF_DB, TEST_DOM_NAME, -+ TEST_ID_PROVIDER, params); -+ assert_non_null(test_ctx->tctx); -+ -+ *state = test_ctx; -+ return 0; -+} -+ -+static int test_sysdb_teardown(void **state) -+{ -+ struct certmap_test_ctx *test_ctx = -+ talloc_get_type(*state, struct certmap_test_ctx); -+ -+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); -+ talloc_free(test_ctx->tctx); -+ assert_true(check_leaks_pop(test_ctx)); -+ talloc_free(test_ctx); -+ assert_true(leak_check_teardown()); -+ return 0; -+} -+ -+static void test_sysdb_get_certmap_not_exists(void **state) -+{ -+ int ret; -+ struct certmap_info **certmap; -+ bool user_name_hint; -+ struct certmap_test_ctx *ctctx = talloc_get_type(*state, -+ struct certmap_test_ctx); -+ -+ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, -+ &user_name_hint); -+ assert_int_equal(ret, ENOENT); -+ -+} -+ -+static void check_certmap(struct certmap_info *m, struct certmap_info *r, -+ size_t exp_domains) -+{ -+ size_t d; -+ -+ assert_non_null(r); -+ assert_non_null(m); -+ assert_string_equal(m->name, r->name); -+ -+ if (r->map_rule == NULL) { -+ assert_null(m->map_rule); -+ } else { -+ assert_string_equal(m->map_rule, r->map_rule); -+ } -+ -+ if (r->match_rule == NULL) { -+ assert_null(m->match_rule); -+ } else { -+ assert_string_equal(m->match_rule, r->match_rule); -+ } -+ -+ assert_int_equal(m->priority, r->priority); -+ assert_non_null(m->domains); -+ if (r->domains == NULL) { -+ assert_null(m->domains[0]); -+ } else { -+ for (d = 0; r->domains[d]; d++) { -+ assert_non_null(m->domains[d]); -+ assert_true(string_in_list(m->domains[d], discard_const(r->domains), -+ true)); -+ } -+ -+ assert_int_equal(d, exp_domains); -+ } -+ -+} -+ -+static void test_sysdb_update_certmap(void **state) -+{ -+ int ret; -+ const char *domains[] = { "dom1.test", "dom2.test", "dom3.test", NULL }; -+ struct certmap_info map_a = { discard_const("map_a"), 11, discard_const("abc"), discard_const("def"), NULL }; -+ struct certmap_info map_b = { discard_const("map_b"), 22, discard_const("abc"), NULL, domains }; -+ struct certmap_info *certmap_empty[] = { NULL }; -+ struct certmap_info *certmap_a[] = { &map_a, NULL }; -+ struct certmap_info *certmap_b[] = { &map_b, NULL }; -+ struct certmap_info *certmap_ab[] = { &map_a, &map_b, NULL }; -+ struct certmap_info **certmap; -+ struct certmap_test_ctx *ctctx = talloc_get_type(*state, -+ struct certmap_test_ctx); -+ bool user_name_hint; -+ -+ ret = sysdb_update_certmap(ctctx->tctx->sysdb, NULL, false); -+ assert_int_equal(ret, EINVAL); -+ -+ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_empty, false); -+ assert_int_equal(ret, EOK); -+ -+ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, -+ &user_name_hint); -+ assert_int_equal(ret, ENOENT); -+ -+ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_a, false); -+ assert_int_equal(ret, EOK); -+ -+ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, -+ &user_name_hint); -+ assert_int_equal(ret, EOK); -+ assert_false(user_name_hint); -+ assert_non_null(certmap); -+ assert_non_null(certmap[0]); -+ assert_string_equal(certmap[0]->name, map_a.name); -+ assert_string_equal(certmap[0]->map_rule, map_a.map_rule); -+ assert_string_equal(certmap[0]->match_rule, map_a.match_rule); -+ assert_int_equal(certmap[0]->priority, map_a.priority); -+ assert_non_null(certmap[0]->domains); -+ assert_null(certmap[0]->domains[0]); -+ assert_null(certmap[1]); -+ check_certmap(certmap[0], &map_a, 0); -+ talloc_free(certmap); -+ -+ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_b, true); -+ assert_int_equal(ret, EOK); -+ -+ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, -+ &user_name_hint); -+ assert_int_equal(ret, EOK); -+ assert_true(user_name_hint); -+ assert_non_null(certmap); -+ assert_non_null(certmap[0]); -+ -+ check_certmap(certmap[0], &map_b, 3); -+ assert_null(certmap[1]); -+ talloc_free(certmap); -+ -+ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_ab, false); -+ assert_int_equal(ret, EOK); -+ -+ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, -+ &user_name_hint); -+ assert_int_equal(ret, EOK); -+ assert_false(user_name_hint); -+ assert_non_null(certmap); -+ assert_non_null(certmap[0]); -+ assert_non_null(certmap[1]); -+ assert_null(certmap[2]); -+ if (strcmp(certmap[0]->name, "map_a") == 0) { -+ check_certmap(certmap[0], &map_a, 0); -+ check_certmap(certmap[1], &map_b, 3); -+ } else { -+ check_certmap(certmap[0], &map_b, 3); -+ check_certmap(certmap[1], &map_a, 0); -+ } -+ talloc_free(certmap); -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ int rv; -+ int no_cleanup = 0; -+ poptContext pc; -+ int opt; -+ struct poptOption long_options[] = { -+ POPT_AUTOHELP -+ SSSD_DEBUG_OPTS -+ {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0, -+ _("Do not delete the test database after a test run"), NULL }, -+ POPT_TABLEEND -+ }; -+ -+ const struct CMUnitTest tests[] = { -+ cmocka_unit_test_setup_teardown(test_sysdb_get_certmap_not_exists, -+ test_sysdb_setup, -+ test_sysdb_teardown), -+ cmocka_unit_test_setup_teardown(test_sysdb_update_certmap, -+ test_sysdb_setup, -+ test_sysdb_teardown), -+ }; -+ -+ /* Set debug level to invalid value so we can deside if -d 0 was used. */ -+ debug_level = SSSDBG_INVALID; -+ -+ pc = poptGetContext(argv[0], argc, argv, long_options, 0); -+ while((opt = poptGetNextOpt(pc)) != -1) { -+ switch(opt) { -+ default: -+ fprintf(stderr, "\nInvalid option %s: %s\n\n", -+ poptBadOption(pc, 0), poptStrerror(opt)); -+ poptPrintUsage(pc, stderr, 0); -+ return 1; -+ } -+ } -+ poptFreeContext(pc); -+ -+ DEBUG_CLI_INIT(debug_level); -+ -+ tests_set_cwd(); -+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE); -+ test_dom_suite_setup(TESTS_PATH); -+ rv = cmocka_run_group_tests(tests, NULL, NULL); -+ -+ if (rv == 0 && no_cleanup == 0) { -+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE); -+ } -+ return rv; -+} --- -2.9.3 - diff --git a/SOURCES/0011-IPA-add-certmap-support.patch b/SOURCES/0011-IPA-add-certmap-support.patch deleted file mode 100644 index d2b8ff6..0000000 --- a/SOURCES/0011-IPA-add-certmap-support.patch +++ /dev/null @@ -1,484 +0,0 @@ -From d51754859a83e7fedf0cac90ad8bf5de09f35463 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 6 Feb 2017 10:28:46 +0100 -Subject: [PATCH 11/15] IPA: add certmap support -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Read certificate mapping data from the IPA server and configure the -certificate mapping library accordingly. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - src/providers/ipa/ipa_config.h | 2 + - src/providers/ipa/ipa_subdomains.c | 354 ++++++++++++++++++++++++++++++ - src/providers/ipa/ipa_subdomains_server.c | 4 + - src/providers/ldap/ldap_id.c | 4 +- - src/providers/ldap/sdap.h | 4 + - 5 files changed, 367 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ipa/ipa_config.h b/src/providers/ipa/ipa_config.h -index 2f1e147d7edab0aca2a16269c6a73bc607b21bd5..60f2d5d7b71227a1d86889ceaf6f0f9ac868480d 100644 ---- a/src/providers/ipa/ipa_config.h -+++ b/src/providers/ipa/ipa_config.h -@@ -37,6 +37,8 @@ - #define IPA_CONFIG_SEARCH_BASE_TEMPLATE "cn=etc,%s" - #define IPA_CONFIG_FILTER "(&(cn=ipaConfig)(objectClass=ipaGuiConfig))" - -+#define IPA_OC_CONFIG "ipaConfig" -+ - struct tevent_req * ipa_get_config_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sdap_handle *sh, -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index b2e96b204213a52014edcc6042ffa1ff8152b8bf..7537550606ef09c0b87a80932c75aa4f93c0efab 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -56,6 +56,24 @@ - - #define IPA_SUBDOMAIN_DISABLED_PERIOD 3600 - -+#define IPA_OC_CERTMAP_CONFIG_OBJECT "ipaCertMapConfigObject" -+#define IPA_CERTMAP_PROMPT_USERNAME "ipaCertMapPromptUserName" -+ -+#define IPA_OC_CERTMAP_RULE "ipaCertMapRule" -+#define IPA_CERTMAP_MAPRULE "ipaCertMapMapRule" -+#define IPA_CERTMAP_MATCHRULE "ipaCertMapMatchRule" -+#define IPA_CERTMAP_PRIORITY "ipaCertMapPriority" -+#define IPA_ENABLED_FLAG "ipaEnabledFlag" -+#define IPA_TRUE_VALUE "TRUE" -+#define IPA_ASSOCIATED_DOMAIN "associatedDomain" -+ -+#define OBJECTCLASS "objectClass" -+ -+#define CERTMAP_FILTER "(|(&("OBJECTCLASS"="IPA_OC_CERTMAP_RULE")" \ -+ "("IPA_ENABLED_FLAG"="IPA_TRUE_VALUE"))" \ -+ "("OBJECTCLASS"="IPA_OC_CERTMAP_CONFIG_OBJECT"))" -+ -+ - struct ipa_subdomains_ctx { - struct be_ctx *be_ctx; - struct ipa_id_ctx *ipa_id_ctx; -@@ -286,6 +304,193 @@ done: - return ret; - } - -+struct priv_sss_debug { -+ int level; -+}; -+ -+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); -+ } -+} -+ -+static errno_t ipa_certmap_parse_results(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domain, -+ struct sdap_options *sdap_opts, -+ size_t count, -+ struct sysdb_attrs **reply, -+ struct certmap_info ***_certmap_list) -+{ -+ struct certmap_info **certmap_list = NULL; -+ struct certmap_info *m; -+ const char *value; -+ const char **values; -+ size_t c; -+ size_t lc = 0; -+ int ret; -+ struct sss_certmap_ctx *certmap_ctx = NULL; -+ const char **ocs = NULL; -+ bool user_name_hint = false; -+ -+ certmap_list = talloc_zero_array(mem_ctx, struct certmap_info *, count + 1); -+ if (certmap_list == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n"); -+ return ENOMEM; -+ } -+ -+ for (c = 0; c < count; c++) { -+ ret = sysdb_attrs_get_string_array(reply[c], SYSDB_OBJECTCLASS, mem_ctx, -+ &ocs); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Missing objectclasses for config objects.\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ if (string_in_list(IPA_OC_CERTMAP_CONFIG_OBJECT, discard_const(ocs), -+ false)) { -+ ret = sysdb_attrs_get_bool(reply[c], IPA_CERTMAP_PROMPT_USERNAME, -+ &user_name_hint); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to read user name hint option, skipping.\n"); -+ } -+ continue; -+ } -+ -+ m = talloc_zero(certmap_list, struct certmap_info); -+ if (m == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sysdb_attrs_get_string(reply[c], IPA_CN, &value); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); -+ goto done; -+ } -+ -+ m->name = talloc_strdup(m, value); -+ if (m->name == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sysdb_attrs_get_string(reply[c], IPA_CERTMAP_MATCHRULE, &value); -+ if (ret == EOK) { -+ m->match_rule = talloc_strdup(m, value); -+ if (m->match_rule == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } else if (ret != ENOENT) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); -+ goto done; -+ } -+ -+ ret = sysdb_attrs_get_string(reply[c], IPA_CERTMAP_MAPRULE, &value); -+ if (ret == EOK) { -+ m->map_rule = talloc_strdup(m, value); -+ if (m->map_rule == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } else if (ret != ENOENT) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); -+ goto done; -+ } -+ -+ ret = sysdb_attrs_get_string_array(reply[c], IPA_ASSOCIATED_DOMAIN, m, -+ &values); -+ if (ret == EOK) { -+ m->domains = values; -+ } else if (ret != ENOENT) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); -+ goto done; -+ } -+ -+ ret = sysdb_attrs_get_uint32_t(reply[c], IPA_CERTMAP_PRIORITY, -+ &m->priority); -+ if (ret != EOK && ret != ENOENT) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); -+ goto done; -+ } else if (ret == ENOENT) { -+ m->priority = SSS_CERTMAP_MIN_PRIO; -+ } -+ -+ certmap_list[lc++] = m; -+ } -+ -+ certmap_list[lc] = NULL; -+ -+ ret = sss_certmap_init(mem_ctx, ext_debug, NULL, &certmap_ctx); -+ if (ret != 0) { -+ 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(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], skipping. " -+ "Please check for typos and if rule syntax is supported.\n", -+ certmap_list[c]->name); -+ goto done; -+ } -+ } -+ -+ ret = sysdb_update_certmap(domain->sysdb, certmap_list, user_name_hint); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_certmap failed"); -+ goto done; -+ } -+ -+ sss_certmap_free_ctx(sdap_opts->certmap_ctx); -+ sdap_opts->certmap_ctx = talloc_steal(sdap_opts, certmap_ctx); -+ -+ if (_certmap_list != NULL) { -+ *_certmap_list = certmap_list; -+ } -+ ret = EOK; -+ -+done: -+ talloc_free(ocs); -+ if (ret != EOK) { -+ sss_certmap_free_ctx(certmap_ctx); -+ talloc_free(certmap_list); -+ } -+ -+ return ret; -+} -+ - static errno_t ipa_subdom_enumerates(struct sss_domain_info *parent, - struct sysdb_attrs *attrs, - bool *_enumerates) -@@ -801,6 +1006,125 @@ static errno_t ipa_subdomains_ranges_recv(struct tevent_req *req) - return EOK; - } - -+#define IPA_CERTMAP_SEARCH_BASE_TEMPLATE "cn=certmap,%s" -+ -+struct ipa_subdomains_certmap_state { -+ struct sss_domain_info *domain; -+ struct sdap_options *sdap_opts; -+}; -+ -+static void ipa_subdomains_certmap_done(struct tevent_req *subreq); -+ -+static struct tevent_req * -+ipa_subdomains_certmap_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct ipa_subdomains_ctx *sd_ctx, -+ struct sdap_handle *sh) -+{ -+ struct ipa_subdomains_certmap_state *state; -+ struct tevent_req *subreq; -+ struct tevent_req *req; -+ errno_t ret; -+ char *ldap_basedn; -+ char *search_base; -+ const char *attrs[] = { OBJECTCLASS, IPA_CN, -+ IPA_CERTMAP_MAPRULE, IPA_CERTMAP_MATCHRULE, -+ IPA_CERTMAP_PRIORITY, IPA_ASSOCIATED_DOMAIN, -+ IPA_CERTMAP_PROMPT_USERNAME, -+ NULL }; -+ -+ req = tevent_req_create(mem_ctx, &state, -+ struct ipa_subdomains_certmap_state); -+ if (req == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); -+ return NULL; -+ } -+ -+ state->domain = sd_ctx->be_ctx->domain; -+ state->sdap_opts = sd_ctx->sdap_id_ctx->opts; -+ -+ ret = domain_to_basedn(state, state->domain->name, &ldap_basedn); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n"); -+ goto immediately; -+ } -+ -+ search_base = talloc_asprintf(state, IPA_CERTMAP_SEARCH_BASE_TEMPLATE, -+ ldap_basedn); -+ if (search_base == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -+ ret = ENOMEM; -+ goto immediately; -+ } -+ -+ subreq = sdap_get_generic_send(state, ev, sd_ctx->sdap_id_ctx->opts, sh, -+ search_base, LDAP_SCOPE_SUBTREE, -+ CERTMAP_FILTER, -+ attrs, NULL, 0, 0, false); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediately; -+ } -+ -+ tevent_req_set_callback(subreq, ipa_subdomains_certmap_done, req); -+ -+ return req; -+ -+immediately: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ -+ return req; -+} -+ -+static void ipa_subdomains_certmap_done(struct tevent_req *subreq) -+{ -+ struct ipa_subdomains_certmap_state *state; -+ struct tevent_req *req; -+ struct sysdb_attrs **reply; -+ size_t reply_count; -+ errno_t ret; -+ -+ req = tevent_req_callback_data(subreq, struct tevent_req); -+ state = tevent_req_data(req, struct ipa_subdomains_certmap_state); -+ -+ ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get data from LDAP [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ ret = ipa_certmap_parse_results(state, state->domain, -+ state->sdap_opts, -+ reply_count, reply, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "Unable to parse certmap results [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+done: -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+static errno_t ipa_subdomains_certmap_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ -+ return EOK; -+} -+ - struct ipa_subdomains_master_state { - struct sss_domain_info *domain; - struct ipa_options *ipa_options; -@@ -1365,6 +1689,7 @@ struct ipa_subdomains_refresh_state { - static errno_t ipa_subdomains_refresh_retry(struct tevent_req *req); - static void ipa_subdomains_refresh_connect_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_ranges_done(struct tevent_req *subreq); -+static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq); -@@ -1487,6 +1812,35 @@ static void ipa_subdomains_refresh_ranges_done(struct tevent_req *subreq) - return; - } - -+ subreq = ipa_subdomains_certmap_send(state, state->ev, state->sd_ctx, -+ sdap_id_op_handle(state->sdap_op)); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ -+ tevent_req_set_callback(subreq, ipa_subdomains_refresh_certmap_done, req); -+ return; -+} -+ -+static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq) -+{ -+ struct ipa_subdomains_refresh_state *state; -+ struct tevent_req *req; -+ errno_t ret; -+ -+ req = tevent_req_callback_data(subreq, struct tevent_req); -+ state = tevent_req_data(req, struct ipa_subdomains_refresh_state); -+ -+ ret = ipa_subdomains_certmap_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to read certificate mapping rules " -+ "[%d]: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ - subreq = ipa_subdomains_master_send(state, state->ev, state->sd_ctx, - sdap_id_op_handle(state->sdap_op)); - if (subreq == NULL) { -diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c -index 1af8676c5a9c49121d0f0118a46796c6637f04f9..ae3baf036e4278fb67d86b42742fb7e80b46724e 100644 ---- a/src/providers/ipa/ipa_subdomains_server.c -+++ b/src/providers/ipa/ipa_subdomains_server.c -@@ -362,6 +362,10 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, - ad_id_ctx->sdap_id_ctx->opts->idmap_ctx = - id_ctx->sdap_id_ctx->opts->idmap_ctx; - -+ /* Set up the certificate mapping context */ -+ ad_id_ctx->sdap_id_ctx->opts->certmap_ctx = -+ id_ctx->sdap_id_ctx->opts->certmap_ctx; -+ - *_ad_id_ctx = ad_id_ctx; - return EOK; - } -diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c -index 8e60769d09383ac8ebe33e5f64fd4fd9788e82cd..0bee0ca8d71abece6749fdb8393b9ceacb64417d 100644 ---- a/src/providers/ldap/ldap_id.c -+++ b/src/providers/ldap/ldap_id.c -@@ -247,7 +247,9 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - } - - ret = sss_cert_derb64_to_ldap_filter(state, filter_value, attr_name, -- NULL, NULL, &user_filter); -+ ctx->opts->certmap_ctx, -+ state->domain, -+ &user_filter); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "sss_cert_derb64_to_ldap_filter failed.\n"); -diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h -index 6079a8bf62d0bdf23c8d462dc0f19c705e391a6e..afdc01948eefe9dda943c8c7ad01a42dd76a1da8 100644 ---- a/src/providers/ldap/sdap.h -+++ b/src/providers/ldap/sdap.h -@@ -25,6 +25,7 @@ - #include "providers/backend.h" - #include - #include "util/sss_ldap.h" -+#include "lib/certmap/sss_certmap.h" - - struct sdap_msg { - struct sdap_msg *next; -@@ -478,6 +479,9 @@ struct sdap_options { - - bool support_matching_rule; - enum dc_functional_level dc_functional_level; -+ -+ /* Certificate mapping support */ -+ struct sss_certmap_ctx *certmap_ctx; - }; - - struct sdap_server_opts { --- -2.9.3 - diff --git a/SOURCES/0011-MAN-GPO-Security-Filtering-limitation.patch b/SOURCES/0011-MAN-GPO-Security-Filtering-limitation.patch new file mode 100644 index 0000000..880f661 --- /dev/null +++ b/SOURCES/0011-MAN-GPO-Security-Filtering-limitation.patch @@ -0,0 +1,41 @@ +From 314c3a0efc276b74f7a2e39da4db29d8fbf43b12 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Thu, 26 Oct 2017 17:12:17 +0200 +Subject: [PATCH 11/21] MAN: GPO Security Filtering limitation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Note in the man pages that current version of SSSD does not support +host entries in the 'Security filtering' list. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3444 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 6c1661d2f4e860d1b547d6188a4fe2bd564e87cf) +--- + src/man/sssd-ad.5.xml | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index 08c1dd09fb829c6cffb416250b9b518668ec5790..649042d587de3d3600fff59866681e302c721af8 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -346,6 +346,13 @@ DOM:dom1:(memberOf:1.2.840.113556.1.4.1941:=cn=nestedgroup,ou=groups,dc=example, + host. + + ++ NOTE: The current version of SSSD does not support ++ host (computer) entries in the GPO 'Security ++ Filtering' list. Only user and group entries are ++ supported. Host entries in the list have no ++ effect. ++ ++ + NOTE: If the operation mode is set to enforcing, it + is possible that users that were previously allowed + logon access will now be denied logon access (as +-- +2.13.5 + diff --git a/SOURCES/0012-nss-idmap-add-sss_nss_getlistbycert.patch b/SOURCES/0012-nss-idmap-add-sss_nss_getlistbycert.patch deleted file mode 100644 index f879ce1..0000000 --- a/SOURCES/0012-nss-idmap-add-sss_nss_getlistbycert.patch +++ /dev/null @@ -1,736 +0,0 @@ -From f2a81a22124e93a026ec0f06b77eab50998ecba5 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 15 Mar 2017 14:21:26 +0100 -Subject: [PATCH 12/15] nss-idmap: add sss_nss_getlistbycert() - -This patch adds a getlistbycert() call to libsss_nss_idmap to make it on -par with InfoPipe. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek ---- - Makefile.am | 2 +- - src/python/pysss_nss_idmap.c | 103 ++++++++++++++++++- - src/responder/nss/nss_cmd.c | 7 ++ - src/responder/nss/nss_protocol.h | 6 ++ - src/responder/nss/nss_protocol_sid.c | 63 ++++++++++++ - src/sss_client/idmap/sss_nss_idmap.c | 110 +++++++++++++++++++- - src/sss_client/idmap/sss_nss_idmap.exports | 6 ++ - src/sss_client/idmap/sss_nss_idmap.h | 17 +++- - src/sss_client/sss_cli.h | 5 + - src/tests/cmocka/test_nss_srv.c | 158 +++++++++++++++++++++++++++++ - 10 files changed, 471 insertions(+), 6 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index bd0ca0d303e1742ad26c7648cd24e2c0135af34e..7516338bc6fd95045d20db8155a0c82fd7003358 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -1128,7 +1128,7 @@ libsss_nss_idmap_la_LIBADD = \ - $(CLIENT_LIBS) - libsss_nss_idmap_la_LDFLAGS = \ - -Wl,--version-script,$(srcdir)/src/sss_client/idmap/sss_nss_idmap.exports \ -- -version-info 2:0:2 -+ -version-info 3:0:3 - - dist_noinst_DATA += src/sss_client/idmap/sss_nss_idmap.exports - -diff --git a/src/python/pysss_nss_idmap.c b/src/python/pysss_nss_idmap.c -index c57cc10a86a7a9a22a791c1eae027a1aafa8f780..2e5851c7a6e48629fd93e428aada499fcbe36ebb 100644 ---- a/src/python/pysss_nss_idmap.c -+++ b/src/python/pysss_nss_idmap.c -@@ -36,9 +36,37 @@ enum lookup_type { - SIDBYID, - NAMEBYSID, - IDBYSID, -- NAMEBYCERT -+ NAMEBYCERT, -+ LISTBYCERT - }; - -+static int add_dict_to_list(PyObject *py_list, PyObject *res_type, -+ PyObject *res, PyObject *id_type) -+{ -+ int ret; -+ PyObject *py_dict; -+ -+ py_dict = PyDict_New(); -+ if (py_dict == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = PyDict_SetItem(py_dict, res_type, res); -+ if (ret != 0) { -+ Py_XDECREF(py_dict); -+ return ret; -+ } -+ -+ ret = PyDict_SetItem(py_dict, PyBytes_FromString(SSS_TYPE_KEY), id_type); -+ if (ret != 0) { -+ Py_XDECREF(py_dict); -+ return ret; -+ } -+ -+ ret = PyList_Append(py_list, py_dict); -+ -+ return ret; -+} - static int add_dict(PyObject *py_result, PyObject *key, PyObject *res_type, - PyObject *res, PyObject *id_type) - { -@@ -191,6 +219,57 @@ static int do_getnamebycert(PyObject *py_result, PyObject *py_cert) - return ret; - } - -+static int do_getlistbycert(PyObject *py_result, PyObject *py_cert) -+{ -+ int ret; -+ const char *cert; -+ char **names = NULL; -+ enum sss_id_type *id_types = NULL; -+ size_t c; -+ -+ cert = py_string_or_unicode_as_string(py_cert); -+ if (cert == NULL) { -+ return EINVAL; -+ } -+ -+ ret = sss_nss_getlistbycert(cert, &names, &id_types); -+ if (ret == 0) { -+ -+ PyObject *py_list; -+ -+ py_list = PyList_New(0); -+ if (py_list == NULL) { -+ return ENOMEM; -+ } -+ -+ for (c = 0; names[c] != NULL; c++) { -+ ret = add_dict_to_list(py_list, -+ PyBytes_FromString(SSS_NAME_KEY), -+ PyUnicode_FromString(names[c]), -+ PYNUMBER_FROMLONG(id_types[c])); -+ if (ret != 0) { -+ goto done; -+ } -+ } -+ ret = PyDict_SetItem(py_result, py_cert, py_list); -+ if (ret != 0) { -+ goto done; -+ } -+ } -+ -+done: -+ free(id_types); -+ if (names != NULL) { -+ for (c = 0; names[c] != NULL; c++) { -+ free(names[c]); -+ } -+ free(names); -+ } -+ -+ return ret; -+} -+ -+ - static int do_getidbysid(PyObject *py_result, PyObject *py_sid) - { - const char *sid; -@@ -231,6 +310,9 @@ static int do_lookup(enum lookup_type type, PyObject *py_result, - case NAMEBYCERT: - return do_getnamebycert(py_result, py_inp); - break; -+ case LISTBYCERT: -+ return do_getlistbycert(py_result, py_inp); -+ break; - default: - return ENOSYS; - } -@@ -368,7 +450,7 @@ static PyObject * py_getidbysid(PyObject *module, PyObject *args) - } - - PyDoc_STRVAR(getnamebycert_doc, --"getnamebycert(sid or list/tuple of certificates) -> dict(sid => dict(results))\n\ -+"getnamebycert(certificate or list/tuple of certificates) -> dict(certificate => dict(results))\n\ - \n\ - Returns a dictionary with a dictonary of results for each given certificates.\n\ - The result dictonary contain the name and the type of the object which can be\n\ -@@ -382,6 +464,21 @@ static PyObject * py_getnamebycert(PyObject *module, PyObject *args) - return check_args(NAMEBYCERT, args); - } - -+PyDoc_STRVAR(getlistbycert_doc, -+"getnamebycert(certificate or list/tuple of certificates) -> dict(certificate => dict(results))\n\ -+\n\ -+Returns a dictionary with a dictonary of results for each given certificates.\n\ -+The result dictonary contain the name and the type of the object which can be\n\ -+accessed with the key constants NAME_KEY and TYPE_KEY, respectively.\n\ -+\n\ -+NOTE: getlistbycert currently works only with id_provider set as \"ad\" or \"ipa\"" -+); -+ -+static PyObject * py_getlistbycert(PyObject *module, PyObject *args) -+{ -+ return check_args(LISTBYCERT, args); -+} -+ - static PyMethodDef methods[] = { - { sss_py_const_p(char, "getsidbyname"), (PyCFunction) py_getsidbyname, - METH_VARARGS, getsidbyname_doc }, -@@ -393,6 +490,8 @@ static PyMethodDef methods[] = { - METH_VARARGS, getidbysid_doc }, - { sss_py_const_p(char, "getnamebycert"), (PyCFunction) py_getnamebycert, - METH_VARARGS, getnamebycert_doc }, -+ { sss_py_const_p(char, "getlistbycert"), (PyCFunction) py_getlistbycert, -+ METH_VARARGS, getlistbycert_doc }, - { NULL,NULL, 0, NULL } - }; - -diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c -index 08b3d32f2662efc1cc803f6e9e5f2d064f7d3033..1931bf62a686c7f30852dac547866609cf54a81b 100644 ---- a/src/responder/nss/nss_cmd.c -+++ b/src/responder/nss/nss_cmd.c -@@ -932,6 +932,12 @@ static errno_t nss_cmd_getnamebycert(struct cli_ctx *cli_ctx) - nss_protocol_fill_single_name); - } - -+static errno_t nss_cmd_getlistbycert(struct cli_ctx *cli_ctx) -+{ -+ return nss_getby_cert(cli_ctx, CACHE_REQ_USER_BY_CERT, -+ nss_protocol_fill_name_list); -+} -+ - struct sss_cmd_table *get_nss_cmds(void) - { - static struct sss_cmd_table nss_cmds[] = { -@@ -961,6 +967,7 @@ struct sss_cmd_table *get_nss_cmds(void) - { SSS_NSS_GETIDBYSID, nss_cmd_getidbysid }, - { SSS_NSS_GETORIGBYNAME, nss_cmd_getorigbyname }, - { SSS_NSS_GETNAMEBYCERT, nss_cmd_getnamebycert }, -+ { SSS_NSS_GETLISTBYCERT, nss_cmd_getlistbycert }, - { SSS_CLI_NULL, NULL } - }; - -diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h -index c94e7b911eb3c0f97b8c06b1766573311cde41ae..e4c0e52c0e642e885ef2c8423ea564beff7242cf 100644 ---- a/src/responder/nss/nss_protocol.h -+++ b/src/responder/nss/nss_protocol.h -@@ -175,6 +175,12 @@ nss_protocol_fill_single_name(struct nss_ctx *nss_ctx, - struct cache_req_result *result); - - errno_t -+nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, -+ struct nss_cmd_ctx *cmd_ctx, -+ struct sss_packet *packet, -+ struct cache_req_result *result); -+ -+errno_t - nss_protocol_fill_id(struct nss_ctx *nss_ctx, - struct nss_cmd_ctx *cmd_ctx, - struct sss_packet *packet, -diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c -index 0b97e65f75412d40832d861568d8e2f9de5e1732..a6a4e27d039c67ef98f6d5900d5e3fcadb3ee717 100644 ---- a/src/responder/nss/nss_protocol_sid.c -+++ b/src/responder/nss/nss_protocol_sid.c -@@ -498,3 +498,66 @@ nss_protocol_fill_id(struct nss_ctx *nss_ctx, - - return EOK; - } -+ -+errno_t -+nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, -+ struct nss_cmd_ctx *cmd_ctx, -+ struct sss_packet *packet, -+ struct cache_req_result *result) -+{ -+ enum sss_id_type *id_types; -+ size_t rp = 0; -+ size_t body_len; -+ uint8_t *body; -+ errno_t ret; -+ struct sized_string *sz_names; -+ size_t len; -+ size_t c; -+ const char *tmp_str; -+ -+ sz_names = talloc_array(cmd_ctx, struct sized_string, result->count); -+ if (sz_names == NULL) { -+ return ENOMEM; -+ } -+ -+ id_types = talloc_array(cmd_ctx, enum sss_id_type, result->count); -+ if (id_types == NULL) { -+ return ENOMEM; -+ } -+ -+ len = 0; -+ for (c = 0; c < result->count; c++) { -+ ret = nss_get_id_type(cmd_ctx, result, &(id_types[c])); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ tmp_str = nss_get_name_from_msg(result->domain, result->msgs[c]); -+ if (tmp_str == NULL) { -+ return EINVAL; -+ } -+ to_sized_string(&(sz_names[c]), tmp_str); -+ -+ len += sz_names[c].len; -+ } -+ -+ len += (2 + result->count) * sizeof(uint32_t); -+ -+ ret = sss_packet_grow(packet, len); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n"); -+ return ret; -+ } -+ -+ sss_packet_get_body(packet, &body, &body_len); -+ -+ SAFEALIGN_SET_UINT32(&body[rp], result->count, &rp); /* Num results. */ -+ SAFEALIGN_SET_UINT32(&body[rp], 0, &rp); /* Reserved. */ -+ for (c = 0; c < result->count; c++) { -+ SAFEALIGN_SET_UINT32(&body[rp], id_types[c], &rp); -+ SAFEALIGN_SET_STRING(&body[rp], sz_names[c].str, sz_names[c].len, -+ &rp); -+ } -+ -+ return EOK; -+} -diff --git a/src/sss_client/idmap/sss_nss_idmap.c b/src/sss_client/idmap/sss_nss_idmap.c -index fa5a499e3606f7e45a406de4d63002ba35365cb1..6f3af267a1e763e7dce77e3862be377ae2bfe984 100644 ---- a/src/sss_client/idmap/sss_nss_idmap.c -+++ b/src/sss_client/idmap/sss_nss_idmap.c -@@ -31,6 +31,7 @@ - #include "util/strtonum.h" - - #define DATA_START (3 * sizeof(uint32_t)) -+#define LIST_START (2 * sizeof(uint32_t)) - union input { - const char *str; - uint32_t id; -@@ -38,10 +39,12 @@ union input { - - struct output { - enum sss_id_type type; -+ enum sss_id_type *types; - union { - char *str; - uint32_t id; - struct sss_nss_kv *kv_list; -+ char **names; - } d; - }; - -@@ -72,6 +75,63 @@ void sss_nss_free_kv(struct sss_nss_kv *kv_list) - } - } - -+void sss_nss_free_list(char **l) -+{ -+ size_t c; -+ -+ if (l != NULL) { -+ for (c = 0; l[c] != NULL; c++) { -+ free(l[c]); -+ } -+ free(l); -+ } -+} -+ -+static int buf_to_name_type_list(uint8_t *buf, size_t buf_len, uint32_t num, -+ char ***names, enum sss_id_type **types) -+{ -+ int ret; -+ size_t c; -+ char **n = NULL; -+ enum sss_id_type *t = NULL; -+ size_t rp = 0; -+ -+ n = calloc(num + 1, sizeof(char *)); -+ if (n == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ t = calloc(num + 1, sizeof(enum sss_id_type)); -+ if (t == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ for (c = 0; c < num; c++) { -+ SAFEALIGN_COPY_UINT32(&(t[c]), buf + rp, &rp); -+ n[c] = strdup((char *) buf + rp); -+ if (n[c] == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ rp += strlen(n[c]) + 1; -+ } -+ -+ ret = EOK; -+ -+done: -+ if (ret != EOK) { -+ sss_nss_free_list(n); -+ free(t); -+ } else { -+ *names = n; -+ *types = t; -+ } -+ -+ return ret; -+} -+ - static int buf_to_kv_list(uint8_t *buf, size_t buf_len, - struct sss_nss_kv **kv_list) - { -@@ -153,13 +213,14 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , - size_t data_len; - uint32_t c; - struct sss_nss_kv *kv_list; -+ char **names; -+ enum sss_id_type *types; - - switch (cmd) { - case SSS_NSS_GETSIDBYNAME: - case SSS_NSS_GETNAMEBYSID: - case SSS_NSS_GETIDBYSID: - case SSS_NSS_GETORIGBYNAME: -- case SSS_NSS_GETNAMEBYCERT: - ret = sss_strnlen(inp.str, 2048, &inp_len); - if (ret != EOK) { - return EINVAL; -@@ -169,6 +230,17 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , - rd.data = inp.str; - - break; -+ case SSS_NSS_GETNAMEBYCERT: -+ case SSS_NSS_GETLISTBYCERT: -+ ret = sss_strnlen(inp.str, 10 * 1024 , &inp_len); -+ if (ret != EOK) { -+ return EINVAL; -+ } -+ -+ rd.len = inp_len + 1; -+ rd.data = inp.str; -+ -+ break; - case SSS_NSS_GETSIDBYID: - rd.len = sizeof(uint32_t); - rd.data = &inp.id; -@@ -195,7 +267,7 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , - if (num_results == 0) { - ret = ENOENT; - goto done; -- } else if (num_results > 1) { -+ } else if (num_results > 1 && cmd != SSS_NSS_GETLISTBYCERT) { - ret = EBADMSG; - goto done; - } -@@ -237,6 +309,18 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , - out->d.id = c; - - break; -+ case SSS_NSS_GETLISTBYCERT: -+ ret = buf_to_name_type_list(repbuf + LIST_START, replen - LIST_START, -+ num_results, -+ &names, &types); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ out->types = types; -+ out->d.names = names; -+ -+ break; - case SSS_NSS_GETORIGBYNAME: - ret = buf_to_kv_list(repbuf + DATA_START, data_len, &kv_list); - if (ret != EOK) { -@@ -392,3 +476,25 @@ int sss_nss_getnamebycert(const char *cert, char **fq_name, - - return ret; - } -+ -+int sss_nss_getlistbycert(const char *cert, char ***fq_name, -+ enum sss_id_type **type) -+{ -+ int ret; -+ union input inp; -+ struct output out; -+ -+ if (fq_name == NULL || cert == NULL || *cert == '\0') { -+ return EINVAL; -+ } -+ -+ inp.str = cert; -+ -+ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETLISTBYCERT, &out); -+ if (ret == EOK) { -+ *fq_name = out.d.names; -+ *type = out.types; -+ } -+ -+ return ret; -+} -diff --git a/src/sss_client/idmap/sss_nss_idmap.exports b/src/sss_client/idmap/sss_nss_idmap.exports -index bd5d80212017d38334c3cdeefa47d6029f42aebb..49dac6fc9351b0ca98cd46e83b85ec8ef0075a0d 100644 ---- a/src/sss_client/idmap/sss_nss_idmap.exports -+++ b/src/sss_client/idmap/sss_nss_idmap.exports -@@ -25,3 +25,9 @@ SSS_NSS_IDMAP_0.2.0 { - global: - sss_nss_getnamebycert; - } SSS_NSS_IDMAP_0.1.0; -+ -+SSS_NSS_IDMAP_0.3.0 { -+ # public functions -+ global: -+ sss_nss_getlistbycert; -+} SSS_NSS_IDMAP_0.2.0; -diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h -index 8a6299194e7b91e084b26c0c96e2f93875a832e7..cbf19479ff9ec6e0d6e07e1f7e48a1571e147740 100644 ---- a/src/sss_client/idmap/sss_nss_idmap.h -+++ b/src/sss_client/idmap/sss_nss_idmap.h -@@ -130,7 +130,7 @@ int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list, - * @param[in] cert base64 encoded certificate - * @param[out] fq_name Fully qualified name of a user or a group, - * must be freed by the caller -- * @param[out] type Type of the object related to the SID -+ * @param[out] type Type of the object related to the cert - * - * @return - * - see #sss_nss_getsidbyname -@@ -139,6 +139,21 @@ int sss_nss_getnamebycert(const char *cert, char **fq_name, - enum sss_id_type *type); - - /** -+ * @brief Return a list of fully qualified names for the given base64 encoded -+ * X.509 certificate in DER format -+ * -+ * @param[in] cert base64 encoded certificate -+ * @param[out] fq_name List of fully qualified name of users or groups, -+ * must be freed by the caller -+ * @param[out] type List of types of the objects related to the cert -+ * -+ * @return -+ * - see #sss_nss_getsidbyname -+ */ -+int sss_nss_getlistbycert(const char *cert, char ***fq_name, -+ enum sss_id_type **type); -+ -+/** - * @brief Free key-value list returned by sss_nss_getorigbyname() - * - * @param[in] kv_list Key-value list returned by sss_nss_getorigbyname(). -diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h -index 8091e11515184dc9b7f32eed535055d9eee3143f..59fee7a4eceb2c185e156e812af7f2f4c6b2a0dd 100644 ---- a/src/sss_client/sss_cli.h -+++ b/src/sss_client/sss_cli.h -@@ -260,6 +260,11 @@ SSS_NSS_GETNAMEBYCERT = 0x0116, /**< Takes the zero terminated string - of a X509 certificate and returns the zero - terminated fully qualified name of the - related object. */ -+SSS_NSS_GETLISTBYCERT = 0x0117, /**< Takes the zero terminated string -+ of the base64 encoded DER representation -+ of a X509 certificate and returns a list -+ of zero terminated fully qualified names -+ of the related objects. */ - }; - - /** -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 76b9c6fb05673130de0957e93291919c263a28f3..50714715cc80338640f2a77ecbe17bd5e0d6e911 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -3454,6 +3454,16 @@ struct passwd testbycert = { - .pw_passwd = discard_const("*"), - }; - -+struct passwd testbycert2 = { -+ .pw_name = discard_const("testcertuser2"), -+ .pw_uid = 23457, -+ .pw_gid = 6890, -+ .pw_dir = discard_const("/home/testcertuser2"), -+ .pw_gecos = discard_const("test cert user2"), -+ .pw_shell = discard_const("/bin/sh"), -+ .pw_passwd = discard_const("*"), -+}; -+ - #define TEST_TOKEN_CERT \ - "MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ - "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA2MjMx" \ -@@ -3495,6 +3505,57 @@ static int test_nss_getnamebycert_check(uint32_t status, uint8_t *body, size_t b - return EOK; - } - -+static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t blen) -+{ -+ size_t rp = 0; -+ uint32_t id_type; -+ uint32_t num; -+ uint32_t reserved; -+ const char *name; -+ int found = 0; -+ const char *fq_name1 = "testcertuser@"TEST_DOM_NAME ; -+ const char *fq_name2 = "testcertuser2@"TEST_DOM_NAME; -+ -+ assert_int_equal(status, EOK); -+ -+ /* num_results and reserved */ -+ SAFEALIGN_COPY_UINT32(&num, body + rp, &rp); -+ assert_in_range(num, 1, 2); -+ SAFEALIGN_COPY_UINT32(&reserved, body + rp, &rp); -+ assert_int_equal(reserved, 0); -+ -+ SAFEALIGN_COPY_UINT32(&id_type, body + rp, &rp); -+ assert_int_equal(id_type, SSS_ID_TYPE_UID); -+ -+ name = (const char *)body + rp; -+ if (num == 1) { -+ assert_string_equal(name, fq_name1); -+ return EOK; -+ } -+ -+ rp += strlen(name) + 1; -+ if (strcmp(name, fq_name1) == 0) { -+ found = 1; -+ } else if (strcmp(name, fq_name2) == 0) { -+ found = 2; -+ } -+ assert_in_range(found, 1, 2); -+ -+ SAFEALIGN_COPY_UINT32(&id_type, body + rp, &rp); -+ assert_int_equal(id_type, SSS_ID_TYPE_UID); -+ -+ name = (const char *)body + rp; -+ if (found == 1) { -+ assert_string_equal(name, fq_name2); -+ } else { -+ assert_string_equal(name, fq_name1); -+ } -+ -+ -+ return EOK; -+} -+ -+ - static void test_nss_getnamebycert(void **state) - { - errno_t ret; -@@ -3572,6 +3633,99 @@ void test_nss_getnamebycert_neg(void **state) - assert_int_equal(nss_test_ctx->ncache_hits, 1); - } - -+static void test_nss_getlistbycert(void **state) -+{ -+ errno_t ret; -+ struct sysdb_attrs *attrs; -+ unsigned char *der = NULL; -+ size_t der_size; -+ -+ attrs = sysdb_new_attrs(nss_test_ctx); -+ assert_non_null(attrs); -+ -+ der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size); -+ assert_non_null(der); -+ -+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); -+ talloc_free(der); -+ assert_int_equal(ret, EOK); -+ -+ /* Prime the cache with a valid user */ -+ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, -+ &testbycert, attrs, 0); -+ assert_int_equal(ret, EOK); -+ talloc_free(attrs); -+ -+ mock_input_cert(TEST_TOKEN_CERT); -+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETLISTBYCERT); -+ mock_fill_bysid(); -+ -+ /* Query for that user, call a callback when command finishes */ -+ /* Should go straight to back end, without contacting DP. */ -+ /* If there is only a single user mapped the result will look like the */ -+ /* result of getnamebycert. */ -+ set_cmd_cb(test_nss_getlistbycert_check); -+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT, -+ nss_test_ctx->nss_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(nss_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ -+static void test_nss_getlistbycert_multi(void **state) -+{ -+ errno_t ret; -+ struct sysdb_attrs *attrs; -+ unsigned char *der = NULL; -+ size_t der_size; -+ -+ der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size); -+ assert_non_null(der); -+ -+ attrs = sysdb_new_attrs(nss_test_ctx); -+ assert_non_null(attrs); -+ -+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); -+ assert_int_equal(ret, EOK); -+ -+ /* Prime the cache with two valid user */ -+ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, -+ &testbycert, attrs, 0); -+ assert_int_equal(ret, EOK); -+ talloc_free(attrs); -+ -+ /* Looks like attrs is modified during store_user() makes sure we start -+ * with fresh data. */ -+ attrs = sysdb_new_attrs(nss_test_ctx); -+ assert_non_null(attrs); -+ -+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); -+ talloc_free(der); -+ assert_int_equal(ret, EOK); -+ -+ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, -+ &testbycert2, attrs, 0); -+ assert_int_equal(ret, EOK); -+ talloc_free(attrs); -+ -+ mock_input_cert(TEST_TOKEN_CERT); -+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETLISTBYCERT); -+ mock_fill_bysid(); -+ -+ /* Query for that user, call a callback when command finishes */ -+ /* Should go straight to back end, without contacting DP */ -+ set_cmd_cb(test_nss_getlistbycert_check); -+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT, -+ nss_test_ctx->nss_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(nss_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ - struct passwd sid_user = { - .pw_name = discard_const("testusersid"), - .pw_uid = 1234, -@@ -3818,6 +3972,10 @@ int main(int argc, const char *argv[]) - nss_test_setup, nss_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getnamebycert, - nss_test_setup, nss_test_teardown), -+ cmocka_unit_test_setup_teardown(test_nss_getlistbycert, -+ nss_test_setup, nss_test_teardown), -+ cmocka_unit_test_setup_teardown(test_nss_getlistbycert_multi, -+ nss_test_setup, nss_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getsidbyname, - nss_test_setup, nss_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getsidbyupn, --- -2.9.3 - diff --git a/SOURCES/0012-sudo-always-use-srv_opts-from-id-context.patch b/SOURCES/0012-sudo-always-use-srv_opts-from-id-context.patch new file mode 100644 index 0000000..8c782f9 --- /dev/null +++ b/SOURCES/0012-sudo-always-use-srv_opts-from-id-context.patch @@ -0,0 +1,64 @@ +From 7738a74e6878536e155d9d589e7ec727c135f5a0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 19 Oct 2017 10:39:21 +0200 +Subject: [PATCH 12/21] sudo: always use srv_opts from id context + +Prior this patch, we remember id_ctx->srv_opts in sudo request to switch +the latest usn values. This works fine most of the time but it may cause +a crash. + +If we have two concurrent sudo refresh and one of these fails, it causes +failover to try the next server and possibly replacing the old srv_opts +with new one and it causes an access after free in the other refresh. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3562 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 2ee201dcf6bbe52abbbed3c2fc4c35ca2e0c8a43) +--- + src/providers/ldap/sdap_async_sudo.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c +index 3c69837fda313b2645c3a8497252670312f600ea..88a387422d5c9ae86cea583bb38dadf90cba37f3 100644 +--- a/src/providers/ldap/sdap_async_sudo.c ++++ b/src/providers/ldap/sdap_async_sudo.c +@@ -279,7 +279,6 @@ done: + struct sdap_sudo_refresh_state { + struct sdap_sudo_ctx *sudo_ctx; + struct tevent_context *ev; +- struct sdap_server_opts *srv_opts; + struct sdap_options *opts; + struct sdap_id_op *sdap_op; + struct sysdb_ctx *sysdb; +@@ -405,9 +404,6 @@ static void sdap_sudo_refresh_connect_done(struct tevent_req *subreq) + + DEBUG(SSSDBG_TRACE_FUNC, "SUDO LDAP connection successful\n"); + +- /* Obtain srv_opts here in case of first connection. */ +- state->srv_opts = state->sudo_ctx->id_ctx->srv_opts; +- + /* Renew host information if needed. */ + if (state->sudo_ctx->run_hostinfo) { + subreq = sdap_sudo_get_hostinfo_send(state, state->opts, +@@ -586,7 +582,6 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq) + goto done; + } + +- + /* start transaction */ + ret = sysdb_transaction_start(state->sysdb); + if (ret != EOK) { +@@ -621,7 +616,7 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq) + /* remember new usn */ + ret = sysdb_get_highest_usn(state, rules, rules_count, &usn); + if (ret == EOK) { +- sdap_sudo_set_usn(state->srv_opts, usn); ++ sdap_sudo_set_usn(state->sudo_ctx->id_ctx->srv_opts, usn); + } else { + DEBUG(SSSDBG_MINOR_FAILURE, "Unable to get highest USN [%d]: %s\n", + ret, sss_strerror(ret)); +-- +2.13.5 + diff --git a/SOURCES/0013-AD-Remember-last-site-discovered.patch b/SOURCES/0013-AD-Remember-last-site-discovered.patch new file mode 100644 index 0000000..f1ad8c2 --- /dev/null +++ b/SOURCES/0013-AD-Remember-last-site-discovered.patch @@ -0,0 +1,109 @@ +From 020d7f12f7c57e3a5c8f844de2b2d0cad020e662 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 18 Oct 2017 15:20:34 +0200 +Subject: [PATCH 13/21] AD: Remember last site discovered + +To discover Active Directory site for a client we must first contact any +directory controller for an LDAP ping. This is done by searching +domain-wide DNS tree which may however contain servers that are not +reachable from current site and than we face long timeouts or failure. + +This patch makes sssd remember the last successfuly discovered site +and use this for DNS search to lookup a site and forest again similar +to what we do when ad_site option is set. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3265 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit f54d202db528207d7794870aabef0656b20369f1) +--- + src/providers/ad/ad_srv.c | 44 +++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 43 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c +index ff01ee95c4d2c6875a989394489f1a0495cc3003..be1ba0f237add894566ae713ce5e29fd202d414c 100644 +--- a/src/providers/ad/ad_srv.c ++++ b/src/providers/ad/ad_srv.c +@@ -481,6 +481,7 @@ struct ad_srv_plugin_ctx { + const char *hostname; + const char *ad_domain; + const char *ad_site_override; ++ const char *current_site; + }; + + struct ad_srv_plugin_ctx * +@@ -518,6 +519,11 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, + if (ctx->ad_site_override == NULL) { + goto fail; + } ++ ++ ctx->current_site = talloc_strdup(ctx, ad_site_override); ++ if (ctx->current_site == NULL) { ++ goto fail; ++ } + } + + return ctx; +@@ -527,6 +533,32 @@ fail: + return NULL; + } + ++static errno_t ++ad_srv_plugin_ctx_switch_site(struct ad_srv_plugin_ctx *ctx, ++ const char *new_site) ++{ ++ const char *site; ++ errno_t ret; ++ ++ if (new_site == NULL) { ++ return EOK; ++ } ++ ++ if (ctx->current_site != NULL && strcmp(ctx->current_site, new_site) == 0) { ++ return EOK; ++ } ++ ++ site = talloc_strdup(ctx, new_site); ++ if (site == NULL) { ++ return ENOMEM; ++ } ++ ++ talloc_zfree(ctx->current_site); ++ ctx->current_site = site; ++ ++ return EOK; ++} ++ + struct ad_srv_plugin_state { + struct tevent_context *ev; + struct ad_srv_plugin_ctx *ctx; +@@ -613,7 +645,7 @@ struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx, + + subreq = ad_get_dc_servers_send(state, ev, ctx->be_res->resolv, + state->discovery_domain, +- state->ctx->ad_site_override); ++ state->ctx->current_site); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; +@@ -709,6 +741,16 @@ static void ad_srv_plugin_site_done(struct tevent_req *subreq) + backup_domain = NULL; + + if (ret == EOK) { ++ /* Remember current site so it can be used during next lookup so ++ * we can contact directory controllers within a known reachable ++ * site first. */ ++ ret = ad_srv_plugin_ctx_switch_site(state->ctx, state->site); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set site [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ + if (strcmp(state->service, "gc") == 0) { + if (state->forest != NULL) { + if (state->site != NULL) { +-- +2.13.5 + diff --git a/SOURCES/0013-nss-allow-larger-buffer-for-certificate-based-reques.patch b/SOURCES/0013-nss-allow-larger-buffer-for-certificate-based-reques.patch deleted file mode 100644 index d0dea12..0000000 --- a/SOURCES/0013-nss-allow-larger-buffer-for-certificate-based-reques.patch +++ /dev/null @@ -1,70 +0,0 @@ -From e7c9ff18f41d9951aff3c99dca7db1871e53cfaf Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 28 Feb 2017 14:19:53 +0100 -Subject: [PATCH 13/15] nss: allow larger buffer for certificate based requests - -To make sure larger certificates can be processed as well the maximal -buffer size is increased for requests by certificate. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek ---- - src/responder/common/responder_packet.c | 21 ++++++++++++++++++++- - src/responder/common/responder_packet.h | 1 + - 2 files changed, 21 insertions(+), 1 deletion(-) - -diff --git a/src/responder/common/responder_packet.c b/src/responder/common/responder_packet.c -index 4f5e110837eb76609d31a77c62a00e00530ffc90..cc4d66995965cca4c86a80c31d2afd4c9ac3e0e4 100644 ---- a/src/responder/common/responder_packet.c -+++ b/src/responder/common/responder_packet.c -@@ -179,6 +179,8 @@ int sss_packet_recv(struct sss_packet *packet, int fd) - size_t rb; - size_t len; - void *buf; -+ size_t new_len; -+ int ret; - - buf = (uint8_t *)packet->buffer + packet->iop; - if (packet->iop > 4) len = sss_packet_get_len(packet) - packet->iop; -@@ -205,7 +207,24 @@ int sss_packet_recv(struct sss_packet *packet, int fd) - } - - if (sss_packet_get_len(packet) > packet->memsize) { -- return EINVAL; -+ /* Allow certificate based requests to use larger buffer but not -+ * larger than SSS_CERT_PACKET_MAX_RECV_SIZE. Due to the way -+ * sss_packet_grow() works the packet len must be set to '0' first and -+ * then grow to the expected size. */ -+ if ((sss_packet_get_cmd(packet) == SSS_NSS_GETNAMEBYCERT -+ || sss_packet_get_cmd(packet) == SSS_NSS_GETLISTBYCERT) -+ && packet->memsize < SSS_CERT_PACKET_MAX_RECV_SIZE -+ && (new_len = sss_packet_get_len(packet)) -+ < SSS_CERT_PACKET_MAX_RECV_SIZE) { -+ new_len = sss_packet_get_len(packet); -+ sss_packet_set_len(packet, 0); -+ ret = sss_packet_grow(packet, new_len); -+ if (ret != EOK) { -+ return ret; -+ } -+ } else { -+ return EINVAL; -+ } - } - - packet->iop += rb; -diff --git a/src/responder/common/responder_packet.h b/src/responder/common/responder_packet.h -index 3ad0eee28477e446c9e4996617beb55f32923d47..afceb4aaefa40fd86bdfde820c92c09b65cd8702 100644 ---- a/src/responder/common/responder_packet.h -+++ b/src/responder/common/responder_packet.h -@@ -25,6 +25,7 @@ - #include "sss_client/sss_cli.h" - - #define SSS_PACKET_MAX_RECV_SIZE 1024 -+#define SSS_CERT_PACKET_MAX_RECV_SIZE ( 10 * SSS_PACKET_MAX_RECV_SIZE ) - - struct sss_packet; - --- -2.9.3 - diff --git a/SOURCES/0014-IPA-Add-s2n-request-to-string-function.patch b/SOURCES/0014-IPA-Add-s2n-request-to-string-function.patch deleted file mode 100644 index 287bfdf..0000000 --- a/SOURCES/0014-IPA-Add-s2n-request-to-string-function.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 8820b7bba01312419171c4949a9f1c5c8c061a55 Mon Sep 17 00:00:00 2001 -From: Justin Stephenson -Date: Mon, 20 Mar 2017 11:51:05 -0400 -Subject: [PATCH 14/15] IPA: Add s2n request to string function - -Add a function to convert request_types to string allowing the -ability to print request type information for ipa_s2n functions during -IPA client operations. - -Reviewed-by: Sumit Bose ---- - src/providers/ipa/ipa_s2n_exop.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index 07bbb2b4d252c8ca9ada4d890c36c903c9f75773..4fe20689fe4c0f2bb5217691dd05b37d2a1cc820 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -979,6 +979,22 @@ done: - return ret; - } - -+static const char *ipa_s2n_reqtype2str(enum request_types request_type) -+{ -+ switch (request_type) { -+ case REQ_SIMPLE: -+ return "REQ_SIMPLE"; -+ case REQ_FULL: -+ return "REQ_FULL"; -+ case REQ_FULL_WITH_MEMBERS: -+ return "REQ_FULL_WITH_MEMBERS"; -+ default: -+ break; -+ } -+ -+ return "Unknown request type"; -+} -+ - struct ipa_s2n_get_list_state { - struct tevent_context *ev; - struct ipa_id_ctx *ipa_ctx; --- -2.9.3 - diff --git a/SOURCES/0014-sysdb-add-functions-to-get-set-client-site.patch b/SOURCES/0014-sysdb-add-functions-to-get-set-client-site.patch new file mode 100644 index 0000000..7fc6ff1 --- /dev/null +++ b/SOURCES/0014-sysdb-add-functions-to-get-set-client-site.patch @@ -0,0 +1,206 @@ +From fafc90b8c225fd77e30e94d985c72f5f2980e59e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 24 Oct 2017 12:09:39 +0200 +Subject: [PATCH 14/21] sysdb: add functions to get/set client site + +Reviewed-by: Jakub Hrozek +(cherry picked from commit e16539779668dacff868999bd59dbf33e3eab872) +--- + src/db/sysdb.h | 10 +++ + src/db/sysdb_subdomains.c | 108 +++++++++++++++++++++++++++++++ + src/tests/cmocka/test_sysdb_subdomains.c | 28 ++++++++ + 3 files changed, 146 insertions(+) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index fbbe321072385bd43353ef2f7d0e30667887d128..4192f9085d941814eccd2ac60ce8fb6d4e1bfa67 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -154,6 +154,7 @@ + #define SYSDB_SUBDOMAIN_FOREST "memberOfForest" + #define SYSDB_SUBDOMAIN_TRUST_DIRECTION "trustDirection" + #define SYSDB_UPN_SUFFIXES "upnSuffixes" ++#define SYSDB_SITE "site" + + #define SYSDB_BASE_ID "baseID" + #define SYSDB_ID_RANGE_SIZE "idRangeSize" +@@ -509,6 +510,15 @@ errno_t sysdb_domain_update_domain_resolution_order( + const char *domain_name, + const char *domain_resolution_order); + ++errno_t ++sysdb_get_site(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *dom, ++ const char **_site); ++ ++errno_t ++sysdb_set_site(struct sss_domain_info *dom, ++ const char *site); ++ + errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, + const char *name, const char *realm, + const char *flat_name, const char *domain_id, +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index 2789cc4949fb7be9ad272d7613ed18a64fa8a20a..cb5de1afe3e8c9692789c5d2679eb3a4e6e1cdb2 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -1284,3 +1284,111 @@ done: + talloc_free(tmp_ctx); + return ret; + } ++ ++errno_t ++sysdb_get_site(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *dom, ++ const char **_site) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_res *res; ++ struct ldb_dn *dn; ++ const char *attrs[] = { SYSDB_SITE, NULL }; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new_fmt(tmp_ctx, dom->sysdb->ldb, SYSDB_DOM_BASE, dom->name); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_search(dom->sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, ++ attrs, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ if (res->count == 0) { ++ *_site = NULL; ++ ret = EOK; ++ goto done; ++ } else if (res->count != 1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Got more than one reply for base search!\n"); ++ ret = EIO; ++ goto done; ++ } ++ ++ *_site = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SITE, NULL); ++ talloc_steal(mem_ctx, *_site); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++errno_t ++sysdb_set_site(struct sss_domain_info *dom, ++ const char *site) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_message *msg; ++ struct ldb_dn *dn; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new_fmt(tmp_ctx, dom->sysdb->ldb, SYSDB_DOM_BASE, dom->name); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ msg = ldb_msg_new(tmp_ctx); ++ if (msg == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ msg->dn = dn; ++ ++ ret = ldb_msg_add_empty(msg, SYSDB_SITE, LDB_FLAG_MOD_REPLACE, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ if (site != NULL) { ++ ret = ldb_msg_add_string(msg, SYSDB_SITE, site); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ } ++ ++ ret = ldb_modify(dom->sysdb->ldb, msg); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ldb_modify()_failed: [%s][%d][%s]\n", ++ ldb_strerror(ret), ret, ldb_errstring(dom->sysdb->ldb)); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} +diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c +index 84bcdc17b39dbc8822097c2006f157a09ea5e466..f8e3e1d915dba0f3a79adbf5af733980bf23a265 100644 +--- a/src/tests/cmocka/test_sysdb_subdomains.c ++++ b/src/tests/cmocka/test_sysdb_subdomains.c +@@ -513,6 +513,31 @@ static void test_sysdb_link_ad_multidom(void **state) + + } + ++static void test_sysdb_set_and_get_site(void **state) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct subdom_test_ctx *test_ctx = ++ talloc_get_type(*state, struct subdom_test_ctx); ++ const char *site; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ assert_non_null(test_ctx); ++ ++ ret = sysdb_get_site(test_ctx, test_ctx->tctx->dom, &site); ++ assert_int_equal(ret, EOK); ++ assert_null(site); ++ ++ ret = sysdb_set_site(test_ctx->tctx->dom, "TestSite"); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_get_site(tmp_ctx, test_ctx->tctx->dom, &site); ++ assert_int_equal(ret, EOK); ++ assert_string_equal(site, "TestSite"); ++ ++ talloc_free(tmp_ctx); ++} ++ + int main(int argc, const char *argv[]) + { + int rv; +@@ -546,6 +571,9 @@ int main(int argc, const char *argv[]) + cmocka_unit_test_setup_teardown(test_sysdb_link_ad_multidom, + test_sysdb_subdom_setup, + test_sysdb_subdom_teardown), ++ cmocka_unit_test_setup_teardown(test_sysdb_set_and_get_site, ++ test_sysdb_subdom_setup, ++ test_sysdb_subdom_teardown), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +-- +2.13.5 + diff --git a/SOURCES/0015-AD-Remember-last-site-discovered-in-sysdb.patch b/SOURCES/0015-AD-Remember-last-site-discovered-in-sysdb.patch new file mode 100644 index 0000000..9c14628 --- /dev/null +++ b/SOURCES/0015-AD-Remember-last-site-discovered-in-sysdb.patch @@ -0,0 +1,161 @@ +From 1be48c91f3d80b51dc2361217f5c840656e0b088 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 1 Nov 2017 14:57:17 +0100 +Subject: [PATCH 15/21] AD: Remember last site discovered in sysdb + +This can speed up sssd startup. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3265 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit fb0431b13a9fcd8ac31e622503acbd10d2b73ac9) +--- + src/db/sysdb_subdomains.c | 2 +- + src/providers/ad/ad_init.c | 2 +- + src/providers/ad/ad_srv.c | 21 +++++++++++++++++++++ + src/providers/ad/ad_srv.h | 1 + + src/providers/ad/ad_subdomains.c | 2 +- + src/providers/ipa/ipa_subdomains_server.c | 2 +- + 6 files changed, 26 insertions(+), 4 deletions(-) + +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index cb5de1afe3e8c9692789c5d2679eb3a4e6e1cdb2..353561765904efe4bd698c38949a1b290ecf0b80 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -1291,7 +1291,7 @@ sysdb_get_site(TALLOC_CTX *mem_ctx, + const char **_site) + { + TALLOC_CTX *tmp_ctx; +- struct ldb_res *res; ++ struct ldb_result *res; + struct ldb_dn *dn; + const char *attrs[] = { SYSDB_SITE, NULL }; + errno_t ret; +diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c +index 131e960d4c623398506f834742400df9c786b86b..e62025d4acd24844a5c7082d00c597516f35de16 100644 +--- a/src/providers/ad/ad_init.c ++++ b/src/providers/ad/ad_init.c +@@ -199,7 +199,7 @@ static errno_t ad_init_srv_plugin(struct be_ctx *be_ctx, + return EOK; + } + +- srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res, ++ srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res, + default_host_dbs, ad_options->id, + hostname, ad_domain, + ad_site_override); +diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c +index be1ba0f237add894566ae713ce5e29fd202d414c..4fa1668605e131b2e31802b1401f49fc6e00a23b 100644 +--- a/src/providers/ad/ad_srv.c ++++ b/src/providers/ad/ad_srv.c +@@ -34,6 +34,7 @@ + #include "providers/fail_over_srv.h" + #include "providers/ldap/sdap.h" + #include "providers/ldap/sdap_async.h" ++#include "db/sysdb.h" + + #define AD_SITE_DOMAIN_FMT "%s._sites.%s" + +@@ -475,6 +476,7 @@ int ad_get_client_site_recv(TALLOC_CTX *mem_ctx, + } + + struct ad_srv_plugin_ctx { ++ struct be_ctx *be_ctx; + struct be_resolv_ctx *be_res; + enum host_database *host_dbs; + struct sdap_options *opts; +@@ -486,6 +488,7 @@ struct ad_srv_plugin_ctx { + + struct ad_srv_plugin_ctx * + ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, ++ struct be_ctx *be_ctx, + struct be_resolv_ctx *be_res, + enum host_database *host_dbs, + struct sdap_options *opts, +@@ -494,12 +497,14 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, + const char *ad_site_override) + { + struct ad_srv_plugin_ctx *ctx = NULL; ++ errno_t ret; + + ctx = talloc_zero(mem_ctx, struct ad_srv_plugin_ctx); + if (ctx == NULL) { + return NULL; + } + ++ ctx->be_ctx = be_ctx; + ctx->be_res = be_res; + ctx->host_dbs = host_dbs; + ctx->opts = opts; +@@ -524,6 +529,15 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, + if (ctx->current_site == NULL) { + goto fail; + } ++ } else { ++ ret = sysdb_get_site(ctx, be_ctx->domain, &ctx->current_site); ++ if (ret != EOK) { ++ /* Not fatal. */ ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Unable to get current site from cache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ ctx->current_site = NULL; ++ } + } + + return ctx; +@@ -556,6 +570,13 @@ ad_srv_plugin_ctx_switch_site(struct ad_srv_plugin_ctx *ctx, + talloc_zfree(ctx->current_site); + ctx->current_site = site; + ++ ret = sysdb_set_site(ctx->be_ctx->domain, ctx->current_site); ++ if (ret != EOK) { ++ /* Not fatal. */ ++ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to store site information " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ } ++ + return EOK; + } + +diff --git a/src/providers/ad/ad_srv.h b/src/providers/ad/ad_srv.h +index ae5efe44755fa09f74064014cce749e35b1831da..fddef686762e57bb95d648247131d39a797aa516 100644 +--- a/src/providers/ad/ad_srv.h ++++ b/src/providers/ad/ad_srv.h +@@ -25,6 +25,7 @@ struct ad_srv_plugin_ctx; + + struct ad_srv_plugin_ctx * + ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, ++ struct be_ctx *be_ctx, + struct be_resolv_ctx *be_res, + enum host_database *host_dbs, + struct sdap_options *opts, +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 280aa54c23bf61e60d23ea91bd44a39f9f43d155..3fb9b950f171d85817cce35ac92ad7c4974ccb68 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -245,7 +245,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + ad_options->id_ctx = ad_id_ctx; + + /* use AD plugin */ +- srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res, ++ srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res, + default_host_dbs, + ad_id_ctx->ad_options->id, + hostname, +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index 10166d162f746fde176e6c7c2bfbe3906b1bfddc..d670a156b37608d20d49d79131138f02e4abf82b 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -305,7 +305,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, + ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE); + + /* use AD plugin */ +- srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res, ++ srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res, + default_host_dbs, + ad_id_ctx->ad_options->id, + id_ctx->server_mode->hostname, +-- +2.13.5 + diff --git a/SOURCES/0015-IPA-Enhance-debug-logging-for-ipa-s2n-operations.patch b/SOURCES/0015-IPA-Enhance-debug-logging-for-ipa-s2n-operations.patch deleted file mode 100644 index 8031b4c..0000000 --- a/SOURCES/0015-IPA-Enhance-debug-logging-for-ipa-s2n-operations.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 359fe83281f2f54d71da65879eafec5ae383f33f Mon Sep 17 00:00:00 2001 -From: Justin Stephenson -Date: Thu, 16 Mar 2017 14:46:55 -0400 -Subject: [PATCH 15/15] IPA: Enhance debug logging for ipa s2n operations - -Add log messages to provide useful debug logging surrounding -IPA client extended operations to the IPA Server during AD trust -requests to retrieve information. Print more details about the -objects requested and received during the ipa_s2n operations. - -This will improve log analysis and troubleshooting efforts during AD -trust user and group resolution failures on IPA clients, such as missing -groups. - -Reviewed-by: Sumit Bose ---- - src/providers/ipa/ipa_s2n_exop.c | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index 4fe20689fe4c0f2bb5217691dd05b37d2a1cc820..c99312274073858e5e03f3e82c069dafc839eb61 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -1156,6 +1156,13 @@ static errno_t ipa_s2n_get_list_step(struct tevent_req *req) - need_v1 = true; - } - -+ if (state->req_input.type == REQ_INP_NAME -+ && state->req_input.inp.name != NULL) { -+ DEBUG(SSSDBG_TRACE_FUNC, "Sending request_type: [%s] for group [%s].\n", -+ ipa_s2n_reqtype2str(state->request_type), -+ state->list[state->list_idx]); -+ } -+ - subreq = ipa_s2n_exop_send(state, state->ev, state->sh, need_v1, - state->exop_timeout, bv_req); - if (subreq == NULL) { -@@ -1194,6 +1201,9 @@ static void ipa_s2n_get_list_next(struct tevent_req *subreq) - goto fail; - } - -+ DEBUG(SSSDBG_TRACE_FUNC, "Received [%s] attributes from IPA server.\n", -+ state->attrs->a.name); -+ - if (is_default_view(state->ipa_ctx->view_name)) { - ret = ipa_s2n_get_list_save_step(req); - if (ret == EOK) { -@@ -1375,6 +1385,11 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx, - goto fail; - } - -+ DEBUG(SSSDBG_TRACE_FUNC, "Sending request_type: [%s] for trust user [%s] " -+ "to IPA server\n", -+ ipa_s2n_reqtype2str(state->request_type), -+ req_input->inp.name); -+ - subreq = ipa_s2n_exop_send(state, state->ev, state->sh, is_v1, - state->exop_timeout, bv_req); - if (subreq == NULL) { -@@ -1661,6 +1676,19 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) - state->attrs = attrs; - - if (attrs->response_type == RESP_USER_GROUPLIST) { -+ -+ if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) { -+ size_t c; -+ -+ DEBUG(SSSDBG_TRACE_FUNC, "Received [%zu] groups in group list " -+ "from IPA Server\n", attrs->ngroups); -+ -+ for (c = 0; c < attrs->ngroups; c++) { -+ DEBUG(SSSDBG_TRACE_FUNC, "[%s].\n", attrs->groups[c]); -+ } -+ } -+ -+ - ret = get_group_dn_list(state, state->dom, - attrs->ngroups, attrs->groups, - &group_dn_list, &missing_list); --- -2.9.3 - diff --git a/SOURCES/0016-UTIL-Add-wrapper-function-to-configure-logger.patch b/SOURCES/0016-UTIL-Add-wrapper-function-to-configure-logger.patch new file mode 100644 index 0000000..a4dea5f --- /dev/null +++ b/SOURCES/0016-UTIL-Add-wrapper-function-to-configure-logger.patch @@ -0,0 +1,133 @@ +From 34fa82bc07c4da14606d7a8a9b68a872fe210a9f Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 23 Oct 2017 14:58:14 +0200 +Subject: [PATCH 16/21] UTIL: Add wrapper function to configure logger +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let's use one enum for logger type instead of many integers (debug_to_file, +debug_to_stderr plus some weird combination for journald). +Old variable were also transformed to enum for backward compatibility + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 09e3f0af96cecb94be69084c025f0355b3111993) +--- + src/util/debug.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/util/debug.h | 18 ++++++++++++++++++ + 2 files changed, 72 insertions(+) + +diff --git a/src/util/debug.c b/src/util/debug.c +index ca4fa4c6f5b150700a0a136d8a7ca9df30c29d73..4e469447e5ab8aa89cd57bcd6d00269875a12bc6 100644 +--- a/src/util/debug.c ++++ b/src/util/debug.c +@@ -43,9 +43,63 @@ int debug_timestamps = SSSDBG_TIMESTAMP_UNRESOLVED; + int debug_microseconds = SSSDBG_MICROSECONDS_UNRESOLVED; + int debug_to_file = 0; + int debug_to_stderr = 0; ++enum sss_logger_t sss_logger; + const char *debug_log_file = "sssd"; + FILE *debug_file = NULL; + ++const char *sss_logger_str[] = { ++ [STDERR_LOGGER] = "stderr", ++ [FILES_LOGGER] = "files", ++#ifdef WITH_JOURNALD ++ [JOURNALD_LOGGER] = "journald", ++#endif ++ NULL, ++}; ++ ++#ifdef WITH_JOURNALD ++#define JOURNALD_STR " journald," ++#else ++#define JOURNALD_STR "" ++#endif ++ ++void sss_set_logger(const char *logger) ++{ ++ /* use old flags */ ++ if (logger == NULL) { ++ if (debug_to_stderr != 0) { ++ sss_logger = STDERR_LOGGER; ++ } ++ /* It is never described what should be used in case of ++ * debug_to_stderr == 1 && debug_to_file == 1. Because neither ++ * of binaries provide both command line arguments. ++ * Let files have higher priority. ++ */ ++ if (debug_to_file != 0) { ++ sss_logger = FILES_LOGGER; ++ } ++#ifdef WITH_JOURNALD ++ if (debug_to_file == 0 && debug_to_stderr == 0) { ++ sss_logger = JOURNALD_LOGGER; ++ } ++#endif ++ } else { ++ if (strcmp(logger, "stderr") == 0) { ++ sss_logger = STDERR_LOGGER; ++ } else if (strcmp(logger, "files") == 0) { ++ sss_logger = FILES_LOGGER; ++#ifdef WITH_JOURNALD ++ } else if (strcmp(logger, "journald") == 0) { ++ sss_logger = JOURNALD_LOGGER; ++#endif ++ } else { ++ /* unexpected value */ ++ fprintf(stderr, "Unexpected logger: %s\nExpected:%s stderr, " ++ "files\n", logger, JOURNALD_STR); ++ sss_logger = STDERR_LOGGER; ++ } ++ } ++} ++ + errno_t set_debug_file_from_fd(const int fd) + { + FILE *dummy; +diff --git a/src/util/debug.h b/src/util/debug.h +index 2a1bd4ffd30817d7128805996c21105fe40982a2..4adafb7cfc03f7381c4d03071eb44edad04bee00 100644 +--- a/src/util/debug.h ++++ b/src/util/debug.h +@@ -31,13 +31,26 @@ + + #define APPEND_LINE_FEED 0x1 + ++enum sss_logger_t { ++ STDERR_LOGGER = 0, ++ FILES_LOGGER, ++#ifdef WITH_JOURNALD ++ JOURNALD_LOGGER, ++#endif ++}; ++ ++extern const char *sss_logger_str[]; + extern const char *debug_prg_name; + extern int debug_level; + extern int debug_timestamps; + extern int debug_microseconds; + extern int debug_to_file; + extern int debug_to_stderr; ++extern enum sss_logger_t sss_logger; + extern const char *debug_log_file; ++ ++void sss_set_logger(const char *logger); ++ + void sss_vdebug_fn(const char *file, + long line, + const char *function, +@@ -80,6 +93,11 @@ int get_fd_from_debug_file(void); + #define SSSDBG_MICROSECONDS_UNRESOLVED -1 + #define SSSDBG_MICROSECONDS_DEFAULT 0 + ++#define SSSD_LOGGER_OPTS \ ++ {"logger", '\0', POPT_ARG_STRING, &opt_logger, 0, \ ++ _("Set logger"), "stderr|files|journald"}, ++ ++ + #define SSSD_DEBUG_OPTS \ + {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0, \ + _("Debug level"), NULL}, \ +-- +2.13.5 + diff --git a/SOURCES/0016-UTIL-iobuf-Make-input-parameter-for-the-readonly-ope.patch b/SOURCES/0016-UTIL-iobuf-Make-input-parameter-for-the-readonly-ope.patch deleted file mode 100644 index 5ded3ab..0000000 --- a/SOURCES/0016-UTIL-iobuf-Make-input-parameter-for-the-readonly-ope.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 4ea851ed034efdb06d13b34797b9f849e3dcec97 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 15 Mar 2017 13:32:42 +0100 -Subject: [PATCH 16/36] UTIL: iobuf: Make input parameter for the readonly - operation const -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/util/sss_iobuf.c | 2 +- - src/util/sss_iobuf.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/util/sss_iobuf.c b/src/util/sss_iobuf.c -index 7c72ea94d7a005dfd9671793b3ad470a6de7967a..900418b750a3455ebc2c3bb1893db726692260b8 100644 ---- a/src/util/sss_iobuf.c -+++ b/src/util/sss_iobuf.c -@@ -49,7 +49,7 @@ struct sss_iobuf *sss_iobuf_init_empty(TALLOC_CTX *mem_ctx, - } - - struct sss_iobuf *sss_iobuf_init_readonly(TALLOC_CTX *mem_ctx, -- uint8_t *data, -+ const uint8_t *data, - size_t size) - { - struct sss_iobuf *iobuf; -diff --git a/src/util/sss_iobuf.h b/src/util/sss_iobuf.h -index eae357a40f2948e63df189f2842edee68691a542..900faaa212230f72f52e344c085167e80ae2b465 100644 ---- a/src/util/sss_iobuf.h -+++ b/src/util/sss_iobuf.h -@@ -47,7 +47,7 @@ struct sss_iobuf *sss_iobuf_init_empty(TALLOC_CTX *mem_ctx, - * @return The newly created buffer on success or NULL on an error. - */ - struct sss_iobuf *sss_iobuf_init_readonly(TALLOC_CTX *mem_ctx, -- uint8_t *data, -+ const uint8_t *data, - size_t size); - - /* --- -2.9.3 - diff --git a/SOURCES/0017-Add-parameter-logger-to-daemons.patch b/SOURCES/0017-Add-parameter-logger-to-daemons.patch new file mode 100644 index 0000000..1a547c3 --- /dev/null +++ b/SOURCES/0017-Add-parameter-logger-to-daemons.patch @@ -0,0 +1,830 @@ +From de26ea6f603e87ef306f08fa1b458b8a180bdf2d Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 23 Oct 2017 15:18:47 +0200 +Subject: [PATCH 17/21] Add parameter --logger to daemons +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Different binary handled information about logging differently + e,g, --debug-to-files --debug-to-stderr +And logging to journald was a special case of previous options +(!debug_file && !debug_to_stderr). It was also tied to the monitor option +"--daemon" and therefore loggind to stderr was used in interactive mode ++ systemd Type=notify. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3433 + +Reviewed-by: Justin Stephenson +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit cb75b275d15beedd1fdecc1f8ced657fba282218) +--- + src/man/sssd.8.xml | 31 +++++++++++++++++++++++++ + src/monitor/monitor.c | 48 ++++++++++++--------------------------- + src/p11_child/p11_child_nss.c | 3 +++ + src/providers/ad/ad_gpo_child.c | 4 ++++ + src/providers/data_provider_be.c | 4 ++++ + src/providers/ipa/selinux_child.c | 4 ++++ + src/providers/krb5/krb5_child.c | 4 ++++ + src/providers/ldap/ldap_child.c | 4 ++++ + src/providers/proxy/proxy_auth.c | 4 ++-- + src/providers/proxy/proxy_child.c | 4 ++++ + src/responder/autofs/autofssrv.c | 4 ++++ + src/responder/ifp/ifpsrv.c | 4 ++++ + src/responder/kcm/kcm.c | 4 ++++ + src/responder/nss/nsssrv.c | 4 ++++ + src/responder/pac/pacsrv.c | 4 ++++ + src/responder/pam/pamsrv.c | 4 ++++ + src/responder/secrets/secsrv.c | 4 ++++ + src/responder/ssh/sshsrv.c | 4 ++++ + src/responder/sudo/sudosrv.c | 4 ++++ + src/tests/cmocka/dummy_child.c | 4 ++++ + src/tests/debug-tests.c | 10 ++++++++ + src/util/child_common.c | 2 +- + src/util/debug.c | 4 ++-- + src/util/server.c | 12 ++++++---- + 24 files changed, 135 insertions(+), 43 deletions(-) + +diff --git a/src/man/sssd.8.xml b/src/man/sssd.8.xml +index 923da6824907f0d2d140d9ca83f87338e7664f83..0b725628ff93f48f832140dd5dc15b040a8b179f 100644 +--- a/src/man/sssd.8.xml ++++ b/src/man/sssd.8.xml +@@ -94,6 +94,37 @@ + + + ++ value ++ ++ ++ ++ Location where SSSD will send log messages. This option ++ overrides the value of the deprecated option ++ . The deprecated ++ option will still work if the ++ is not used. ++ ++ ++ stderr: Redirect debug messages to ++ standard error output. ++ ++ ++ files: Redirect debug messages to ++ the log files. By default, the log files are stored in ++ /var/log/sssd and there are ++ separate log files for every SSSD service and domain. ++ ++ ++ journald: Redirect debug messages ++ to systemd-journald ++ ++ ++ Default: not set ++ ++ ++ ++ ++ + , + + +diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c +index 7726548bbb666bb189667efc1de2295f8a001105..3c0b7ab2dac10fe15a8a5b807cb68ea4b7ab8461 100644 +--- a/src/monitor/monitor.c ++++ b/src/monitor/monitor.c +@@ -1211,22 +1211,11 @@ static int get_service_config(struct mt_ctx *ctx, const char *name, + } + } + +- if (debug_to_file) { +- svc->command = talloc_strdup_append( +- svc->command, " --debug-to-files" +- ); +- if (!svc->command) { +- talloc_free(svc); +- return ENOMEM; +- } +- } else if (ctx->is_daemon == false) { +- svc->command = talloc_strdup_append( +- svc->command, " --debug-to-stderr" +- ); +- if (!svc->command) { +- talloc_free(svc); +- return ENOMEM; +- } ++ svc->command = talloc_asprintf_append( ++ svc->command, " --logger=%s", sss_logger_str[sss_logger]); ++ if (!svc->command) { ++ talloc_free(svc); ++ return ENOMEM; + } + } + +@@ -1374,22 +1363,11 @@ static int get_provider_config(struct mt_ctx *ctx, const char *name, + } + } + +- if (debug_to_file) { +- svc->command = talloc_strdup_append( +- svc->command, " --debug-to-files" +- ); +- if (!svc->command) { +- talloc_free(svc); +- return ENOMEM; +- } +- } else if (ctx->is_daemon == false) { +- svc->command = talloc_strdup_append( +- svc->command, " --debug-to-stderr" +- ); +- if (!svc->command) { +- talloc_free(svc); +- return ENOMEM; +- } ++ svc->command = talloc_asprintf_append( ++ svc->command, " --logger=%s", sss_logger_str[sss_logger]); ++ if (!svc->command) { ++ talloc_free(svc); ++ return ENOMEM; + } + } + +@@ -2454,6 +2432,7 @@ int main(int argc, const char *argv[]) + int opt_version = 0; + int opt_netlinkoff = 0; + char *opt_config_file = NULL; ++ char *opt_logger = NULL; + char *config_file = NULL; + int flags = 0; + struct main_context *main_ctx; +@@ -2465,6 +2444,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + {"daemon", 'D', POPT_ARG_NONE, &opt_daemon, 0, \ + _("Become a daemon (default)"), NULL }, \ + {"interactive", 'i', POPT_ARG_NONE, &opt_interactive, 0, \ +@@ -2551,6 +2531,8 @@ int main(int argc, const char *argv[]) + debug_to_stderr = 1; + } + ++ sss_set_logger(opt_logger); ++ + if (opt_config_file) { + config_file = talloc_strdup(tmp_ctx, opt_config_file); + } else { +@@ -2575,7 +2557,7 @@ int main(int argc, const char *argv[]) + + /* Open before server_setup() does to have logging + * during configuration checking */ +- if (debug_to_file) { ++ if (sss_logger == FILES_LOGGER) { + ret = open_debug_file(); + if (ret) { + return 7; +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index f165b58e63d2b8a6f26acf8bd89e7b41713e7359..e7dbcb689220d1cd2585fbde5f26e84f8fa15cc2 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -537,6 +537,7 @@ int main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; ++ char *opt_logger = NULL; + errno_t ret; + TALLOC_CTX *main_ctx = NULL; + char *cert; +@@ -564,6 +565,7 @@ int main(int argc, const char *argv[]) + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, + &debug_to_stderr, 0, + _("Send the debug output to stderr directly."), NULL }, ++ SSSD_LOGGER_OPTS + {"auth", 0, POPT_ARG_NONE, NULL, 'a', _("Run in auth mode"), NULL}, + {"pre", 0, POPT_ARG_NONE, NULL, 'p', _("Run in pre-auth mode"), NULL}, + {"pin", 0, POPT_ARG_NONE, NULL, 'i', _("Expect PIN on stdin"), NULL}, +@@ -672,6 +674,7 @@ int main(int argc, const char *argv[]) + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } + } ++ sss_set_logger(opt_logger); + + DEBUG(SSSDBG_TRACE_FUNC, "p11_child started.\n"); + +diff --git a/src/providers/ad/ad_gpo_child.c b/src/providers/ad/ad_gpo_child.c +index 8e5e062547721567cb450f9d0f72f1ec8cb99f96..5375cc691e8649c289672b74c4bfe5266c8222c9 100644 +--- a/src/providers/ad/ad_gpo_child.c ++++ b/src/providers/ad/ad_gpo_child.c +@@ -687,6 +687,7 @@ main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; ++ char *opt_logger = NULL; + errno_t ret; + int sysvol_gpt_version; + int result; +@@ -710,6 +711,7 @@ main(int argc, const char *argv[]) + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, + &debug_to_stderr, 0, + _("Send the debug output to stderr directly."), NULL }, ++ SSSD_LOGGER_OPTS + POPT_TABLEEND + }; + +@@ -744,6 +746,8 @@ main(int argc, const char *argv[]) + } + } + ++ sss_set_logger(opt_logger); ++ + DEBUG(SSSDBG_TRACE_FUNC, "gpo_child started.\n"); + + main_ctx = talloc_new(NULL); +diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c +index 2e55dc4e3fe9ba1aa8c1c51c426efee00b9ae91d..56ddac112a209b6937313d3d3c94a73d2067331f 100644 +--- a/src/providers/data_provider_be.c ++++ b/src/providers/data_provider_be.c +@@ -537,6 +537,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + char *be_domain = NULL; + char *srv_name = NULL; + struct main_context *main_ctx; +@@ -548,6 +549,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + {"domain", 0, POPT_ARG_STRING, &be_domain, 0, + _("Domain of the information provider (mandatory)"), NULL }, +@@ -582,6 +584,8 @@ int main(int argc, const char *argv[]) + debug_log_file = talloc_asprintf(NULL, "sssd_%s", be_domain); + if (!debug_log_file) return 2; + ++ sss_set_logger(opt_logger); ++ + srv_name = talloc_asprintf(NULL, "sssd[be[%s]]", be_domain); + if (!srv_name) return 2; + +diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c +index 073475094ee491bd5453898c6ba65214fa14fe59..120492686963241b7e419413f489cc38953e32f2 100644 +--- a/src/providers/ipa/selinux_child.c ++++ b/src/providers/ipa/selinux_child.c +@@ -206,6 +206,7 @@ int main(int argc, const char *argv[]) + struct response *resp = NULL; + ssize_t written; + bool needs_update; ++ char *opt_logger = NULL; + + struct poptOption long_options[] = { + POPT_AUTOHELP +@@ -220,6 +221,7 @@ int main(int argc, const char *argv[]) + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, + &debug_to_stderr, 0, + _("Send the debug output to stderr directly."), NULL }, ++ SSSD_LOGGER_OPTS + POPT_TABLEEND + }; + +@@ -254,6 +256,8 @@ int main(int argc, const char *argv[]) + } + } + ++ sss_set_logger(opt_logger); ++ + DEBUG(SSSDBG_TRACE_FUNC, "selinux_child started.\n"); + DEBUG(SSSDBG_TRACE_INTERNAL, + "Running with effective IDs: [%"SPRIuid"][%"SPRIgid"].\n", +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index 888cc5d6f5c554901cc46d4315844d7bbbe582b8..700338e47a3f9ac6fcf11b4c92364dbdb4f9bcf7 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -3020,6 +3020,7 @@ int main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; ++ char *opt_logger = NULL; + errno_t ret; + krb5_error_code kerr; + uid_t fast_uid; +@@ -3039,6 +3040,7 @@ int main(int argc, const char *argv[]) + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, + &debug_to_stderr, 0, + _("Send the debug output to stderr directly."), NULL }, ++ SSSD_LOGGER_OPTS + {CHILD_OPT_FAST_CCACHE_UID, 0, POPT_ARG_INT, &fast_uid, 0, + _("The user to create FAST ccache as"), NULL}, + {CHILD_OPT_FAST_CCACHE_GID, 0, POPT_ARG_INT, &fast_gid, 0, +@@ -3097,6 +3099,8 @@ int main(int argc, const char *argv[]) + } + } + ++ sss_set_logger(opt_logger); ++ + DEBUG(SSSDBG_TRACE_FUNC, "krb5_child started.\n"); + + kr = talloc_zero(NULL, struct krb5_req); +diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c +index b796e5cae01517c85c2fc1605b1e5877454691dc..baeed239db5dc7ffa482edcbc155f25f718c8249 100644 +--- a/src/providers/ldap/ldap_child.c ++++ b/src/providers/ldap/ldap_child.c +@@ -599,6 +599,7 @@ int main(int argc, const char *argv[]) + int kerr; + int opt; + int debug_fd = -1; ++ char *opt_logger = NULL; + poptContext pc; + TALLOC_CTX *main_ctx = NULL; + uint8_t *buf = NULL; +@@ -622,6 +623,7 @@ int main(int argc, const char *argv[]) + _("An open file descriptor for the debug logs"), NULL}, + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \ + _("Send the debug output to stderr directly."), NULL }, \ ++ SSSD_LOGGER_OPTS + POPT_TABLEEND + }; + +@@ -657,6 +659,8 @@ int main(int argc, const char *argv[]) + } + } + ++ sss_set_logger(opt_logger); ++ + BlockSignals(false, SIGTERM); + CatchSignal(SIGTERM, sig_term_handler); + +diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c +index a05586e60b6ef894b0fcf1b8b3f30fdbf51a808d..665a29cf779290b8d35973245a36a1b5224bca78 100644 +--- a/src/providers/proxy/proxy_auth.c ++++ b/src/providers/proxy/proxy_auth.c +@@ -178,9 +178,9 @@ static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx, + + state->command = talloc_asprintf(req, + "%s/proxy_child -d %#.4x --debug-timestamps=%d " +- "--debug-microseconds=%d%s --domain %s --id %d", ++ "--debug-microseconds=%d --logger=%s --domain %s --id %d", + SSSD_LIBEXEC_PATH, debug_level, debug_timestamps, +- debug_microseconds, (debug_to_file ? " --debug-to-files" : ""), ++ debug_microseconds, sss_logger_str[sss_logger], + auth_ctx->be->domain->name, + child_ctx->id); + if (state->command == NULL) { +diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c +index be58622eb8b26231eeb6699976d51f57dc44de98..ae4855adeb5cc68f1a19003355a5d94f5b1bb378 100644 +--- a/src/providers/proxy/proxy_child.c ++++ b/src/providers/proxy/proxy_child.c +@@ -504,6 +504,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + char *domain = NULL; + char *srv_name = NULL; + char *conf_entry = NULL; +@@ -517,6 +518,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + {"domain", 0, POPT_ARG_STRING, &domain, 0, + _("Domain of the information provider (mandatory)"), NULL }, +@@ -561,6 +563,8 @@ int main(int argc, const char *argv[]) + debug_log_file = talloc_asprintf(NULL, "proxy_child_%s", domain); + if (!debug_log_file) return 2; + ++ sss_set_logger(opt_logger); ++ + srv_name = talloc_asprintf(NULL, "sssd[proxy_child[%s]]", domain); + if (!srv_name) return 2; + +diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c +index cfb2233fdfc346bf27b128ee8c4261f4c73e3470..b0762a2b685a7c5ab3abfa281f0906ad8bfe1c88 100644 +--- a/src/responder/autofs/autofssrv.c ++++ b/src/responder/autofs/autofssrv.c +@@ -185,6 +185,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -193,6 +194,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -221,6 +223,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_autofs"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[autofs]", 0, uid, gid, + CONFDB_AUTOFS_CONF_ENTRY, &main_ctx); + if (ret != EOK) { +diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c +index 0dc61a42200cc79fc6f12515a8f581ad0201a043..85dfbacc217e2870dd7517e36a1d39e7f2054a8b 100644 +--- a/src/responder/ifp/ifpsrv.c ++++ b/src/responder/ifp/ifpsrv.c +@@ -355,6 +355,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -363,6 +364,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -391,6 +393,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_ifp"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[ifp]", 0, 0, 0, + CONFDB_IFP_CONF_ENTRY, &main_ctx); + if (ret != EOK) return 2; +diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c +index 2202f96381a2622a2c5433e281172287b325f960..358fcc18165dec7b41a7389a3ef22660ac04b4a8 100644 +--- a/src/responder/kcm/kcm.c ++++ b/src/responder/kcm/kcm.c +@@ -258,6 +258,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -266,6 +267,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + POPT_TABLEEND + }; +@@ -293,6 +295,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_kcm"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[kcm]", 0, uid, gid, CONFDB_KCM_CONF_ENTRY, + &main_ctx); + if (ret != EOK) return 2; +diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c +index 32bfcd69bbb9b35e9932b70a826c4f99ab6a07f3..11d19fd30c86283d537623db12e52caa6cc4dcd3 100644 +--- a/src/responder/nss/nsssrv.c ++++ b/src/responder/nss/nsssrv.c +@@ -422,6 +422,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -430,6 +431,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -458,6 +460,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_nss"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[nss]", 0, uid, gid, CONFDB_NSS_CONF_ENTRY, + &main_ctx); + if (ret != EOK) return 2; +diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c +index 1f820c07f5c55fe8df75cce05b403c41075d9f94..b72e5c8d2a42bc85f0974dcb81a1290d3f740986 100644 +--- a/src/responder/pac/pacsrv.c ++++ b/src/responder/pac/pacsrv.c +@@ -209,6 +209,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -217,6 +218,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -245,6 +247,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_pac"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[pac]", 0, uid, gid, + CONFDB_PAC_CONF_ENTRY, &main_ctx); + if (ret != EOK) return 2; +diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c +index 79470823d18138da6ef9235e6336a3220ead1797..cc0e4bddcdbecfadabea78a6d2815d0ac6d651b6 100644 +--- a/src/responder/pam/pamsrv.c ++++ b/src/responder/pam/pamsrv.c +@@ -355,6 +355,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -365,6 +366,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -393,6 +395,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_pam"; + ++ sss_set_logger(opt_logger); ++ + if (!is_socket_activated()) { + /* Crate pipe file descriptors here before privileges are dropped + * in server_setup() */ +diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c +index 2b661b165ef0c174557f53012b2dbaa236a6e359..59c0f3a56040a6fc0c092247fbd124a069f97153 100644 +--- a/src/responder/secrets/secsrv.c ++++ b/src/responder/secrets/secsrv.c +@@ -324,6 +324,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -332,6 +333,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + POPT_TABLEEND + }; +@@ -359,6 +361,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_secrets"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[secrets]", 0, uid, gid, CONFDB_SEC_CONF_ENTRY, + &main_ctx); + if (ret != EOK) return 2; +diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c +index 440f0e2b9dc06e3dc52ff96d7207b8a3727865c0..8b0e7cc2d71044d7ab3bd2439041f678ddedb4cd 100644 +--- a/src/responder/ssh/sshsrv.c ++++ b/src/responder/ssh/sshsrv.c +@@ -177,6 +177,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -185,6 +186,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -213,6 +215,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_ssh"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[ssh]", 0, uid, gid, + CONFDB_SSH_CONF_ENTRY, &main_ctx); + if (ret != EOK) { +diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c +index dca70ea4afc0e6df6d1b1864338c7b1091a98fee..19058321a25022d7704556ec0ef79729db3ac1f2 100644 +--- a/src/responder/sudo/sudosrv.c ++++ b/src/responder/sudo/sudosrv.c +@@ -178,6 +178,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -186,6 +187,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -214,6 +216,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_sudo"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[sudo]", 0, uid, gid, CONFDB_SUDO_CONF_ENTRY, + &main_ctx); + if (ret != EOK) { +diff --git a/src/tests/cmocka/dummy_child.c b/src/tests/cmocka/dummy_child.c +index bcaa9455037a0604422750bf7cc719a25cef4a99..811cb40490c89c4250401e0d8d3e9d1c277f57af 100644 +--- a/src/tests/cmocka/dummy_child.c ++++ b/src/tests/cmocka/dummy_child.c +@@ -34,6 +34,7 @@ int main(int argc, const char *argv[]) + { + int opt; + int debug_fd = -1; ++ char *opt_logger = NULL; + poptContext pc; + ssize_t len; + ssize_t written; +@@ -55,6 +56,7 @@ int main(int argc, const char *argv[]) + _("An open file descriptor for the debug logs"), NULL}, + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \ + _("Send the debug output to stderr directly."), NULL }, ++ SSSD_LOGGER_OPTS + {"guitar", 0, POPT_ARG_STRING, &guitar, 0, _("Who plays guitar"), NULL }, + {"drums", 0, POPT_ARG_STRING, &drums, 0, _("Who plays drums"), NULL }, + POPT_TABLEEND +@@ -76,6 +78,8 @@ int main(int argc, const char *argv[]) + } + poptFreeContext(pc); + ++ sss_set_logger(opt_logger); ++ + action = getenv("TEST_CHILD_ACTION"); + if (action) { + if (strcasecmp(action, "check_extra_args") == 0) { +diff --git a/src/tests/debug-tests.c b/src/tests/debug-tests.c +index d904d7eb8b5418608023faca0d62067f3106d23b..1446ec0474ab4bf72e66b58831fef59defd7be76 100644 +--- a/src/tests/debug-tests.c ++++ b/src/tests/debug-tests.c +@@ -343,6 +343,7 @@ START_TEST(test_debug_is_set_single_no_timestamp) + debug_microseconds = 0; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); + + for (i = 0; i <= 9; i++) { + debug_level = levels[i]; +@@ -385,6 +386,8 @@ START_TEST(test_debug_is_set_single_timestamp) + debug_microseconds = 0; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); ++ + + for (i = 0; i <= 9; i++) { + debug_level = levels[i]; +@@ -432,6 +435,8 @@ START_TEST(test_debug_is_set_single_timestamp_microseconds) + debug_microseconds = 1; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); ++ + + for (i = 0; i <= 9; i++) { + debug_level = levels[i]; +@@ -480,6 +485,8 @@ START_TEST(test_debug_is_notset_no_timestamp) + debug_microseconds = 0; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); ++ + + for (i = 0; i <= 9; i++) { + debug_level = all_set & ~levels[i]; +@@ -525,6 +532,8 @@ START_TEST(test_debug_is_notset_timestamp) + debug_microseconds = 0; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); ++ + + for (i = 0; i <= 9; i++) { + debug_level = all_set & ~levels[i]; +@@ -570,6 +579,7 @@ START_TEST(test_debug_is_notset_timestamp_microseconds) + debug_microseconds = 1; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); + + for (i = 0; i <= 9; i++) { + debug_level = all_set & ~levels[i]; +diff --git a/src/util/child_common.c b/src/util/child_common.c +index b300d84bf432608db96de36e04637b5fb115212e..dc070f26446305e07cbb34edd1e4d72db72aedc5 100644 +--- a/src/util/child_common.c ++++ b/src/util/child_common.c +@@ -676,7 +676,7 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx, + } + + if (child_debug_stderr) { +- argv[--argc] = talloc_strdup(argv, "--debug-to-stderr"); ++ argv[--argc] = talloc_strdup(argv, "--logger=stderr"); + if (argv[argc] == NULL) { + ret = ENOMEM; + goto fail; +diff --git a/src/util/debug.c b/src/util/debug.c +index 4e469447e5ab8aa89cd57bcd6d00269875a12bc6..30801fce7c27b115d1cafd4ed826a57c7d444a72 100644 +--- a/src/util/debug.c ++++ b/src/util/debug.c +@@ -277,7 +277,7 @@ void sss_vdebug_fn(const char *file, + errno_t ret; + va_list ap_fallback; + +- if (!debug_file && !debug_to_stderr) { ++ if (sss_logger == JOURNALD_LOGGER) { + /* If we are not outputting logs to files, we should be sending them + * to journald. + * NOTE: on modern systems, this is where stdout/stderr will end up +@@ -470,7 +470,7 @@ int rotate_debug_files(void) + int ret; + errno_t error; + +- if (!debug_to_file) return EOK; ++ if (sss_logger != FILES_LOGGER) return EOK; + + do { + error = 0; +diff --git a/src/util/server.c b/src/util/server.c +index 0046c9737bc0d9aea7be59b4fed5e0f8930ff66e..26b8b27f0e5c8524520a2d4774e90fd6cb32bf7a 100644 +--- a/src/util/server.c ++++ b/src/util/server.c +@@ -455,7 +455,7 @@ int server_setup(const char *name, int flags, + char *conf_db; + int ret = EOK; + bool dt; +- bool dl; ++ bool dl = false; + bool dm; + struct tevent_signal *tes; + struct logrotate_ctx *lctx; +@@ -637,16 +637,18 @@ int server_setup(const char *name, int flags, + } + + /* same for debug to file */ +- dl = (debug_to_file != 0); + ret = confdb_get_bool(ctx->confdb_ctx, conf_entry, + CONFDB_SERVICE_DEBUG_TO_FILES, +- dl, &dl); ++ false, &dl); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) [%s]\n", + ret, strerror(ret)); + return ret; + } +- if (dl) debug_to_file = 1; ++ if (dl) { ++ debug_to_file = 1; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); ++ } + + /* before opening the log file set up log rotation */ + lctx = talloc_zero(ctx, struct logrotate_ctx); +@@ -662,7 +664,7 @@ int server_setup(const char *name, int flags, + } + + /* open log file if told so */ +- if (debug_to_file) { ++ if (sss_logger == FILES_LOGGER) { + ret = open_debug_file(); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Error setting up logging (%d) " +-- +2.13.5 + diff --git a/SOURCES/0017-UTIL-Fix-a-typo-in-the-tcurl-test-tool.patch b/SOURCES/0017-UTIL-Fix-a-typo-in-the-tcurl-test-tool.patch deleted file mode 100644 index c51e496..0000000 --- a/SOURCES/0017-UTIL-Fix-a-typo-in-the-tcurl-test-tool.patch +++ /dev/null @@ -1,32 +0,0 @@ -From c402799ea8b24d2e382d0ad7a06ee92861852972 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 15 Mar 2017 13:42:03 +0100 -Subject: [PATCH 17/36] UTIL: Fix a typo in the tcurl test tool -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/tests/tcurl_test_tool.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c -index 35ea979780df47c92ed92bc5bba713faa8909b90..38cea432885c97ca3827c8f158bf7e3ebfc67b31 100644 ---- a/src/tests/tcurl_test_tool.c -+++ b/src/tests/tcurl_test_tool.c -@@ -204,8 +204,8 @@ int main(int argc, const char *argv[]) - urls[i], - headers, - inbufs[i], -- 10); -- if (ctx == NULL) { -+ 5); -+ if (req == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, "Could not create request\n"); - talloc_zfree(tool_ctx); - return 1; --- -2.9.3 - diff --git a/SOURCES/0018-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch b/SOURCES/0018-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch new file mode 100644 index 0000000..a409fab --- /dev/null +++ b/SOURCES/0018-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch @@ -0,0 +1,259 @@ +From 66cdb732268cc8dfd4f0800178d1cc186de83ef7 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 23 Oct 2017 18:03:46 +0200 +Subject: [PATCH 18/21] SYSTEMD: Replace parameter --debug-to-files with + ${DEBUG_LOGGER} +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Users can set variable DEBUG_LOGGER in environment files +(/etc/sysconfig/sssd or /etc/default/sssd; depending on the distribution) +to override default logging to files. + +e.g. +DEBUG_LOGGER=--logger=stderr +DEBUG_LOGGER=--logger=journald + +Resolves: +https://pagure.io/SSSD/sssd/issue/3433 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit a7277fecf7a65ab6c83b36f009c558cdfbf997d2) +--- + Makefile.am | 12 +----------- + contrib/sssd.spec.in | 4 ---- + src/sysv/systemd/journal.conf.in | 7 ------- + src/sysv/systemd/sssd-autofs.service.in | 3 ++- + src/sysv/systemd/sssd-ifp.service.in | 3 ++- + src/sysv/systemd/sssd-kcm.service.in | 3 ++- + src/sysv/systemd/sssd-nss.service.in | 3 ++- + src/sysv/systemd/sssd-pac.service.in | 3 ++- + src/sysv/systemd/sssd-pam.service.in | 3 ++- + src/sysv/systemd/sssd-secrets.service.in | 3 ++- + src/sysv/systemd/sssd-ssh.service.in | 3 ++- + src/sysv/systemd/sssd-sudo.service.in | 3 ++- + src/sysv/systemd/sssd.service.in | 3 ++- + 13 files changed, 21 insertions(+), 32 deletions(-) + delete mode 100644 src/sysv/systemd/journal.conf.in + +diff --git a/Makefile.am b/Makefile.am +index 41a8f32f4e76fdcbd09ad833161f0bdada19e389..5483375167d99568e8313c9a0488900419be6ec3 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -91,7 +91,7 @@ sssdkcmdatadir = $(datadir)/sssd-kcm + deskprofilepath = $(sss_statedir)/deskprofile + + if HAVE_SYSTEMD_UNIT +-ifp_exec_cmd = $(sssdlibexecdir)/sssd_ifp --uid 0 --gid 0 --debug-to-files --dbus-activated ++ifp_exec_cmd = $(sssdlibexecdir)/sssd_ifp --uid 0 --gid 0 --dbus-activated + ifp_systemdservice = SystemdService=sssd-ifp.service + ifp_restart = Restart=on-failure + else +@@ -4483,10 +4483,6 @@ if BUILD_KCM + src/sysv/systemd/sssd-kcm.service \ + $(NULL) + endif +-if WITH_JOURNALD +- systemdconf_DATA += \ +- src/sysv/systemd/journal.conf +-endif + else + if HAVE_SUSE + init_SCRIPTS += \ +@@ -4535,7 +4531,6 @@ replace_script = \ + + EXTRA_DIST += \ + src/sysv/systemd/sssd.service.in \ +- src/sysv/systemd/journal.conf.in \ + src/sysv/systemd/sssd-nss.socket.in \ + src/sysv/systemd/sssd-nss.service.in \ + src/sysv/systemd/sssd-pam.socket.in \ +@@ -4585,10 +4580,6 @@ src/sysv/systemd/sssd.service: src/sysv/systemd/sssd.service.in Makefile + @$(MKDIR_P) src/sysv/systemd/ + $(replace_script) + +-src/sysv/systemd/journal.conf: src/sysv/systemd/journal.conf.in Makefile +- @$(MKDIR_P) src/sysv/systemd/ +- $(replace_script) +- + src/sysv/systemd/sssd-nss.socket: src/sysv/systemd/sssd-nss.socket.in Makefile + @$(MKDIR_P) src/sysv/systemd/ + $(replace_script) +@@ -4924,7 +4915,6 @@ endif + rm -f $(builddir)/src/sysv/systemd/sssd-secrets.service + rm -f $(builddir)/src/sysv/systemd/sssd-kcm.socket + rm -f $(builddir)/src/sysv/systemd/sssd-kcm.service +- rm -f $(builddir)/src/sysv/systemd/journal.conf + rm -f $(builddir)/src/tools/wrappers/sss_debuglevel + + CLEANFILES += *.X */*.X */*/*.X +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index e76b51833d5dfa3207d28add4af1016c00f25e1f..1ee64d5a2a64635984260fceced779f4804e8b31 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -971,10 +971,6 @@ done + %attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd + %attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd/conf.d + %ghost %attr(0600,sssd,sssd) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf +-%if (0%{?use_systemd} == 1) +-%attr(755,root,root) %dir %{_sysconfdir}/systemd/system/sssd.service.d +-%config(noreplace) %{_sysconfdir}/systemd/system/sssd.service.d/journal.conf +-%endif + %dir %{_sysconfdir}/logrotate.d + %config(noreplace) %{_sysconfdir}/logrotate.d/sssd + %dir %{_sysconfdir}/rwtab.d +diff --git a/src/sysv/systemd/journal.conf.in b/src/sysv/systemd/journal.conf.in +deleted file mode 100644 +index 9ce170b4893629792516aab41573adea1fb741f0..0000000000000000000000000000000000000000 +--- a/src/sysv/systemd/journal.conf.in ++++ /dev/null +@@ -1,7 +0,0 @@ +-[Service] +-# Uncomment *both* of the following lines to enable debug logging +-# to go to journald instead of /var/log/sssd. You will need to +-# run 'systemctl daemon-reload' and then restart the SSSD service +-# for this to take effect +-#ExecStart= +-#ExecStart=@sbindir@/sssd -i +diff --git a/src/sysv/systemd/sssd-autofs.service.in b/src/sysv/systemd/sssd-autofs.service.in +index 32ea6e19ca7f9aa65599c0cf296a8c5e73362271..c2dc254c8f3f56cb6ae4dc481781688aa702b102 100644 +--- a/src/sysv/systemd/sssd-autofs.service.in ++++ b/src/sysv/systemd/sssd-autofs.service.in +@@ -9,8 +9,9 @@ RefuseManualStart=true + Also=sssd-autofs.socket + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_autofs.log +-ExecStart=@libexecdir@/sssd/sssd_autofs --debug-to-files --socket-activated ++ExecStart=@libexecdir@/sssd/sssd_autofs ${DEBUG_LOGGER} --socket-activated + Restart=on-failure + User=@SSSD_USER@ + Group=@SSSD_USER@ +diff --git a/src/sysv/systemd/sssd-ifp.service.in b/src/sysv/systemd/sssd-ifp.service.in +index 8e7abdb0e8c5ec83f9423c688daf845a16c57e7e..05a9a602b2d27c54a4faa79c58e0ecba90267100 100644 +--- a/src/sysv/systemd/sssd-ifp.service.in ++++ b/src/sysv/systemd/sssd-ifp.service.in +@@ -5,7 +5,8 @@ After=sssd.service + BindsTo=sssd.service + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + Type=dbus + BusName=org.freedesktop.sssd.infopipe +-ExecStart=@ifp_exec_cmd@ ++ExecStart=@ifp_exec_cmd@ ${DEBUG_LOGGER} + @ifp_restart@ +diff --git a/src/sysv/systemd/sssd-kcm.service.in b/src/sysv/systemd/sssd-kcm.service.in +index 1e2bee12dc3bedd17d41b86f91c9b2b52d985c40..92306f97ec73a775739bfdb4454df14956e5e133 100644 +--- a/src/sysv/systemd/sssd-kcm.service.in ++++ b/src/sysv/systemd/sssd-kcm.service.in +@@ -6,4 +6,5 @@ Documentation=man:sssd-kcm(5) + Also=sssd-kcm.socket + + [Service] +-ExecStart=@libexecdir@/sssd/sssd_kcm --uid 0 --gid 0 --debug-to-files ++Environment=DEBUG_LOGGER=--logger=files ++ExecStart=@libexecdir@/sssd/sssd_kcm --uid 0 --gid 0 ${DEBUG_LOGGER} +diff --git a/src/sysv/systemd/sssd-nss.service.in b/src/sysv/systemd/sssd-nss.service.in +index 6a29078d5a36dff229e47bf7ce953e46443ce023..fe771ad0fa99968bb1d42037abf2f960271589b1 100644 +--- a/src/sysv/systemd/sssd-nss.service.in ++++ b/src/sysv/systemd/sssd-nss.service.in +@@ -9,5 +9,6 @@ RefuseManualStart=true + Also=sssd-nss.socket + + [Service] +-ExecStart=@libexecdir@/sssd/sssd_nss --debug-to-files --socket-activated ++Environment=DEBUG_LOGGER=--logger=files ++ExecStart=@libexecdir@/sssd/sssd_nss ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-pac.service.in b/src/sysv/systemd/sssd-pac.service.in +index ffbfdec030ba6d5cf75c989854c27bc46b6983a5..dbd25abc476f579c9d8cce171fdeafa06e567610 100644 +--- a/src/sysv/systemd/sssd-pac.service.in ++++ b/src/sysv/systemd/sssd-pac.service.in +@@ -9,8 +9,9 @@ RefuseManualStart=true + Also=sssd-pac.socket + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pac.log +-ExecStart=@libexecdir@/sssd/sssd_pac --debug-to-files --socket-activated ++ExecStart=@libexecdir@/sssd/sssd_pac ${DEBUG_LOGGER} --socket-activated + Restart=on-failure + User=@SSSD_USER@ + Group=@SSSD_USER@ +diff --git a/src/sysv/systemd/sssd-pam.service.in b/src/sysv/systemd/sssd-pam.service.in +index 6dec46f0c5d384c500268dafcd00af894088e0b6..df722d1f3014bf62cc60114c30331424d14f411b 100644 +--- a/src/sysv/systemd/sssd-pam.service.in ++++ b/src/sysv/systemd/sssd-pam.service.in +@@ -9,8 +9,9 @@ RefuseManualStart=true + Also=sssd-pam.socket sssd-pam-priv.socket + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pam.log +-ExecStart=@libexecdir@/sssd/sssd_pam --debug-to-files --socket-activated ++ExecStart=@libexecdir@/sssd/sssd_pam ${DEBUG_LOGGER} --socket-activated + Restart=on-failure + User=@SSSD_USER@ + Group=@SSSD_USER@ +diff --git a/src/sysv/systemd/sssd-secrets.service.in b/src/sysv/systemd/sssd-secrets.service.in +index f45d647677a62900c01c7eb103597f2b1387498c..a7b41e0b16a5fa882546b41047e616fd2140329f 100644 +--- a/src/sysv/systemd/sssd-secrets.service.in ++++ b/src/sysv/systemd/sssd-secrets.service.in +@@ -6,4 +6,5 @@ Documentation=man:sssd-secrets(5) + Also=sssd-secrets.socket + + [Service] +-ExecStart=@libexecdir@/sssd/sssd_secrets --uid 0 --gid 0 --debug-to-files ++Environment=DEBUG_LOGGER=--logger=files ++ExecStart=@libexecdir@/sssd/sssd_secrets --uid 0 --gid 0 ${DEBUG_LOGGER} +diff --git a/src/sysv/systemd/sssd-ssh.service.in b/src/sysv/systemd/sssd-ssh.service.in +index 6f233b4854018d79cc0ad9d67d53ebd67a49f7b7..f41249ea0fe19e5044d5d06ba195ab604d8e6a29 100644 +--- a/src/sysv/systemd/sssd-ssh.service.in ++++ b/src/sysv/systemd/sssd-ssh.service.in +@@ -9,8 +9,9 @@ RefuseManualStart=true + Also=sssd-ssh.socket + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_ssh.log +-ExecStart=@libexecdir@/sssd/sssd_ssh --debug-to-files --socket-activated ++ExecStart=@libexecdir@/sssd/sssd_ssh ${DEBUG_LOGGER} --socket-activated + Restart=on-failure + User=@SSSD_USER@ + Group=@SSSD_USER@ +diff --git a/src/sysv/systemd/sssd-sudo.service.in b/src/sysv/systemd/sssd-sudo.service.in +index b59bcbcd817c3986d7ee245b1083f90ff5a3775a..da022f768af91e360182fad0ff885fad43ecfdc0 100644 +--- a/src/sysv/systemd/sssd-sudo.service.in ++++ b/src/sysv/systemd/sssd-sudo.service.in +@@ -9,8 +9,9 @@ RefuseManualStart=true + Also=sssd-sudo.socket + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_sudo.log +-ExecStart=@libexecdir@/sssd/sssd_sudo --debug-to-files --socket-activated ++ExecStart=@libexecdir@/sssd/sssd_sudo --socket-activated + Restart=on-failure + User=@SSSD_USER@ + Group=@SSSD_USER@ +diff --git a/src/sysv/systemd/sssd.service.in b/src/sysv/systemd/sssd.service.in +index 05cfd3705084dbff8b46fb07e736612612c58b70..cea848fac80303d6fae12dd84316a91dbc60072d 100644 +--- a/src/sysv/systemd/sssd.service.in ++++ b/src/sysv/systemd/sssd.service.in +@@ -5,8 +5,9 @@ Before=systemd-user-sessions.service nss-user-lookup.target + Wants=nss-user-lookup.target + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + EnvironmentFile=-@environment_file@ +-ExecStart=@sbindir@/sssd -i -f ++ExecStart=@sbindir@/sssd -i ${DEBUG_LOGGER} + Type=notify + NotifyAccess=main + +-- +2.13.5 + diff --git a/SOURCES/0018-UTIL-Add-SAFEALIGN_COPY_UINT8_CHECK.patch b/SOURCES/0018-UTIL-Add-SAFEALIGN_COPY_UINT8_CHECK.patch deleted file mode 100644 index bb11f98..0000000 --- a/SOURCES/0018-UTIL-Add-SAFEALIGN_COPY_UINT8_CHECK.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 4aecf8a2d3962d962da1e2f98b0bb3b84a8ae536 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Thu, 23 Feb 2017 20:55:05 +0100 -Subject: [PATCH 18/36] UTIL: Add SAFEALIGN_COPY_UINT8_CHECK -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This macro will be used later in the KCM code - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/util/util_safealign.h | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/src/util/util_safealign.h b/src/util/util_safealign.h -index 0d9a579cdbfafc30bf2d0a6ad2651c71428ebd93..57f04a17d4a38300b959c1593d756b351ebd89e8 100644 ---- a/src/util/util_safealign.h -+++ b/src/util/util_safealign.h -@@ -130,6 +130,12 @@ safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter) - safealign_memcpy(dest, src, srclen, pctr); \ - } while(0) - -+#define SAFEALIGN_COPY_UINT8_CHECK(dest, src, len, pctr) do { \ -+ if ((*(pctr) + sizeof(uint8_t)) > (len) || \ -+ SIZE_T_OVERFLOW(*(pctr), sizeof(uint8_t))) { return EINVAL; } \ -+ safealign_memcpy(dest, src, sizeof(uint8_t), pctr); \ -+} while(0) -+ - /* Aliases for backward compatibility. */ - #define SAFEALIGN_SET_VALUE SAFEALIGN_SETMEM_VALUE - #define SAFEALIGN_SET_INT64 SAFEALIGN_SETMEM_INT64 --- -2.9.3 - diff --git a/SOURCES/0019-SYSTEMD-Add-environment-file-to-responder-service-fi.patch b/SOURCES/0019-SYSTEMD-Add-environment-file-to-responder-service-fi.patch new file mode 100644 index 0000000..060c43e --- /dev/null +++ b/SOURCES/0019-SYSTEMD-Add-environment-file-to-responder-service-fi.patch @@ -0,0 +1,107 @@ +From cc4f298024b2ef08cc0740ebbaf916bd494ef892 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 24 Oct 2017 12:15:48 +0200 +Subject: [PATCH 19/21] SYSTEMD: Add environment file to responder service + files +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 115145f0fb7507c1b9c5489bc77398d422a66875) +--- + src/sysv/systemd/sssd-autofs.service.in | 1 + + src/sysv/systemd/sssd-ifp.service.in | 1 + + src/sysv/systemd/sssd-nss.service.in | 1 + + src/sysv/systemd/sssd-pac.service.in | 1 + + src/sysv/systemd/sssd-pam.service.in | 1 + + src/sysv/systemd/sssd-ssh.service.in | 1 + + src/sysv/systemd/sssd-sudo.service.in | 1 + + 7 files changed, 7 insertions(+) + +diff --git a/src/sysv/systemd/sssd-autofs.service.in b/src/sysv/systemd/sssd-autofs.service.in +index c2dc254c8f3f56cb6ae4dc481781688aa702b102..7f920ad66a46bb0785c3f947bc26c15d0e370259 100644 +--- a/src/sysv/systemd/sssd-autofs.service.in ++++ b/src/sysv/systemd/sssd-autofs.service.in +@@ -10,6 +10,7 @@ Also=sssd-autofs.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_autofs.log + ExecStart=@libexecdir@/sssd/sssd_autofs ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-ifp.service.in b/src/sysv/systemd/sssd-ifp.service.in +index 05a9a602b2d27c54a4faa79c58e0ecba90267100..f3bf92223ce8847858f57c2bb04b97c858be0ead 100644 +--- a/src/sysv/systemd/sssd-ifp.service.in ++++ b/src/sysv/systemd/sssd-ifp.service.in +@@ -6,6 +6,7 @@ BindsTo=sssd.service + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + Type=dbus + BusName=org.freedesktop.sssd.infopipe + ExecStart=@ifp_exec_cmd@ ${DEBUG_LOGGER} +diff --git a/src/sysv/systemd/sssd-nss.service.in b/src/sysv/systemd/sssd-nss.service.in +index fe771ad0fa99968bb1d42037abf2f960271589b1..c671280f2c8a7f85fd09a72983a21db0c30df3b9 100644 +--- a/src/sysv/systemd/sssd-nss.service.in ++++ b/src/sysv/systemd/sssd-nss.service.in +@@ -10,5 +10,6 @@ Also=sssd-nss.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStart=@libexecdir@/sssd/sssd_nss ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-pac.service.in b/src/sysv/systemd/sssd-pac.service.in +index dbd25abc476f579c9d8cce171fdeafa06e567610..590449b01223fe799eebb12b63229dfb8f2438f9 100644 +--- a/src/sysv/systemd/sssd-pac.service.in ++++ b/src/sysv/systemd/sssd-pac.service.in +@@ -10,6 +10,7 @@ Also=sssd-pac.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pac.log + ExecStart=@libexecdir@/sssd/sssd_pac ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-pam.service.in b/src/sysv/systemd/sssd-pam.service.in +index df722d1f3014bf62cc60114c30331424d14f411b..f2e938579c7ef4254bb2e05231bfe83d7e20f395 100644 +--- a/src/sysv/systemd/sssd-pam.service.in ++++ b/src/sysv/systemd/sssd-pam.service.in +@@ -10,6 +10,7 @@ Also=sssd-pam.socket sssd-pam-priv.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pam.log + ExecStart=@libexecdir@/sssd/sssd_pam ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-ssh.service.in b/src/sysv/systemd/sssd-ssh.service.in +index f41249ea0fe19e5044d5d06ba195ab604d8e6a29..1c185466dfa8c13804cc980bbbdbc997d4ebe955 100644 +--- a/src/sysv/systemd/sssd-ssh.service.in ++++ b/src/sysv/systemd/sssd-ssh.service.in +@@ -10,6 +10,7 @@ Also=sssd-ssh.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_ssh.log + ExecStart=@libexecdir@/sssd/sssd_ssh ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-sudo.service.in b/src/sysv/systemd/sssd-sudo.service.in +index da022f768af91e360182fad0ff885fad43ecfdc0..f13d88107eccd9e80447390c9c0f8940ae933106 100644 +--- a/src/sysv/systemd/sssd-sudo.service.in ++++ b/src/sysv/systemd/sssd-sudo.service.in +@@ -10,6 +10,7 @@ Also=sssd-sudo.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_sudo.log + ExecStart=@libexecdir@/sssd/sssd_sudo --socket-activated + Restart=on-failure +-- +2.13.5 + diff --git a/SOURCES/0019-UTIL-Add-utility-macro-cli_creds_get_gid.patch b/SOURCES/0019-UTIL-Add-utility-macro-cli_creds_get_gid.patch deleted file mode 100644 index 84752b5..0000000 --- a/SOURCES/0019-UTIL-Add-utility-macro-cli_creds_get_gid.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 62acd53dc2880b23cfb221ce40537abfb6e011bb Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 20 Sep 2016 22:00:27 +0200 -Subject: [PATCH 19/36] UTIL: Add utility macro cli_creds_get_gid() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The KCM responder checks the owneship of the ccache based on both UID -and GID of the peer. In order to reuse the already existing creds -structure, let's just add a new macro that returns the GID from the -creds structure. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/util/util_creds.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/util/util_creds.h b/src/util/util_creds.h -index 65468fa12b8c6921859574c40f5759c936a10e86..936b9965d1ccd2b437d93b38d789b6f8389f47a6 100644 ---- a/src/util/util_creds.h -+++ b/src/util/util_creds.h -@@ -71,6 +71,7 @@ struct cli_creds { - }; - - #define cli_creds_get_uid(x) x->ucred.uid -+#define cli_creds_get_gid(x) x->ucred.gid - - #else /* not HAVE_UCRED */ - struct cli_creds { --- -2.9.3 - diff --git a/SOURCES/0020-UTIL-Add-type-specific-getsetters-to-sss_iobuf.patch b/SOURCES/0020-UTIL-Add-type-specific-getsetters-to-sss_iobuf.patch deleted file mode 100644 index 97c4775..0000000 --- a/SOURCES/0020-UTIL-Add-type-specific-getsetters-to-sss_iobuf.patch +++ /dev/null @@ -1,194 +0,0 @@ -From cef2ade5294bd9dc06f7eca26287c2e90e2c2ee1 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Thu, 23 Feb 2017 21:57:13 +0100 -Subject: [PATCH 20/36] UTIL: Add type-specific getsetters to sss_iobuf -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The KCM responder receives its input as unstructured data. To make the -parsing easier, this commit adds several type-specific getsetters to the -iobuf module. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/util/sss_iobuf.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++ - src/util/sss_iobuf.h | 33 ++++++++++++++++ - 2 files changed, 141 insertions(+) - -diff --git a/src/util/sss_iobuf.c b/src/util/sss_iobuf.c -index 900418b750a3455ebc2c3bb1893db726692260b8..fc288d2df2bfaaba393dd490d4da8976de804cb5 100644 ---- a/src/util/sss_iobuf.c -+++ b/src/util/sss_iobuf.c -@@ -184,6 +184,25 @@ errno_t sss_iobuf_read(struct sss_iobuf *iobuf, - return EOK; - } - -+errno_t sss_iobuf_read_len(struct sss_iobuf *iobuf, -+ size_t len, -+ uint8_t *_buf) -+{ -+ size_t read; -+ errno_t ret; -+ -+ ret = sss_iobuf_read(iobuf, len, _buf, &read); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ if (read != len) { -+ return ENOBUFS; -+ } -+ -+ return EOK; -+} -+ - errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf, - uint8_t *buf, - size_t len) -@@ -203,3 +222,92 @@ errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf, - - return EOK; - } -+ -+errno_t sss_iobuf_read_uint32(struct sss_iobuf *iobuf, -+ uint32_t *_val) -+{ -+ SAFEALIGN_COPY_UINT32_CHECK(_val, iobuf_ptr(iobuf), -+ iobuf->capacity, &iobuf->dp); -+ return EOK; -+} -+ -+errno_t sss_iobuf_read_int32(struct sss_iobuf *iobuf, -+ int32_t *_val) -+{ -+ SAFEALIGN_COPY_INT32_CHECK(_val, iobuf_ptr(iobuf), -+ iobuf->capacity, &iobuf->dp); -+ return EOK; -+} -+ -+errno_t sss_iobuf_write_uint32(struct sss_iobuf *iobuf, -+ uint32_t val) -+{ -+ errno_t ret; -+ -+ ret = ensure_bytes(iobuf, sizeof(uint32_t)); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ SAFEALIGN_SETMEM_UINT32(iobuf_ptr(iobuf), val, &iobuf->dp); -+ return EOK; -+} -+ -+errno_t sss_iobuf_write_int32(struct sss_iobuf *iobuf, -+ int32_t val) -+{ -+ errno_t ret; -+ -+ ret = ensure_bytes(iobuf, sizeof(int32_t)); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ SAFEALIGN_SETMEM_INT32(iobuf_ptr(iobuf), val, &iobuf->dp); -+ return EOK; -+} -+ -+errno_t sss_iobuf_read_stringz(struct sss_iobuf *iobuf, -+ const char **_out) -+{ -+ uint8_t *end; -+ size_t len; -+ -+ if (iobuf == NULL) { -+ return EINVAL; -+ } -+ -+ if (_out == NULL) { -+ return EINVAL; -+ } -+ -+ *_out = NULL; -+ -+ end = memchr(iobuf_ptr(iobuf), '\0', sss_iobuf_get_size(iobuf)); -+ if (end == NULL) { -+ return EINVAL; -+ } -+ -+ len = end + 1 - iobuf_ptr(iobuf); -+ if (sss_iobuf_get_size(iobuf) < len) { -+ return EINVAL; -+ } -+ -+ *_out = (const char *) iobuf_ptr(iobuf); -+ iobuf->dp += len; -+ return EOK; -+} -+ -+errno_t sss_iobuf_write_stringz(struct sss_iobuf *iobuf, -+ const char *str) -+{ -+ if (iobuf == NULL || str == NULL) { -+ return EINVAL; -+ } -+ -+ SAFEALIGN_MEMCPY_CHECK(iobuf_ptr(iobuf), -+ str, strlen(str)+1, -+ sss_iobuf_get_size(iobuf), -+ &iobuf->dp); -+ return EOK; -+} -diff --git a/src/util/sss_iobuf.h b/src/util/sss_iobuf.h -index 900faaa212230f72f52e344c085167e80ae2b465..cc3dfd1e98eeb49b979ac321bd0253bffa8a6dff 100644 ---- a/src/util/sss_iobuf.h -+++ b/src/util/sss_iobuf.h -@@ -96,6 +96,22 @@ errno_t sss_iobuf_read(struct sss_iobuf *iobuf, - size_t *_read); - - /* -+ * @brief Read an exact number of bytes from an IO buffer -+ * -+ * Read exactly len bytes from an IO buffer. If the buffer contains fewer -+ * bytes than len, ENOBUFS is returned. -+ * -+ * @param[in] iobuf The IO buffer to read from -+ * @param[in] len The maximum number of bytes to read -+ * @param[out] _buf The buffer to read data into from iobuf -+ * -+ * @return EOK on success, errno otherwise -+ */ -+errno_t sss_iobuf_read_len(struct sss_iobuf *iobuf, -+ size_t len, -+ uint8_t *_buf); -+ -+/* - * @brief Write into an IO buffer - * - * Attempts to write len bytes into the iobuf. If the capacity is exceeded, -@@ -115,4 +131,21 @@ errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf, - uint8_t *buf, - size_t len); - -+errno_t sss_iobuf_read_uint32(struct sss_iobuf *iobuf, -+ uint32_t *_val); -+ -+errno_t sss_iobuf_write_uint32(struct sss_iobuf *iobuf, -+ uint32_t val); -+ -+errno_t sss_iobuf_read_int32(struct sss_iobuf *iobuf, -+ int32_t *_val); -+ -+errno_t sss_iobuf_write_int32(struct sss_iobuf *iobuf, -+ int32_t val); -+ -+errno_t sss_iobuf_read_stringz(struct sss_iobuf *iobuf, -+ const char **_out); -+ -+errno_t sss_iobuf_write_stringz(struct sss_iobuf *iobuf, -+ const char *str); - #endif /* __SSS_IOBUF_H_ */ --- -2.9.3 - diff --git a/SOURCES/0020-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch b/SOURCES/0020-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch new file mode 100644 index 0000000..8ade838 --- /dev/null +++ b/SOURCES/0020-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch @@ -0,0 +1,47 @@ +From 65e47ac92a16c57058b955fe9ec2e17b838a37db Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 24 Oct 2017 12:07:46 +0200 +Subject: [PATCH 20/21] UTIL: Hide and deprecate parameter --debug-to-files +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Justin Stephenson +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 18a47bcc463c866de6b6b0327e6d85ceb1e0f7d6) +--- + src/man/sssd.8.xml | 4 ++++ + src/util/debug.h | 2 +- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/man/sssd.8.xml b/src/man/sssd.8.xml +index 0b725628ff93f48f832140dd5dc15b040a8b179f..f2cbe015b844579af98aebd864770bc651dcf4b1 100644 +--- a/src/man/sssd.8.xml ++++ b/src/man/sssd.8.xml +@@ -90,6 +90,10 @@ + log files are stored in /var/log/sssd and + there are separate log files for every SSSD service and domain. + ++ ++ This option is deprecated. It is replaced by ++ . ++ + + + +diff --git a/src/util/debug.h b/src/util/debug.h +index 4adafb7cfc03f7381c4d03071eb44edad04bee00..09f50cc9f3122f02d8ba2092dfb7ee633332de9b 100644 +--- a/src/util/debug.h ++++ b/src/util/debug.h +@@ -101,7 +101,7 @@ int get_fd_from_debug_file(void); + #define SSSD_DEBUG_OPTS \ + {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0, \ + _("Debug level"), NULL}, \ +- {"debug-to-files", 'f', POPT_ARG_NONE, &debug_to_file, 0, \ ++ {"debug-to-files", 'f', POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_file, 0, \ + _("Send the debug output to files instead of stderr"), NULL }, \ + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \ + _("Send the debug output to stderr directly."), NULL }, \ +-- +2.13.5 + diff --git a/SOURCES/0021-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch b/SOURCES/0021-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch new file mode 100644 index 0000000..6f138f1 --- /dev/null +++ b/SOURCES/0021-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch @@ -0,0 +1,213 @@ +From 7ebfab326f94e508ce2910c7242a8dd7652ec8a2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 25 Oct 2017 11:25:09 +0200 +Subject: [PATCH 21/21] LDAP: Bind to the LDAP server also in the auth +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When dealing with id_provider not being the same as auth_provider, SSSD +has to bind the DN of the user which wants to authenticate with the +ldap_default_bind_dn and the password provided by the user. + +In order to do so, the least intrusive way is just by replacing +sdap_connect*() functions by sdap_cli_connect*() functions in the LDAP's +auth module. + +The simple change also allowed us to remove some code that is already +executed as part of sdap_cli_connect*() and some functions had their +names adapted to reflect better their new purpose. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3451 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Sumit Bose +(cherry picked from commit add72860c7a7a2c418f4d8b6790b5caeaf7dfb7b) +--- + src/providers/ldap/ldap_auth.c | 114 +++++++++-------------------------------- + 1 file changed, 25 insertions(+), 89 deletions(-) + +diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c +index 00ddd889b6294e457c13218491547b84f1468266..a3b1480aae4272d2e10f105a1eaf3a5816c3487c 100644 +--- a/src/providers/ldap/ldap_auth.c ++++ b/src/providers/ldap/ldap_auth.c +@@ -619,14 +619,11 @@ struct auth_state { + char *dn; + enum pwexpire pw_expire_type; + void *pw_expire_data; +- +- struct fo_server *srv; + }; + +-static struct tevent_req *auth_get_server(struct tevent_req *req); ++static struct tevent_req *auth_connect_send(struct tevent_req *req); + static void auth_get_dn_done(struct tevent_req *subreq); + static void auth_do_bind(struct tevent_req *req); +-static void auth_resolve_done(struct tevent_req *subreq); + static void auth_connect_done(struct tevent_req *subreq); + static void auth_bind_user_done(struct tevent_req *subreq); + +@@ -659,7 +656,6 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, + state->ctx = ctx; + state->username = username; + state->authtok = authtok; +- state->srv = NULL; + if (try_chpass_service && ctx->chpass_service != NULL && + ctx->chpass_service->name != NULL) { + state->sdap_service = ctx->chpass_service; +@@ -667,7 +663,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, + state->sdap_service = ctx->service; + } + +- if (!auth_get_server(req)) goto fail; ++ if (!auth_connect_send(req)) goto fail; + + return req; + +@@ -676,75 +672,37 @@ fail: + return NULL; + } + +-static struct tevent_req *auth_get_server(struct tevent_req *req) ++static struct tevent_req *auth_connect_send(struct tevent_req *req) + { +- struct tevent_req *next_req; ++ struct tevent_req *subreq; + struct auth_state *state = tevent_req_data(req, + struct auth_state); +- +- /* NOTE: this call may cause service->uri to be refreshed +- * with a new valid server. Do not use service->uri before */ +- next_req = be_resolve_server_send(state, +- state->ev, +- state->ctx->be, +- state->sdap_service->name, +- state->srv == NULL ? true : false); +- if (!next_req) { +- DEBUG(SSSDBG_CRIT_FAILURE, "be_resolve_server_send failed.\n"); +- return NULL; +- } +- +- tevent_req_set_callback(next_req, auth_resolve_done, req); +- return next_req; +-} +- +-static void auth_resolve_done(struct tevent_req *subreq) +-{ +- struct tevent_req *req = tevent_req_callback_data(subreq, +- struct tevent_req); +- struct auth_state *state = tevent_req_data(req, +- struct auth_state); +- int ret; + bool use_tls; + +- ret = be_resolve_server_recv(subreq, state, &state->srv); +- talloc_zfree(subreq); +- if (ret) { +- /* all servers have been tried and none +- * was found good, go offline */ +- tevent_req_error(req, ETIMEDOUT); +- return; ++ /* Check for undocumented debugging feature to disable TLS ++ * for authentication. This should never be used in production ++ * for obvious reasons. ++ */ ++ use_tls = !dp_opt_get_bool(state->ctx->opts->basic, SDAP_DISABLE_AUTH_TLS); ++ if (!use_tls) { ++ sss_log(SSS_LOG_ALERT, "LDAP authentication being performed over " ++ "insecure connection. This should be done " ++ "for debugging purposes only."); + } + +- /* Determine whether we need to use TLS */ +- if (sdap_is_secure_uri(state->ctx->service->uri)) { +- DEBUG(SSSDBG_TRACE_INTERNAL, +- "[%s] is a secure channel. No need to run START_TLS\n", +- state->ctx->service->uri); +- use_tls = false; +- } else { ++ subreq = sdap_cli_connect_send(state, state->ev, state->ctx->opts, ++ state->ctx->be, ++ state->sdap_service, false, ++ use_tls ? CON_TLS_ON : CON_TLS_OFF, false); + +- /* Check for undocumented debugging feature to disable TLS +- * for authentication. This should never be used in production +- * for obvious reasons. +- */ +- use_tls = !dp_opt_get_bool(state->ctx->opts->basic, SDAP_DISABLE_AUTH_TLS); +- if (!use_tls) { +- sss_log(SSS_LOG_ALERT, "LDAP authentication being performed over " +- "insecure connection. This should be done " +- "for debugging purposes only."); +- } +- } +- +- subreq = sdap_connect_send(state, state->ev, state->ctx->opts, +- state->sdap_service->uri, +- state->sdap_service->sockaddr, use_tls); +- if (!subreq) { ++ if (subreq == NULL) { + tevent_req_error(req, ENOMEM); +- return; ++ return NULL; + } + + tevent_req_set_callback(subreq, auth_connect_done, req); ++ ++ return subreq; + } + + static void auth_connect_done(struct tevent_req *subreq) +@@ -755,35 +713,13 @@ static void auth_connect_done(struct tevent_req *subreq) + struct auth_state); + int ret; + +- ret = sdap_connect_recv(subreq, state, &state->sh); ++ ret = sdap_cli_connect_recv(subreq, state, NULL, &state->sh, NULL); + talloc_zfree(subreq); +- if (ret) { +- if (state->srv) { +- /* mark this server as bad if connection failed */ +- be_fo_set_port_status(state->ctx->be, +- state->sdap_service->name, +- state->srv, PORT_NOT_WORKING); +- } +- +- if (auth_get_server(req) == NULL) { ++ if (ret != EOK) { ++ if (auth_connect_send(req) == NULL) { + tevent_req_error(req, ENOMEM); + } + return; +- } else if (state->srv) { +- be_fo_set_port_status(state->ctx->be, state->sdap_service->name, +- state->srv, PORT_WORKING); +- } +- +- /* In case the ID provider is set to proxy, this might be the first +- * LDAP operation at all, so we need to set the connection status +- */ +- if (state->sh->connected == false) { +- ret = sdap_set_connected(state->sh, state->ev); +- if (ret) { +- DEBUG(SSSDBG_OP_FAILURE, "Cannot set connected status\n"); +- tevent_req_error(req, ret); +- return; +- } + } + + ret = get_user_dn(state, state->ctx->be->domain, +@@ -870,7 +806,7 @@ static void auth_bind_user_done(struct tevent_req *subreq) + break; + case ETIMEDOUT: + case ERR_NETWORK_IO: +- if (auth_get_server(req) == NULL) { ++ if (auth_connect_send(req) == NULL) { + tevent_req_error(req, ENOMEM); + } + return; +-- +2.13.5 + diff --git a/SOURCES/0021-UTIL-krb5-principal-un-marshalling.patch b/SOURCES/0021-UTIL-krb5-principal-un-marshalling.patch deleted file mode 100644 index c088f68..0000000 --- a/SOURCES/0021-UTIL-krb5-principal-un-marshalling.patch +++ /dev/null @@ -1,262 +0,0 @@ -From aa309f35905951c6fdd12d286bb3aeeb61a62088 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 20 Sep 2016 22:03:30 +0200 -Subject: [PATCH 21/36] UTIL: krb5 principal (un)marshalling -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The KCM responder needs to read the contents of the principal blob that -the Kerberos library sends. Since libkrb5 doesn't export any API to do -so, we need to implement marshalling and unmarshalling of the principal -ourselves. - -In future, when the KCM server also supports renewals, we will also need -to unmarshall the credentials, but until that is not really needed, the -credentials will be stored as a blob. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/util/sss_krb5.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++ - src/util/sss_krb5.h | 9 +++ - 2 files changed, 204 insertions(+) - -diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c -index 4808a7703d07bb4eba91f14a7a515aadaec1774b..d461cf881566af37f31524c16f6a5f1511a5dc89 100644 ---- a/src/util/sss_krb5.c -+++ b/src/util/sss_krb5.c -@@ -24,6 +24,7 @@ - - #include "config.h" - -+#include "util/sss_iobuf.h" - #include "util/util.h" - #include "util/sss_krb5.h" - -@@ -1128,3 +1129,197 @@ done: - - return res; - } -+ -+static errno_t iobuf_read_uint32be(struct sss_iobuf *iobuf, -+ uint32_t *_val) -+{ -+ uint32_t beval; -+ errno_t ret; -+ -+ ret = sss_iobuf_read_uint32(iobuf, &beval); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ *_val = be32toh(beval); -+ return EOK; -+} -+ -+static errno_t iobuf_write_uint32be(struct sss_iobuf *iobuf, -+ uint32_t val) -+{ -+ uint32_t beval; -+ -+ beval = htobe32(val); -+ return sss_iobuf_write_uint32(iobuf, beval); -+} -+ -+static errno_t iobuf_get_len_bytes(TALLOC_CTX *mem_ctx, -+ struct sss_iobuf *iobuf, -+ uint32_t *_nbytes, -+ uint8_t **_bytes) -+{ -+ errno_t ret; -+ uint32_t nbytes; -+ uint8_t *bytes = NULL; -+ -+ ret = iobuf_read_uint32be(iobuf, &nbytes); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ bytes = talloc_zero_size(mem_ctx, nbytes); -+ if (bytes == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = sss_iobuf_read_len(iobuf, nbytes, bytes); -+ if (ret != EOK) { -+ talloc_free(bytes); -+ return ret; -+ } -+ -+ *_bytes = bytes; -+ *_nbytes = nbytes; -+ return EOK; -+} -+ -+static errno_t get_krb5_data(TALLOC_CTX *mem_ctx, -+ struct sss_iobuf *iobuf, -+ krb5_data *k5data) -+{ -+ errno_t ret; -+ uint32_t nbytes; -+ uint8_t *bytes = NULL; -+ -+ ret = iobuf_get_len_bytes(mem_ctx, iobuf, &nbytes, &bytes); -+ if (ret != EOK) { -+ talloc_free(bytes); -+ return ret; -+ } -+ -+ k5data->data = (char *) bytes; /* FIXME - the cast is ugly */ -+ k5data->length = nbytes; -+ return EOK; -+} -+ -+static errno_t set_krb5_data(struct sss_iobuf *iobuf, -+ krb5_data *k5data) -+{ -+ errno_t ret; -+ -+ ret = iobuf_write_uint32be(iobuf, k5data->length); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ if (k5data->length > 0) { -+ ret = sss_iobuf_write_len(iobuf, -+ (uint8_t *) k5data->data, -+ k5data->length); -+ if (ret != EOK) { -+ return ret; -+ } -+ } -+ -+ return EOK; -+} -+ -+/* FIXME - it would be nice if Kerberos exported these APIs.. */ -+krb5_error_code sss_krb5_unmarshal_princ(TALLOC_CTX *mem_ctx, -+ struct sss_iobuf *iobuf, -+ krb5_principal *_princ) -+{ -+ krb5_principal princ = NULL; -+ krb5_error_code ret; -+ uint32_t ncomps; -+ -+ if (iobuf == NULL || _princ == NULL) { -+ return EINVAL; -+ } -+ -+ princ = talloc_zero(mem_ctx, struct krb5_principal_data); -+ if (princ == NULL) { -+ return ENOMEM; -+ } -+ -+ princ->magic = KV5M_PRINCIPAL; -+ -+ ret = iobuf_read_uint32be(iobuf, (uint32_t *) &princ->type); -+ if (ret != EOK) { -+ goto fail; -+ } -+ -+ ret = iobuf_read_uint32be(iobuf, &ncomps); -+ if (ret != EOK) { -+ goto fail; -+ } -+ -+ if (ncomps > sss_iobuf_get_capacity(iobuf)) { -+ /* Sanity check to avoid large allocations */ -+ ret = EINVAL; -+ goto fail; -+ } -+ -+ if (ncomps != 0) { -+ princ->data = talloc_zero_array(princ, krb5_data, ncomps); -+ if (princ->data == NULL) { -+ ret = ENOMEM; -+ goto fail; -+ } -+ -+ princ->length = ncomps; -+ } -+ -+ ret = get_krb5_data(princ, iobuf, &princ->realm); -+ if (ret != EOK) { -+ goto fail; -+ } -+ -+ for (size_t i = 0; i < ncomps; i++) { -+ ret = get_krb5_data(princ->data, iobuf, &princ->data[i]); -+ if (ret != EOK) { -+ goto fail; -+ } -+ } -+ -+ *_princ = princ; -+ return 0; -+ -+fail: -+ talloc_free(princ); -+ return ret; -+} -+ -+krb5_error_code sss_krb5_marshal_princ(krb5_principal princ, -+ struct sss_iobuf *iobuf) -+{ -+ krb5_error_code ret; -+ -+ if (iobuf == NULL || princ == NULL) { -+ return EINVAL; -+ } -+ -+ ret = iobuf_write_uint32be(iobuf, princ->type); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ ret = iobuf_write_uint32be(iobuf, princ->length); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ ret = set_krb5_data(iobuf, &princ->realm); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ for (int i = 0; i < princ->length; i++) { -+ ret = set_krb5_data(iobuf, &princ->data[i]); -+ if (ret != EOK) { -+ return ret; -+ } -+ } -+ return EOK; -+} -diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h -index ac0f6082c75a8878f72346733e592b7575d44089..0d9043be98749b1a21a1b74c68f07298fa27f230 100644 ---- a/src/util/sss_krb5.h -+++ b/src/util/sss_krb5.h -@@ -32,6 +32,7 @@ - #include - #endif - -+#include "util/sss_iobuf.h" - #include "util/util.h" - - #define KRB5_CHILD_LOG_FILE "krb5_child" -@@ -186,4 +187,12 @@ krb5_error_code sss_krb5_kt_have_content(krb5_context context, - krb5_keytab keytab); - - bool sss_krb5_realm_has_proxy(const char *realm); -+ -+krb5_error_code sss_krb5_marshal_princ(krb5_principal princ, -+ struct sss_iobuf *iobuf); -+ -+krb5_error_code sss_krb5_unmarshal_princ(TALLOC_CTX *mem_ctx, -+ struct sss_iobuf *iobuf, -+ krb5_principal *_princ); -+ - #endif /* __SSS_KRB5_H__ */ --- -2.9.3 - diff --git a/SOURCES/0022-KCM-Initial-responder-build-and-packaging.patch b/SOURCES/0022-KCM-Initial-responder-build-and-packaging.patch deleted file mode 100644 index c2ba5a6..0000000 --- a/SOURCES/0022-KCM-Initial-responder-build-and-packaging.patch +++ /dev/null @@ -1,1013 +0,0 @@ -From 8cb263f039da9e616e907d25701593dca22b11ed Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 1 Aug 2016 12:52:07 +0200 -Subject: [PATCH 22/36] KCM: Initial responder build and packaging -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Adds the initial build of the Kerberos Cache Manager responder (KCM). - -This is a deamon that is capable of holding and storing Kerberos -ccaches. When KCM is used, the kerberos libraries (invoked through e.g. -kinit) are referred to as a 'client' and the KCM deamon is referred to -as 'server'. - -At the moment, only the Heimdal implementation of Kerberos implements the -KCM server: - https://www.h5l.org/manual/HEAD/info/heimdal/Credential-cache-server-_002d-KCM.html -This patch adds a KCM server to SSSD. - -In MIT, only the 'client-side' support was added: - http://k5wiki.kerberos.org/wiki/Projects/KCM_client -This page also describes the protocol between the client and the server. - -The client is capable of talking to the server over either UNIX sockets -(Linux, most Unixes) or Mach RPC (macOS). Our server only implements the -UNIX sockets way and should be socket-activated by systemd, although can -in theory be also ran explicitly. - -The KCM server only builds if the configuration option "--with-kcm" is -enabled. It is packaged in a new subpackage sssd-kcm in order to allow -distributions to enable the KCM credential caches by installing this -subpackage only, without the rest of the SSSD. The sssd-kcm subpackage -also includes a krb5.conf.d snippet that allows the admin to just uncomment -the KCM defaults and instructs them to start the socket. - -The server can be configured in sssd.conf in the "[kcm]" section. -By default, the server only listens on the same socket path the Heimdal -server uses, which is "/var/run/.heim_org.h5l.kcm-socket". This is, -however, configurable. - -The file src/responder/kcm/kcm.h is more or less directly imported from -the MIT Kerberos tree, with an additional sentinel code and some -comments. Not all KCM operations are implemented, only those that also -the MIT client implements. That said, this KCM server should also be -usable with a Heimdal client, although no special testing was with this -hybrid. - -The patch also adds several error codes that will be used in later -patches. - -Related to: - https://pagure.io/SSSD/sssd/issue/2887 - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - Makefile.am | 53 ++++++++ - configure.ac | 10 +- - contrib/kcm_default_ccache | 12 ++ - contrib/sssd.spec.in | 41 ++++++ - src/conf_macros.m4 | 16 +++ - src/confdb/confdb.h | 3 + - src/config/cfg_rules.ini | 19 +++ - src/external/libcurl.m4 | 6 +- - src/responder/kcm/kcm.c | 254 +++++++++++++++++++++++++++++++++++ - src/responder/kcm/kcm.h | 97 +++++++++++++ - src/responder/kcm/kcmsrv_cmd.c | 65 +++++++++ - src/responder/kcm/kcmsrv_pvt.h | 58 ++++++++ - src/sysv/systemd/sssd-kcm.service.in | 9 ++ - src/sysv/systemd/sssd-kcm.socket.in | 10 ++ - src/util/util_errors.c | 5 + - src/util/util_errors.h | 5 + - 16 files changed, 658 insertions(+), 5 deletions(-) - create mode 100644 contrib/kcm_default_ccache - create mode 100644 src/responder/kcm/kcm.c - create mode 100644 src/responder/kcm/kcm.h - create mode 100644 src/responder/kcm/kcmsrv_cmd.c - create mode 100644 src/responder/kcm/kcmsrv_pvt.h - create mode 100644 src/sysv/systemd/sssd-kcm.service.in - create mode 100644 src/sysv/systemd/sssd-kcm.socket.in - -diff --git a/Makefile.am b/Makefile.am -index 7516338bc6fd95045d20db8155a0c82fd7003358..4248536e90370c1aab59549a9c18408ef314e6d4 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -87,6 +87,7 @@ sudolibdir = @sudolibpath@ - polkitdir = @polkitdir@ - pamconfdir = $(sysconfdir)/pam.d - systemtap_tapdir = @tapset_dir@ -+krb5sysincludedir = $(sysconfdir)/krb5.conf.d - - if HAVE_SYSTEMD_UNIT - ifp_exec_cmd = $(sssdlibexecdir)/sssd_ifp --uid 0 --gid 0 --debug-to-files --dbus-activated -@@ -186,6 +187,11 @@ endif - if BUILD_SECRETS - sssdlibexec_PROGRAMS += sssd_secrets - endif -+if BUILD_KCM -+sssdlibexec_PROGRAMS += sssd_kcm -+dist_krb5sysinclude_DATA = contrib/kcm_default_ccache -+endif -+ - - if BUILD_PAC_RESPONDER - sssdlibexec_PROGRAMS += sssd_pac -@@ -703,6 +709,8 @@ dist_noinst_HEADERS = \ - src/responder/secrets/secsrv_private.h \ - src/responder/secrets/secsrv_local.h \ - src/responder/secrets/secsrv_proxy.h \ -+ src/responder/kcm/kcm.h \ -+ src/responder/kcm/kcmsrv_pvt.h \ - src/sbus/sbus_client.h \ - src/sbus/sssd_dbus.h \ - src/sbus/sssd_dbus_meta.h \ -@@ -1476,6 +1484,24 @@ sssd_secrets_LDADD = \ - $(NULL) - endif - -+if BUILD_KCM -+sssd_kcm_SOURCES = \ -+ src/responder/kcm/kcm.c \ -+ src/responder/kcm/kcmsrv_cmd.c \ -+ src/util/sss_sockets.c \ -+ $(SSSD_RESPONDER_OBJ) \ -+ $(NULL) -+sssd_kcm_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(KRB5_CFLAGS) \ -+ $(NULL) -+sssd_kcm_LDADD = \ -+ $(KRB5_LIBS) \ -+ $(SSSD_LIBS) \ -+ $(SSSD_INTERNAL_LTLIBS) \ -+ $(NULL) -+endif -+ - sssd_be_SOURCES = \ - src/providers/data_provider_be.c \ - src/providers/data_provider_req.c \ -@@ -4259,6 +4285,12 @@ if BUILD_SUDO - src/sysv/systemd/sssd-sudo.service \ - $(NULL) - endif -+if BUILD_KCM -+ systemdunit_DATA += \ -+ src/sysv/systemd/sssd-kcm.socket \ -+ src/sysv/systemd/sssd-kcm.service \ -+ $(NULL) -+endif - if WITH_JOURNALD - systemdconf_DATA += \ - src/sysv/systemd/journal.conf -@@ -4350,6 +4382,12 @@ EXTRA_DIST += \ - src/sysv/systemd/sssd-sudo.service.in \ - $(NULL) - endif -+if BUILD_KCM -+EXTRA_DIST += \ -+ src/sysv/systemd/sssd-kcm.socket.in \ -+ src/sysv/systemd/sssd-kcm.service.in \ -+ $(NULL) -+endif - - src/sysv/systemd/sssd.service: src/sysv/systemd/sssd.service.in Makefile - @$(MKDIR_P) src/sysv/systemd/ -@@ -4433,6 +4471,16 @@ src/sysv/systemd/sssd-sudo.service: src/sysv/systemd/sssd-sudo.service.in Makefi - $(replace_script) - endif - -+if BUILD_KCM -+src/sysv/systemd/sssd-kcm.socket: src/sysv/systemd/sssd-kcm.socket.in Makefile -+ @$(MKDIR_P) src/sysv/systemd/ -+ $(replace_script) -+ -+src/sysv/systemd/sssd-kcm.service: src/sysv/systemd/sssd-kcm.service.in Makefile -+ @$(MKDIR_P) src/sysv/systemd/ -+ $(replace_script) -+endif -+ - SSSD_USER_DIRS = \ - $(DESTDIR)$(dbpath) \ - $(DESTDIR)$(keytabdir) \ -@@ -4596,6 +4644,9 @@ install-data-hook: - if BUILD_SAMBA - mv $(DESTDIR)/$(winbindplugindir)/winbind_idmap_sss.so $(DESTDIR)/$(winbindplugindir)/sss.so - endif -+if BUILD_KCM -+ $(MKDIR_P) $(DESTDIR)/$(krb5sysincludedir) -+endif - - uninstall-hook: - if [ -f $(abs_builddir)/src/config/.files2 ]; then \ -@@ -4670,6 +4721,8 @@ endif - rm -f $(builddir)/src/sysv/systemd/sssd-sudo.service - rm -f $(builddir)/src/sysv/systemd/sssd-secrets.socket - rm -f $(builddir)/src/sysv/systemd/sssd-secrets.service -+ rm -f $(builddir)/src/sysv/systemd/sssd-kcm.socket -+ rm -f $(builddir)/src/sysv/systemd/sssd-kcm.service - rm -f $(builddir)/src/sysv/systemd/journal.conf - - CLEANFILES += *.X */*.X */*/*.X -diff --git a/configure.ac b/configure.ac -index dd1012015a5fea9f25e5b5199b4868fbc0bc14c4..c363d48a806cc1998e85779a92b6b59b0e2a5c9c 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -155,6 +155,7 @@ WITH_SSSD_USER - SSSD_RUNSTATEDIR - WITH_SECRETS - WITH_SECRETS_DB_PATH -+WITH_KCM - - m4_include([src/external/pkg.m4]) - m4_include([src/external/libpopt.m4]) -@@ -193,13 +194,20 @@ m4_include([src/external/libresolv.m4]) - m4_include([src/external/intgcheck.m4]) - m4_include([src/external/systemtap.m4]) - m4_include([src/external/service.m4]) --m4_include([src/external/libcurl.m4]) - - if test x$with_secrets = xyes; then - m4_include([src/external/libhttp_parser.m4]) - m4_include([src/external/libjansson.m4]) - fi - -+if test x$with_kcm = xyes; then -+ m4_include([src/external/libcurl.m4]) -+fi -+# This variable is defined by external/libcurl.m4, but conditionals -+# must be always evaluated -+AM_CONDITIONAL([BUILD_WITH_LIBCURL], -+ [test x"$have_curlopt_unix_sockpath" = xyes]) -+ - WITH_UNICODE_LIB - if test x$unicode_lib = xlibunistring; then - m4_include([src/external/libunistring.m4]) -diff --git a/contrib/kcm_default_ccache b/contrib/kcm_default_ccache -new file mode 100644 -index 0000000000000000000000000000000000000000..ac88fca86b60b19f772912b5d9d14595a96d101d ---- /dev/null -+++ b/contrib/kcm_default_ccache -@@ -0,0 +1,12 @@ -+# This file should normally be installed by your distribution into a -+# directory that is included from the Kerberos configuration file (/etc/krb5.conf) -+# On Fedora/RHEL/CentOS, this is /etc/krb5.conf.d/ -+# -+# To enable the KCM credential cache, uncomment the following lines and -+# enable the KCM socket and the service: -+# systemctl enable sssd-kcm.socket -+# systemctl start sssd-kcm.socket -+# systemctl enable sssd-kcm.service -+ -+#[libdefaults] -+# default_ccache_name = KCM: -diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in -index 28ebe07a26a3112210b092b7831e7f6aae061c8d..5c7c2af521a84ef2ca6cca7b2d6cd1f9b3057056 100644 ---- a/contrib/sssd.spec.in -+++ b/contrib/sssd.spec.in -@@ -112,6 +112,13 @@ - %global enable_systemtap_opt --enable-systemtap - %endif - -+%if (0%{?fedora} >= 23 || 0%{?rhel} >= 7) -+ %global with_kcm 1 -+ %global with_kcm_option --with-kcm -+%else -+ %global with_kcm_option --without-kcm -+%endif -+ - Name: @PACKAGE_NAME@ - Version: @PACKAGE_VERSION@ - Release: 0@PRERELEASE_VERSION@%{?dist} -@@ -677,6 +684,18 @@ Requires: libsss_certmap = %{version}-%{release} - %description -n libsss_certmap-devel - Library to map certificates to users based on rules - -+%if (0%{?with_kcm} == 1) -+%package kcm -+Summary: An implementation of a Kerberos KCM server -+Group: Applications/System -+License: GPLv3+ -+Requires: sssd-common = %{version}-%{release} -+ -+%description kcm -+An implementation of a Kerberos KCM server. Use this package if you want to -+use the KCM: Kerberos credentials cache. -+%endif -+ - %prep - %setup -q -n %{name}-%{version} - -@@ -706,6 +725,7 @@ autoreconf -ivf - %{?with_python3_option} \ - %{?enable_polkit_rules_option} \ - %{?enable_systemtap_opt} \ -+ %{?with_kcm_option} \ - %{?experimental} - - make %{?_smp_mflags} all -@@ -1178,6 +1198,15 @@ done - %{_libdir}/libsss_certmap.so - %{_libdir}/pkgconfig/sss_certmap.pc - -+%if (0%{?with_kcm} == 1) -+%files kcm -+%{_libexecdir}/%{servicename}/sssd_kcm -+%dir %{_sysconfdir}/krb5.conf.d -+%config(noreplace) %{_sysconfdir}/krb5.conf.d/kcm_default_ccache -+%{_unitdir}/sssd-kcm.socket -+%{_unitdir}/sssd-kcm.service -+%endif -+ - %pre common - getent group sssd >/dev/null || groupadd -r sssd - getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd -@@ -1274,6 +1303,18 @@ fi - - %postun -n libsss_simpleifp -p /sbin/ldconfig - -+%if (0%{?with_kcm} == 1) -+%post kcm -+%systemd_post sssd-kcm.socket -+ -+%preun kcm -+%systemd_preun sssd-kcm.socket -+ -+%postun kcm -+%systemd_postun_with_restart sssd-kcm.socket -+%systemd_postun_with_restart sssd-kcm.service -+%endif -+ - %changelog - * Mon Mar 15 2010 Stephen Gallagher - @PACKAGE_VERSION@-0@PRERELEASE_VERSION@ - - Automated build of the SSSD -diff --git a/src/conf_macros.m4 b/src/conf_macros.m4 -index 749e7694f4dd7086468e461194ef274be2094236..420997229cb3c244afd8fb21b074e43a21de0eda 100644 ---- a/src/conf_macros.m4 -+++ b/src/conf_macros.m4 -@@ -887,6 +887,22 @@ AC_DEFUN([WITH_SECRETS], - AM_CONDITIONAL([BUILD_SECRETS], [test x"$with_secrets" = xyes]) - ]) - -+AC_DEFUN([WITH_KCM], -+ [ AC_ARG_WITH([kcm], -+ [AC_HELP_STRING([--with-kcm], -+ [Whether to build with KCM server support [yes]] -+ ) -+ ], -+ [with_kcm=$withval], -+ with_kcm=yes -+ ) -+ -+ if test x"$with_kcm" = xyes; then -+ AC_DEFINE(BUILD_KCM, 1, [whether to build with KCM server support]) -+ fi -+ AM_CONDITIONAL([BUILD_KCM], [test x"$with_kcm" = xyes]) -+ ]) -+ - AC_DEFUN([WITH_SECRETS_DB_PATH], - [ AC_ARG_WITH([secrets-db-path], - [AC_HELP_STRING([--with-secrets-db-path=PATH], -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index c05b1cee45ece748bf8e2b1e1ecf3dc28979e48b..c443e869a7a6782265b42c4ad122867c4e3dd8e0 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -231,6 +231,9 @@ - #define CONFDB_SEC_MAX_SECRETS "max_secrets" - #define CONFDB_SEC_MAX_PAYLOAD_SIZE "max_payload_size" - -+/* KCM Service */ -+#define CONFDB_KCM_CONF_ENTRY "config/kcm" -+#define CONFDB_KCM_SOCKET "socket_path" - - struct confdb_ctx; - struct config_file_ctx; -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index c287328828cae2f0ad8a5a105f1c2b3e05353021..5e789c51658c51c0af1338d23d6c0f30f40bf119 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -9,6 +9,7 @@ section = ssh - section = pac - section = ifp - section = secrets -+section = kcm - section_re = ^secrets/users/[0-9]\+$ - section_re = ^domain/.*$ - -@@ -262,6 +263,24 @@ option = forward_headers - option = username - option = password - -+# KCM responder -+[rule/allowed_kcm_options] -+validator = ini_allowed_options -+section_re = ^kcm$ -+ -+option = timeout -+option = debug -+option = debug_level -+option = debug_timestamps -+option = debug_microseconds -+option = debug_to_files -+option = command -+option = reconnection_retries -+option = fd_limit -+option = client_idle_timeout -+option = description -+option = socket_path -+ - [rule/allowed_domain_options] - validator = ini_allowed_options - section_re = ^domain/.*$ -diff --git a/src/external/libcurl.m4 b/src/external/libcurl.m4 -index 3bc303ca4e1dea8a04117e32b8c4466b80d885b1..b420b04ad806bd1251f086b773ffe480d39f8bd3 100644 ---- a/src/external/libcurl.m4 -+++ b/src/external/libcurl.m4 -@@ -9,8 +9,8 @@ AS_IF([test x$enable_libcurl = xyes], - [PKG_CHECK_MODULES([CURL], - [libcurl], - [found_libcurl=yes], -- [AC_MSG_WARN([ --The libcurl development library was not found. Some features will be disabled.]) -+ [AC_MSG_ERROR([ -+The libcurl development library was not found.]) - ])]) - - AS_IF([test x"$found_libcurl" = xyes], -@@ -32,7 +32,5 @@ AS_IF([test x"$found_libcurl" = xyes], - AC_SUBST(CURL_LIBS) - AC_SUBST(CURL_CFLAGS) - --AM_CONDITIONAL([BUILD_WITH_LIBCURL], -- [test x"$have_curlopt_unix_sockpath" = xyes]) - AM_COND_IF([BUILD_WITH_LIBCURL], - [AC_DEFINE_UNQUOTED(HAVE_LIBCURL, 1, [Build with libcurl support])]) -diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c -new file mode 100644 -index 0000000000000000000000000000000000000000..90a6999c5e39d48a1a2ea8168d171612a65077d5 ---- /dev/null -+++ b/src/responder/kcm/kcm.c -@@ -0,0 +1,254 @@ -+/* -+ SSSD -+ -+ KCM Server - the mainloop and server setup -+ -+ Copyright (C) Red Hat, 2016 -+ -+ 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 "config.h" -+ -+#include -+#include -+ -+#include "responder/kcm/kcm.h" -+#include "responder/kcm/kcmsrv_pvt.h" -+#include "responder/common/responder.h" -+#include "util/util.h" -+ -+#define DEFAULT_KCM_FD_LIMIT 2048 -+ -+#ifndef SSS_KCM_SOCKET_NAME -+#define SSS_KCM_SOCKET_NAME DEFAULT_KCM_SOCKET_PATH -+#endif -+ -+static int kcm_responder_ctx_destructor(void *ptr) -+{ -+ struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx); -+ -+ /* mark that we are shutting down the responder, so it is propagated -+ * into underlying contexts that are freed right before rctx */ -+ DEBUG(SSSDBG_TRACE_FUNC, "Responder is being shut down\n"); -+ rctx->shutting_down = true; -+ -+ return 0; -+} -+ -+static int kcm_get_config(struct kcm_ctx *kctx) -+{ -+ int ret; -+ char *sock_name; -+ -+ ret = confdb_get_int(kctx->rctx->cdb, -+ CONFDB_KCM_CONF_ENTRY, -+ CONFDB_SERVICE_FD_LIMIT, -+ DEFAULT_KCM_FD_LIMIT, -+ &kctx->fd_limit); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "Failed to get file descriptors limit\n"); -+ goto done; -+ } -+ -+ ret = confdb_get_int(kctx->rctx->cdb, -+ kctx->rctx->confdb_service_path, -+ CONFDB_RESPONDER_CLI_IDLE_TIMEOUT, -+ CONFDB_RESPONDER_CLI_IDLE_DEFAULT_TIMEOUT, -+ &kctx->rctx->client_idle_timeout); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get the client idle timeout [%d]: %s\n", -+ ret, strerror(ret)); -+ goto done; -+ } -+ -+ /* Ensure that the client timeout is at least ten seconds */ -+ if (kctx->rctx->client_idle_timeout < 10) { -+ kctx->rctx->client_idle_timeout = 10; -+ } -+ -+ ret = confdb_get_string(kctx->rctx->cdb, -+ kctx->rctx, -+ kctx->rctx->confdb_service_path, -+ CONFDB_KCM_SOCKET, -+ SSS_KCM_SOCKET_NAME, -+ &sock_name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get the client idle timeout [%d]: %s\n", -+ ret, strerror(ret)); -+ goto done; -+ } -+ kctx->rctx->sock_name = sock_name; -+ -+ ret = EOK; -+ -+done: -+ return ret; -+} -+ -+static int kcm_data_destructor(void *ptr) -+{ -+ struct kcm_resp_ctx *kcm_data = talloc_get_type(ptr, struct kcm_resp_ctx); -+ -+ if (kcm_data != NULL) { -+ krb5_free_context(kcm_data->k5c); -+ } -+ return 0; -+} -+ -+static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx) -+{ -+ struct kcm_resp_ctx *kcm_data; -+ krb5_error_code kret; -+ -+ kcm_data = talloc_zero(mem_ctx, struct kcm_resp_ctx); -+ if (kcm_data == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing kcm data\n"); -+ return NULL; -+ } -+ -+ kret = krb5_init_context(&kcm_data->k5c); -+ if (kret != EOK) { -+ talloc_free(kcm_data); -+ return NULL; -+ } -+ talloc_set_destructor((TALLOC_CTX*)kcm_data, kcm_data_destructor); -+ -+ return kcm_data; -+} -+ -+static int kcm_process_init(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct confdb_ctx *cdb) -+{ -+ struct resp_ctx *rctx; -+ struct kcm_ctx *kctx; -+ int ret; -+ -+ rctx = talloc_zero(mem_ctx, struct resp_ctx); -+ if (rctx == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing resp_ctx\n"); -+ return ENOMEM; -+ } -+ rctx->ev = ev; -+ rctx->cdb = cdb; -+ rctx->confdb_service_path = CONFDB_KCM_CONF_ENTRY; -+ rctx->shutting_down = false; -+ rctx->lfd = -1; -+ rctx->priv_lfd = -1; -+ -+ talloc_set_destructor((TALLOC_CTX*)rctx, kcm_responder_ctx_destructor); -+ -+ kctx = talloc_zero(rctx, struct kcm_ctx); -+ if (kctx == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing kcm_ctx\n"); -+ ret = ENOMEM; -+ goto fail; -+ } -+ -+ kctx->rctx = rctx; -+ kctx->rctx->pvt_ctx = kctx; -+ -+ ret = kcm_get_config(kctx); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "fatal error getting KCM config\n"); -+ goto fail; -+ } -+ -+ kctx->kcm_data = kcm_data_setup(kctx); -+ if (kctx->kcm_data == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "fatal error initializing responder data\n"); -+ ret = EIO; -+ goto fail; -+ } -+ -+ /* Set up file descriptor limits */ -+ responder_set_fd_limit(kctx->fd_limit); -+ -+ ret = activate_unix_sockets(rctx, kcm_connection_setup); -+ if (ret != EOK) goto fail; -+ -+ DEBUG(SSSDBG_TRACE_FUNC, "KCM Initialization complete\n"); -+ -+ return EOK; -+ -+fail: -+ talloc_free(rctx); -+ return ret; -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ int opt; -+ poptContext pc; -+ struct main_context *main_ctx; -+ int ret; -+ uid_t uid; -+ gid_t gid; -+ -+ struct poptOption long_options[] = { -+ POPT_AUTOHELP -+ SSSD_MAIN_OPTS -+ SSSD_SERVER_OPTS(uid, gid) -+ POPT_TABLEEND -+ }; -+ -+ /* Set debug level to invalid value so we can deside if -d 0 was used. */ -+ debug_level = SSSDBG_INVALID; -+ -+ umask(DFL_RSP_UMASK); -+ -+ pc = poptGetContext(argv[0], argc, argv, long_options, 0); -+ while((opt = poptGetNextOpt(pc)) != -1) { -+ switch(opt) { -+ default: -+ fprintf(stderr, "\nInvalid option %s: %s\n\n", -+ poptBadOption(pc, 0), poptStrerror(opt)); -+ poptPrintUsage(pc, stderr, 0); -+ return 1; -+ } -+ } -+ -+ poptFreeContext(pc); -+ -+ DEBUG_INIT(debug_level); -+ -+ /* set up things like debug, signals, daemonization, etc... */ -+ debug_log_file = "sssd_kcm"; -+ -+ ret = server_setup("sssd[kcm]", 0, uid, gid, CONFDB_KCM_CONF_ENTRY, -+ &main_ctx); -+ if (ret != EOK) return 2; -+ -+ ret = die_if_parent_died(); -+ if (ret != EOK) { -+ /* This is not fatal, don't return */ -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Could not set up to exit when parent process does\n"); -+ } -+ -+ ret = kcm_process_init(main_ctx, -+ main_ctx->event_ctx, -+ main_ctx->confdb_ctx); -+ if (ret != EOK) return 3; -+ -+ /* loop on main */ -+ server_loop(main_ctx); -+ -+ return 0; -+} -diff --git a/src/responder/kcm/kcm.h b/src/responder/kcm/kcm.h -new file mode 100644 -index 0000000000000000000000000000000000000000..1ea7e9bbca754dca2eeb72a08830fa2f95713b4f ---- /dev/null -+++ b/src/responder/kcm/kcm.h -@@ -0,0 +1,97 @@ -+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -+/* include/kcm.h - Kerberos cache manager protocol declarations */ -+/* -+ * Copyright (C) 2014 by the Massachusetts Institute of Technology. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * * Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * * Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in -+ * the documentation and/or other materials provided with the -+ * distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -+ * OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef KCM_H -+#define KCM_H -+ -+#define KCM_PROTOCOL_VERSION_MAJOR 2 -+#define KCM_PROTOCOL_VERSION_MINOR 0 -+ -+#define KCM_UUID_LEN 16 -+ -+/* This should ideally be in RUNSTATEDIR, but Heimdal uses a hardcoded -+ * /var/run, and we need to use the same default path. */ -+#define DEFAULT_KCM_SOCKET_PATH "/var/run/.heim_org.h5l.kcm-socket" -+#define DEFAULT_KCM_MACH_SERVICE "org.h5l.kcm" -+ -+/* -+ * All requests begin with: -+ * major version (1 bytes) -+ * minor version (1 bytes) -+ * opcode (16-bit big-endian) -+ * -+ * All replies begin with a 32-bit big-endian reply code. -+ * -+ * Parameters are appended to the request or reply with no delimiters. Flags -+ * and time offsets are stored as 32-bit big-endian integers. Names are -+ * marshalled as zero-terminated strings. Principals and credentials are -+ * marshalled in the v4 FILE ccache format. UUIDs are 16 bytes. UUID lists -+ * are not delimited, so nothing can come after them. -+ */ -+ -+/* Opcodes without comments are currently unused in the MIT client -+ * implementation. */ -+typedef enum kcm_opcode { -+ KCM_OP_NOOP, -+ KCM_OP_GET_NAME, -+ KCM_OP_RESOLVE, -+ KCM_OP_GEN_NEW, /* 0x3 () -> (name) */ -+ KCM_OP_INITIALIZE, /* 0x4 (name, princ) -> () */ -+ KCM_OP_DESTROY, /* 0x4 (name) -> () */ -+ KCM_OP_STORE, /* 0x6 (name, cred) -> () */ -+ KCM_OP_RETRIEVE, -+ KCM_OP_GET_PRINCIPAL, /* 0x8 (name) -> (princ) */ -+ KCM_OP_GET_CRED_UUID_LIST, /* 0x9 (name) -> (uuid, ...) */ -+ KCM_OP_GET_CRED_BY_UUID, /* 0xa (name, uuid) -> (cred) */ -+ KCM_OP_REMOVE_CRED, /* (name, flags, credtag) -> () */ -+ KCM_OP_SET_FLAGS, -+ KCM_OP_CHOWN, -+ KCM_OP_CHMOD, -+ KCM_OP_GET_INITIAL_TICKET, -+ KCM_OP_GET_TICKET, -+ KCM_OP_MOVE_CACHE, -+ KCM_OP_GET_CACHE_UUID_LIST, /* 0x12 () -> (uuid, ...) */ -+ KCM_OP_GET_CACHE_BY_UUID, /* 0x13 (uuid) -> (name) */ -+ KCM_OP_GET_DEFAULT_CACHE, /* 0x14 () -> (name) */ -+ KCM_OP_SET_DEFAULT_CACHE, /* 0x15 (name) -> () */ -+ KCM_OP_GET_KDC_OFFSET, /* 0x16 (name) -> (offset) */ -+ KCM_OP_SET_KDC_OFFSET, /* 0x17 (name, offset) -> () */ -+ KCM_OP_ADD_NTLM_CRED, -+ KCM_OP_HAVE_NTLM_CRED, -+ KCM_OP_DEL_NTLM_CRED, -+ KCM_OP_DO_NTLM_AUTH, -+ KCM_OP_GET_NTLM_USER_LIST, -+ -+ KCM_OP_SENTINEL, /* SSSD addition, not in the MIT header */ -+} kcm_opcode; -+ -+#endif /* KCM_H */ -diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c -new file mode 100644 -index 0000000000000000000000000000000000000000..e9a03cbd41169c93e00b0630dc1e05e205881ec9 ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_cmd.c -@@ -0,0 +1,65 @@ -+/* -+ SSSD -+ -+ KCM Server - the KCM server request and reply parsing and dispatching -+ -+ Copyright (C) Red Hat, 2016 -+ -+ 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 "config.h" -+#include "util/util.h" -+#include "responder/common/responder.h" -+ -+struct kcm_proto_ctx { -+ void *unused; -+}; -+ -+static void kcm_fd_handler(struct tevent_context *ev, -+ struct tevent_fd *fde, -+ uint16_t flags, void *ptr) -+{ -+ errno_t ret; -+ struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx); -+ -+ /* Always reset the idle timer on any activity */ -+ ret = reset_client_idle_timer(cctx); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Could not create idle timer for client. " -+ "This connection may not auto-terminate\n"); -+ /* Non-fatal, continue */ -+ } -+} -+ -+int kcm_connection_setup(struct cli_ctx *cctx) -+{ -+ struct kcm_proto_ctx *protocol_ctx; -+ -+ protocol_ctx = talloc_zero(cctx, struct kcm_proto_ctx); -+ if (protocol_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ cctx->protocol_ctx = protocol_ctx; -+ cctx->cfd_handler = kcm_fd_handler; -+ return EOK; -+} -+ -+/* Dummy, not used here but required to link to other responder files */ -+struct cli_protocol_version *register_cli_protocol_version(void) -+{ -+ return NULL; -+} -diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h -new file mode 100644 -index 0000000000000000000000000000000000000000..a7c9d062c17f09986d894064176c3a461d396ac0 ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_pvt.h -@@ -0,0 +1,58 @@ -+/* -+ SSSD -+ -+ KCM Server - private header file -+ -+ Copyright (C) Red Hat, 2016 -+ -+ 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 . -+*/ -+ -+#ifndef __KCMSRV_PVT_H__ -+#define __KCMSRV_PVT_H__ -+ -+#include "config.h" -+ -+#include -+#include "responder/common/responder.h" -+ -+/* KCM IO structure */ -+struct kcm_data { -+ uint8_t *data; -+ size_t length; -+}; -+ -+/* To avoid leaking the sssd-specific responder data to other -+ * modules, the ccache databases and other KCM specific data -+ * are kept separately -+ */ -+struct kcm_resp_ctx { -+ krb5_context k5c; -+}; -+ -+/* responder context that contains both the responder data, -+ * like the ccaches and the sssd-specific stuff like the -+ * generic responder ctx -+ */ -+struct kcm_ctx { -+ struct resp_ctx *rctx; -+ int fd_limit; -+ char *socket_path; -+ -+ struct kcm_resp_ctx *kcm_data; -+}; -+ -+int kcm_connection_setup(struct cli_ctx *cctx); -+ -+#endif /* __KCMSRV_PVT_H__ */ -diff --git a/src/sysv/systemd/sssd-kcm.service.in b/src/sysv/systemd/sssd-kcm.service.in -new file mode 100644 -index 0000000000000000000000000000000000000000..1e2bee12dc3bedd17d41b86f91c9b2b52d985c40 ---- /dev/null -+++ b/src/sysv/systemd/sssd-kcm.service.in -@@ -0,0 +1,9 @@ -+[Unit] -+Description=SSSD Kerberos Cache Manager -+Documentation=man:sssd-kcm(5) -+ -+[Install] -+Also=sssd-kcm.socket -+ -+[Service] -+ExecStart=@libexecdir@/sssd/sssd_kcm --uid 0 --gid 0 --debug-to-files -diff --git a/src/sysv/systemd/sssd-kcm.socket.in b/src/sysv/systemd/sssd-kcm.socket.in -new file mode 100644 -index 0000000000000000000000000000000000000000..80ec1c0c8f190e83de0b603df8e90aa49d2ec181 ---- /dev/null -+++ b/src/sysv/systemd/sssd-kcm.socket.in -@@ -0,0 +1,10 @@ -+[Unit] -+Description=SSSD Secrets Service responder socket -+Documentation=man:sssd-kcm(8) -+Requires=sssd-secrets.socket -+ -+[Socket] -+ListenStream=@localstatedir@/run/.heim_org.h5l.kcm-socket -+ -+[Install] -+WantedBy=sockets.target -diff --git a/src/util/util_errors.c b/src/util/util_errors.c -index 17388c997db5315c2491af1021e75aff07632488..23cfdf9c6116a2c8e569a041e8289b65a112fd08 100644 ---- a/src/util/util_errors.c -+++ b/src/util/util_errors.c -@@ -40,6 +40,7 @@ struct err_string error_to_str[] = { - { "Credentials are expired, old ccache was removed" }, /* ERR_CREDS_EXPIRED_CCACHE */ - { "Failure setting user credentials"}, /* ERR_CREDS_INVALID */ - { "No cached credentials available" }, /* ERR_NO_CACHED_CREDS */ -+ { "No matching credentials found" }, /* ERR_NO_MATCHING_CREDS */ - { "Cached credentials are expired" }, /* ERR_CACHED_CREDS_EXPIRED */ - { "Authentication Denied" }, /* ERR_AUTH_DENIED */ - { "Authentication Failed" }, /* ERR_AUTH_FAILED */ -@@ -104,6 +105,10 @@ struct err_string error_to_str[] = { - { "The secret payload size is too large" }, /* ERR_SEC_PAYLOAD_SIZE_IS_TOO_LARGE */ - { "No authentication methode available" }, /* ERR_NO_AUTH_METHOD_AVAILABLE */ - { "Smartcard authentication not supported" }, /* ERR_SC_AUTH_NOT_SUPPORTED */ -+ { "Malformed input KCM packet" }, /* ERR_KCM_MALFORMED_IN_PKT */ -+ { "KCM operation not implemented" }, /* ERR_KCM_OP_NOT_IMPLEMENTED */ -+ { "End of credential cache reached" }, /* ERR_KCM_CC_END */ -+ { "Credential cache name not allowed" }, /* ERR_KCM_WRONG_CCNAME_FORMAT */ - { "ERR_LAST" } /* ERR_LAST */ - }; - -diff --git a/src/util/util_errors.h b/src/util/util_errors.h -index 7aacad26084a3a2af6333988f07db865f6a4d299..387d481616db1ed5e22b73fae82632a582fae946 100644 ---- a/src/util/util_errors.h -+++ b/src/util/util_errors.h -@@ -62,6 +62,7 @@ enum sssd_errors { - ERR_CREDS_EXPIRED_CCACHE, - ERR_CREDS_INVALID, - ERR_NO_CACHED_CREDS, -+ ERR_NO_MATCHING_CREDS, - ERR_CACHED_CREDS_EXPIRED, - ERR_AUTH_DENIED, - ERR_AUTH_FAILED, -@@ -126,6 +127,10 @@ enum sssd_errors { - ERR_SEC_PAYLOAD_SIZE_IS_TOO_LARGE, - ERR_NO_AUTH_METHOD_AVAILABLE, - ERR_SC_AUTH_NOT_SUPPORTED, -+ ERR_KCM_MALFORMED_IN_PKT, -+ ERR_KCM_OP_NOT_IMPLEMENTED, -+ ERR_KCM_CC_END, -+ ERR_KCM_WRONG_CCNAME_FORMAT, - ERR_LAST /* ALWAYS LAST */ - }; - --- -2.9.3 - diff --git a/SOURCES/0022-sss_client-create-nss_common.h.patch b/SOURCES/0022-sss_client-create-nss_common.h.patch new file mode 100644 index 0000000..f695b2b --- /dev/null +++ b/SOURCES/0022-sss_client-create-nss_common.h.patch @@ -0,0 +1,143 @@ +From 22c5575eb442f20230081cc06528d685397c8914 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 29 Sep 2017 21:38:54 +0200 +Subject: [PATCH 22/31] sss_client: create nss_common.h + +This patch makes sss_nss_getpw_readrep() and sss_nss_getgr_readrep() +calls which parse SSSD's replies for user and group requests available +to other components. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 7449b236523409cc8766fb957d6cba051fdfb483) +--- + Makefile.am | 1 + + src/sss_client/nss_common.h | 43 +++++++++++++++++++++++++++++++++++++++++++ + src/sss_client/nss_group.c | 10 +++------- + src/sss_client/nss_passwd.c | 11 +++-------- + 4 files changed, 50 insertions(+), 15 deletions(-) + create mode 100644 src/sss_client/nss_common.h + +diff --git a/Makefile.am b/Makefile.am +index 5483375167d99568e8313c9a0488900419be6ec3..dc2f4b1857ce5bd376544488348731be29b6b293 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3623,6 +3623,7 @@ libnss_sss_la_SOURCES = \ + src/sss_client/nss_services.c \ + src/sss_client/sss_cli.h \ + src/sss_client/nss_compat.h \ ++ src/sss_client/nss_common.h \ + src/sss_client/nss_mc_common.c \ + src/util/io.c \ + src/util/murmurhash3.c \ +diff --git a/src/sss_client/nss_common.h b/src/sss_client/nss_common.h +new file mode 100644 +index 0000000000000000000000000000000000000000..e83b4f95a3136b5aa711194a4d37389eebfb607a +--- /dev/null ++++ b/src/sss_client/nss_common.h +@@ -0,0 +1,43 @@ ++/* ++ SSSD ++ ++ Common routines for classical and enhanced NSS interface ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) Red Hat, Inc 2007 ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser 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 Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with this program. If not, see . ++*/ ++ ++ ++ ++struct sss_nss_pw_rep { ++ struct passwd *result; ++ char *buffer; ++ size_t buflen; ++}; ++ ++int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr, ++ uint8_t *buf, size_t *len); ++ ++struct sss_nss_gr_rep { ++ struct group *result; ++ char *buffer; ++ size_t buflen; ++}; ++ ++int sss_nss_getgr_readrep(struct sss_nss_gr_rep *pr, ++ uint8_t *buf, size_t *len); +diff --git a/src/sss_client/nss_group.c b/src/sss_client/nss_group.c +index 0e686af43aeb84a5938315e3922e9fcf2fef4e83..42fba6242d23fc1d52cfd7be10cf10383010f091 100644 +--- a/src/sss_client/nss_group.c ++++ b/src/sss_client/nss_group.c +@@ -29,6 +29,7 @@ + #include + #include "sss_cli.h" + #include "nss_mc.h" ++#include "nss_common.h" + + static struct sss_nss_getgrent_data { + size_t len; +@@ -190,14 +191,9 @@ done: + * + * FIXME: do we need to pad so that each result is 32 bit aligned ? + */ +-struct sss_nss_gr_rep { +- struct group *result; +- char *buffer; +- size_t buflen; +-}; + +-static int sss_nss_getgr_readrep(struct sss_nss_gr_rep *pr, +- uint8_t *buf, size_t *len) ++int sss_nss_getgr_readrep(struct sss_nss_gr_rep *pr, ++ uint8_t *buf, size_t *len) + { + errno_t ret; + size_t i, l, slen, ptmem, pad, dlen, glen; +diff --git a/src/sss_client/nss_passwd.c b/src/sss_client/nss_passwd.c +index c43f9bc50f43599b541e97f5a5aa60de036a5cdf..61e2a567e684fbc7664b5d425e81cfa28a98e845 100644 +--- a/src/sss_client/nss_passwd.c ++++ b/src/sss_client/nss_passwd.c +@@ -28,6 +28,7 @@ + #include + #include "sss_cli.h" + #include "nss_mc.h" ++#include "nss_common.h" + + static struct sss_nss_getpwent_data { + size_t len; +@@ -63,14 +64,8 @@ static void sss_nss_getpwent_data_clean(void) { + * 8-X: sequence of 5, 0 terminated, strings (name, passwd, gecos, dir, shell) + */ + +-struct sss_nss_pw_rep { +- struct passwd *result; +- char *buffer; +- size_t buflen; +-}; +- +-static int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr, +- uint8_t *buf, size_t *len) ++int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr, ++ uint8_t *buf, size_t *len) + { + errno_t ret; + size_t i, slen, dlen; +-- +2.13.6 + diff --git a/SOURCES/0023-KCM-request-parsing-and-sending-a-reply.patch b/SOURCES/0023-KCM-request-parsing-and-sending-a-reply.patch deleted file mode 100644 index 5e59dc2..0000000 --- a/SOURCES/0023-KCM-request-parsing-and-sending-a-reply.patch +++ /dev/null @@ -1,578 +0,0 @@ -From aface2604c53db717299ac3dfe798dfd0c540f99 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 23 Sep 2016 14:00:10 +0200 -Subject: [PATCH 23/36] KCM: request parsing and sending a reply -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Implements parsing the KCM client request into per-client buffers and -sending a response for both the failure case and for success. - -The protocol is documented at: - http://k5wiki.kerberos.org/wiki/Projects/KCM_client - -Several places don't use the sss_iobuf structure, because they don't -parse variable-length data from the buffer and it's much more efficient -to just allocate the needed request and reply structure on the stack. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/responder/kcm/kcmsrv_cmd.c | 467 ++++++++++++++++++++++++++++++++++++++++- - src/responder/kcm/kcmsrv_pvt.h | 21 +- - 2 files changed, 474 insertions(+), 14 deletions(-) - -diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c -index e9a03cbd41169c93e00b0630dc1e05e205881ec9..cbf70353730d8a4e03d8f75c97395f4ef007e77f 100644 ---- a/src/responder/kcm/kcmsrv_cmd.c -+++ b/src/responder/kcm/kcmsrv_cmd.c -@@ -19,14 +19,430 @@ - along with this program. If not, see . - */ - -+#include -+ - #include "config.h" - #include "util/util.h" -+#include "util/sss_iobuf.h" - #include "responder/common/responder.h" -+#include "responder/kcm/kcmsrv_pvt.h" -+#include "responder/kcm/kcm.h" - --struct kcm_proto_ctx { -- void *unused; -+/* The first four bytes of a message is always the size */ -+#define KCM_MSG_LEN_SIZE 4 -+ -+/* The return code is 32bits */ -+#define KCM_RETCODE_SIZE 4 -+ -+/* The maximum length of a request or reply as defined by the RPC -+ * protocol. This is the same constant size as MIT KRB5 uses -+ */ -+#define KCM_PACKET_MAX_SIZE 2048 -+ -+/* KCM operation, its raw input and raw output and result */ -+struct kcm_op_io { -+ struct kcm_op *op; -+ struct kcm_data request; -+ struct sss_iobuf *reply; -+}; -+ -+/** -+ * KCM IO-vector operations -+ */ -+struct kcm_iovec { -+ /* We don't use iovec b/c void pointers don't allow for -+ * pointer arithmetics and it's convenient to keep track -+ * of processed bytes -+ */ -+ uint8_t *kiov_base; -+ size_t kiov_len; -+ size_t nprocessed; -+}; -+ -+static errno_t kcm_iovec_op(int fd, struct kcm_iovec *kiov, bool do_read) -+{ -+ ssize_t len; -+ struct iovec iov[1]; -+ -+ iov[0].iov_base = kiov->kiov_base + kiov->nprocessed; -+ iov[0].iov_len = kiov->kiov_len - kiov->nprocessed; -+ if (iov[0].iov_len == 0) { -+ /* This iovec is full (read) or depleted (write), proceed to the next one */ -+ return EOK; -+ } -+ -+ if (do_read) { -+ len = readv(fd, iov, 1); -+ } else { -+ len = writev(fd, iov, 1); -+ } -+ -+ if (len == -1) { -+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { -+ return EAGAIN; -+ } else { -+ return errno; -+ } -+ } -+ -+ if (len == 0) { -+ /* Read event on fd that doesn't yield data? error */ -+ return ENODATA; -+ } -+ -+ /* Decrease the amount of available free space in the iovec */ -+ kiov->nprocessed += len; -+ return EOK; -+} -+ -+static errno_t kcm_read_iovec(int fd, struct kcm_iovec *kiov) -+{ -+ return kcm_iovec_op(fd, kiov, true); -+} -+ -+static errno_t kcm_write_iovec(int fd, struct kcm_iovec *kiov) -+{ -+ return kcm_iovec_op(fd, kiov, false); -+} -+ -+/** -+ * Parsing KCM input -+ * -+ * The request is received as two IO vectors: -+ * -+ * first iovec: -+ * length 32-bit big-endian integer -+ * -+ * second iovec: -+ * major protocol number 8-bit big-endian integer -+ * minor protocol number 8-bit big-endian integer -+ * opcode 16-bit big-endian integer -+ * message payload buffer -+ */ -+struct kcm_reqbuf { -+ uint8_t lenbuf[KCM_MSG_LEN_SIZE]; -+ struct kcm_iovec v_len; -+ -+ /* Includes the major, minor versions etc */ -+ uint8_t msgbuf[KCM_PACKET_MAX_SIZE]; -+ struct kcm_iovec v_msg; -+}; -+ -+static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf, -+ struct kcm_op_io *op_io) -+{ -+ size_t lc = 0; -+ size_t mc = 0; -+ uint16_t opcode = 0; -+ uint16_t opcode_be = 0; -+ uint32_t len_be = 0; -+ uint32_t msglen; -+ uint8_t proto_maj = 0; -+ uint8_t proto_min = 0; -+ -+ /* The first 4 bytes before the payload is message length */ -+ SAFEALIGN_COPY_UINT32_CHECK(&len_be, -+ reqbuf->v_len.kiov_base, -+ reqbuf->v_len.kiov_len, -+ &lc); -+ msglen = be32toh(len_be); -+ DEBUG(SSSDBG_TRACE_LIBS, -+ "Received message with length %"PRIu32"\n", msglen); -+ -+ if (msglen == 0) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Illegal zero-length message\n"); -+ return EBADMSG; -+ } -+ -+ if (msglen != reqbuf->v_msg.nprocessed) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Sender claims the message is %"PRIu32" bytes, " -+ "but received %zu\n", -+ msglen, reqbuf->v_msg.nprocessed); -+ return EBADMSG; -+ } -+ -+ /* First 16 bits are 8 bit major and 8bit major protocol version */ -+ SAFEALIGN_COPY_UINT8_CHECK(&proto_maj, -+ reqbuf->v_msg.kiov_base + mc, -+ reqbuf->v_msg.kiov_len, -+ &mc); -+ SAFEALIGN_COPY_UINT8_CHECK(&proto_min, -+ reqbuf->v_msg.kiov_base + mc, -+ reqbuf->v_msg.kiov_len, -+ &mc); -+ -+ if (proto_maj != KCM_PROTOCOL_VERSION_MAJOR) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Expected major version %d, got %"PRIu16"\n", -+ KCM_PROTOCOL_VERSION_MAJOR, (uint16_t) proto_maj); -+ return ERR_KCM_MALFORMED_IN_PKT; -+ } -+ -+ if (proto_min != KCM_PROTOCOL_VERSION_MINOR) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Expected minor version %d, got %"PRIu16"\n", -+ KCM_PROTOCOL_VERSION_MINOR, (uint16_t) proto_maj); -+ return ERR_KCM_MALFORMED_IN_PKT; -+ } -+ -+ SAFEALIGN_COPY_UINT16_CHECK(&opcode_be, -+ reqbuf->v_msg.kiov_base + mc, -+ reqbuf->v_msg.kiov_len, -+ &mc); -+ -+ opcode = be16toh(opcode_be); -+ DEBUG(SSSDBG_TRACE_LIBS, "Received operation code %"PRIu16"\n", opcode); -+ -+ return EOK; -+} -+ -+/** -+ * Constructing a reply for failure and success -+ * -+ * The reply consists of three IO vectors: -+ * 1) length iovec: -+ * length: 32-bit big-endian -+ * -+ * 2) return code iovec: -+ * retcode: 32-bit big-endian. Non-zero on failure in the KCM server, -+ * zero if the KCM operation ran (even if the operation itself -+ * failed) -+ * -+ * 3) reply iovec -+ * message: buffer, first 32-bits of the buffer is the return code of -+ * the KCM operation, the rest depends on the operation itself. -+ * The buffer's length is specified by the first integer in the -+ * reply (very intuitive, right?) -+ * -+ * The client always reads the length and return code iovectors. However, the -+ * client reads the reply iovec only if retcode is 0 in the return code iovector -+ * (see kcmio_unix_socket_read() in the MIT tree) -+ */ -+struct kcm_repbuf { -+ uint8_t lenbuf[KCM_MSG_LEN_SIZE]; -+ struct kcm_iovec v_len; -+ -+ uint8_t rcbuf[KCM_RETCODE_SIZE]; -+ struct kcm_iovec v_rc; -+ -+ uint8_t msgbuf[KCM_PACKET_MAX_SIZE]; -+ struct kcm_iovec v_msg; -+}; -+ -+static errno_t kcm_failbuf_construct(errno_t ret, -+ struct kcm_repbuf *repbuf) -+{ -+ size_t c; -+ -+ c = 0; -+ SAFEALIGN_SETMEM_UINT32(repbuf->lenbuf, 0, &c); -+ c = 0; -+ SAFEALIGN_SETMEM_UINT32(repbuf->rcbuf, htobe32(ret), &c); -+ -+ return EOK; -+} -+ -+/** -+ * Construct a reply buffer and send it to the KCM client -+ */ -+static void kcm_reply_error(struct cli_ctx *cctx, -+ errno_t retcode, -+ struct kcm_repbuf *repbuf) -+{ -+ errno_t ret; -+ krb5_error_code kerr; -+ -+ DEBUG(SSSDBG_OP_FAILURE, -+ "KCM operation returs failure [%d]: %s\n", -+ retcode, sss_strerror(retcode)); -+ kerr = sss2krb5_error(retcode); -+ -+ ret = kcm_failbuf_construct(kerr, repbuf); -+ if (ret != EOK) { -+ /* If we can't construct the reply buffer, just terminate the client */ -+ talloc_free(cctx); -+ return; -+ } -+ -+ TEVENT_FD_WRITEABLE(cctx->cfde); -+} -+ -+/** -+ * Request-reply dispatcher -+ */ -+struct kcm_req_ctx { -+ /* client context owns per-client buffers including this one */ -+ struct cli_ctx *cctx; -+ -+ /* raw IO buffers */ -+ struct kcm_reqbuf reqbuf; -+ struct kcm_repbuf repbuf; -+ -+ /* long-lived responder structures */ -+ struct kcm_ctx *kctx; -+ -+ struct kcm_op_io op_io; - }; - -+static errno_t kcm_recv_data(int fd, struct kcm_reqbuf *reqbuf) -+{ -+ errno_t ret; -+ -+ ret = kcm_read_iovec(fd, &reqbuf->v_len); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ ret = kcm_read_iovec(fd, &reqbuf->v_msg); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ return EOK; -+} -+ -+static struct kcm_req_ctx *kcm_new_req(TALLOC_CTX *mem_ctx, -+ struct cli_ctx *cctx, -+ struct kcm_ctx *kctx) -+{ -+ struct kcm_req_ctx *req; -+ -+ req = talloc_zero(cctx, struct kcm_req_ctx); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ req->reqbuf.v_len.kiov_base = req->reqbuf.lenbuf; -+ req->reqbuf.v_len.kiov_len = KCM_MSG_LEN_SIZE; -+ -+ req->reqbuf.v_msg.kiov_base = req->reqbuf.msgbuf; -+ req->reqbuf.v_msg.kiov_len = KCM_PACKET_MAX_SIZE; -+ -+ req->repbuf.v_len.kiov_base = req->repbuf.lenbuf; -+ req->repbuf.v_len.kiov_len = KCM_MSG_LEN_SIZE; -+ -+ req->repbuf.v_rc.kiov_base = req->repbuf.rcbuf; -+ req->repbuf.v_rc.kiov_len = KCM_RETCODE_SIZE; -+ -+ req->repbuf.v_msg.kiov_base = req->repbuf.msgbuf; -+ /* Length of the msg iobuf will be adjusted later, so far use the full -+ * length so that constructing the reply can use that capacity -+ */ -+ req->repbuf.v_msg.kiov_len = KCM_PACKET_MAX_SIZE; -+ -+ req->cctx = cctx; -+ req->kctx = kctx; -+ -+ return req; -+} -+ -+static void kcm_recv(struct cli_ctx *cctx) -+{ -+ struct kcm_req_ctx *req; -+ struct kcm_ctx *kctx; -+ int ret; -+ -+ kctx = talloc_get_type(cctx->rctx->pvt_ctx, struct kcm_ctx); -+ req = talloc_get_type(cctx->state_ctx, struct kcm_req_ctx); -+ if (req == NULL) { -+ /* A new request comes in, setup data structures */ -+ req = kcm_new_req(cctx, cctx, kctx); -+ if (req == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot set up client connection\n"); -+ talloc_free(cctx); -+ return; -+ } -+ -+ cctx->state_ctx = req; -+ } -+ -+ ret = kcm_recv_data(cctx->cfd, &req->reqbuf); -+ switch (ret) { -+ case ENODATA: -+ DEBUG(SSSDBG_TRACE_ALL, "Client closed connection.\n"); -+ talloc_free(cctx); -+ return; -+ case EAGAIN: -+ DEBUG(SSSDBG_TRACE_ALL, "Retry later\n"); -+ return; -+ case EOK: -+ /* all fine */ -+ break; -+ default: -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "Failed to receive data (%d, %s), aborting client\n", -+ ret, sss_strerror(ret)); -+ talloc_free(cctx); -+ return; -+ } -+ -+ ret = kcm_input_parse(&req->reqbuf, &req->op_io); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "Failed to parse data (%d, %s), aborting client\n", -+ ret, sss_strerror(ret)); -+ goto fail; -+ } -+ -+ /* do not read anymore, client is done sending */ -+ TEVENT_FD_NOT_READABLE(cctx->cfde); -+ -+ kcm_reply_error(cctx, ret, &req->repbuf); -+ return; -+ -+fail: -+ /* Fail with reply */ -+ kcm_reply_error(cctx, ret, &req->repbuf); -+} -+ -+static int kcm_send_data(struct cli_ctx *cctx) -+{ -+ struct kcm_req_ctx *req; -+ errno_t ret; -+ -+ req = talloc_get_type(cctx->state_ctx, struct kcm_req_ctx); -+ -+ ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_len); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_rc); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_msg); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ return EOK; -+} -+ -+static void kcm_send(struct cli_ctx *cctx) -+{ -+ errno_t ret; -+ -+ ret = kcm_send_data(cctx); -+ if (ret == EAGAIN) { -+ /* not all data was sent, loop again */ -+ return; -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n"); -+ talloc_free(cctx); -+ return; -+ } -+ -+ /* ok all sent */ -+ TEVENT_FD_NOT_WRITEABLE(cctx->cfde); -+ TEVENT_FD_READABLE(cctx->cfde); -+ talloc_zfree(cctx->state_ctx); -+ return; -+} -+ - static void kcm_fd_handler(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, void *ptr) -@@ -39,25 +455,54 @@ static void kcm_fd_handler(struct tevent_context *ev, - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Could not create idle timer for client. " -- "This connection may not auto-terminate\n"); -+ "This connection may not auto-terminate\n"); - /* Non-fatal, continue */ - } -+ -+ if (flags & TEVENT_FD_READ) { -+ kcm_recv(cctx); -+ return; -+ } -+ if (flags & TEVENT_FD_WRITE) { -+ kcm_send(cctx); -+ return; -+ } - } - - int kcm_connection_setup(struct cli_ctx *cctx) - { -- struct kcm_proto_ctx *protocol_ctx; -- -- protocol_ctx = talloc_zero(cctx, struct kcm_proto_ctx); -- if (protocol_ctx == NULL) { -- return ENOMEM; -- } -- -- cctx->protocol_ctx = protocol_ctx; - cctx->cfd_handler = kcm_fd_handler; - return EOK; - } - -+krb5_error_code sss2krb5_error(errno_t err) -+{ -+ switch (err) { -+ case EOK: -+ return 0; -+ case ENOMEM: -+ return KRB5_CC_NOMEM; -+ case EACCES: -+ return KRB5_FCC_PERM; -+ case ERR_KCM_OP_NOT_IMPLEMENTED: -+ return KRB5_CC_NOSUPP; -+ case ERR_WRONG_NAME_FORMAT: -+ return KRB5_CC_BADNAME; -+ case ERR_NO_MATCHING_CREDS: -+ return KRB5_FCC_NOFILE; -+ case ERR_NO_CREDS: -+ return KRB5_CC_NOTFOUND; -+ case ERR_KCM_CC_END: -+ return KRB5_CC_END; -+ case ERR_KCM_MALFORMED_IN_PKT: -+ case EINVAL: -+ case EIO: -+ return KRB5_CC_IO; -+ } -+ -+ return KRB5_FCC_INTERNAL; -+} -+ - /* Dummy, not used here but required to link to other responder files */ - struct cli_protocol_version *register_cli_protocol_version(void) - { -diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h -index a7c9d062c17f09986d894064176c3a461d396ac0..fd1fd9fa32d59a323d465def68999f24f84e3923 100644 ---- a/src/responder/kcm/kcmsrv_pvt.h -+++ b/src/responder/kcm/kcmsrv_pvt.h -@@ -27,13 +27,20 @@ - #include - #include "responder/common/responder.h" - --/* KCM IO structure */ -+/* -+ * KCM IO structure -+ * -+ * In theory we cold use sss_iobuf there, but since iobuf was -+ * made opaque, this allows it to allocate the structures on -+ * the stack in one go. -+ * */ - struct kcm_data { - uint8_t *data; - size_t length; - }; - --/* To avoid leaking the sssd-specific responder data to other -+/* -+ * To avoid leaking the sssd-specific responder data to other - * modules, the ccache databases and other KCM specific data - * are kept separately - */ -@@ -41,7 +48,8 @@ struct kcm_resp_ctx { - krb5_context k5c; - }; - --/* responder context that contains both the responder data, -+/* -+ * responder context that contains both the responder data, - * like the ccaches and the sssd-specific stuff like the - * generic responder ctx - */ -@@ -55,4 +63,11 @@ struct kcm_ctx { - - int kcm_connection_setup(struct cli_ctx *cctx); - -+/* -+ * Internally in SSSD-KCM we use SSSD-internal error codes so that we -+ * can always the same sss_strerror() functions to format the errors -+ * nicely, but the client expects libkrb5 error codes. -+ */ -+krb5_error_code sss2krb5_error(errno_t err); -+ - #endif /* __KCMSRV_PVT_H__ */ --- -2.9.3 - diff --git a/SOURCES/0023-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch b/SOURCES/0023-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch new file mode 100644 index 0000000..d6f9b89 --- /dev/null +++ b/SOURCES/0023-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch @@ -0,0 +1,901 @@ +From 15d7f1aeb541615314b914b6be1149f6e289d3e2 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 29 Sep 2017 16:16:01 +0200 +Subject: [PATCH 23/31] nss-idmap: add nss like calls with timeout and flags + +This patch adds new calls to libsss_nss_idmap to get NSS like user and +group information directly from SSSD without using the system's NSS +interfaces. + +Additionally a timeout and a flags options are added which are not +available for system's NSS. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 5e6622722e84d594298a8324f3685a1bda2b5868) +--- + Makefile.am | 22 +- + configure.ac | 13 + + src/sss_client/common.c | 9 +- + src/sss_client/common_private.h | 41 +++ + src/sss_client/idmap/common_ex.c | 105 +++++++ + src/sss_client/idmap/sss_nss_ex.c | 402 +++++++++++++++++++++++++++ + src/sss_client/idmap/sss_nss_idmap.exports | 10 + + src/sss_client/idmap/sss_nss_idmap.h | 135 +++++++++ + src/sss_client/idmap/sss_nss_idmap_private.h | 30 ++ + 9 files changed, 757 insertions(+), 10 deletions(-) + create mode 100644 src/sss_client/common_private.h + create mode 100644 src/sss_client/idmap/common_ex.c + create mode 100644 src/sss_client/idmap/sss_nss_ex.c + create mode 100644 src/sss_client/idmap/sss_nss_idmap_private.h + +diff --git a/Makefile.am b/Makefile.am +index dc2f4b1857ce5bd376544488348731be29b6b293..dd25d1f7ea1be66388aa1b393bac290c4d7501a2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1159,13 +1159,28 @@ pkgconfig_DATA += src/sss_client/idmap/sss_nss_idmap.pc + libsss_nss_idmap_la_DEPENDENCIES = src/sss_client/idmap/sss_nss_idmap.exports + libsss_nss_idmap_la_SOURCES = \ + src/sss_client/idmap/sss_nss_idmap.c \ ++ src/sss_client/idmap/sss_nss_ex.c \ ++ src/sss_client/idmap/sss_nss_idmap_private.h \ + src/sss_client/common.c \ +- src/util/strtonum.c ++ src/sss_client/idmap/common_ex.c \ ++ src/sss_client/nss_mc_passwd.c \ ++ src/sss_client/nss_passwd.c \ ++ src/sss_client/nss_mc_group.c \ ++ src/sss_client/nss_group.c \ ++ src/sss_client/nss_mc_initgr.c \ ++ src/sss_client/nss_mc_common.c \ ++ src/util/strtonum.c \ ++ src/util/murmurhash3.c \ ++ src/util/io.c \ ++ $(NULL) + libsss_nss_idmap_la_LIBADD = \ +- $(CLIENT_LIBS) ++ $(LIBCLOCK_GETTIME) \ ++ $(CLIENT_LIBS) \ ++ -lpthread \ ++ $(NULL) + libsss_nss_idmap_la_LDFLAGS = \ + -Wl,--version-script,$(srcdir)/src/sss_client/idmap/sss_nss_idmap.exports \ +- -version-info 3:0:3 ++ -version-info 4:0:4 + + dist_noinst_DATA += src/sss_client/idmap/sss_nss_idmap.exports + +@@ -3624,6 +3639,7 @@ libnss_sss_la_SOURCES = \ + src/sss_client/sss_cli.h \ + src/sss_client/nss_compat.h \ + src/sss_client/nss_common.h \ ++ src/sss_client/common_private.h \ + src/sss_client/nss_mc_common.c \ + src/util/io.c \ + src/util/murmurhash3.c \ +diff --git a/configure.ac b/configure.ac +index 7037927b5f7045b29d3774c85758e00e35e6def6..7e699d33e342c70d210d3f320c8a29a99e0c78a6 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -75,6 +75,19 @@ AC_SEARCH_LIBS([timer_create], [rt posix4], + AC_SUBST([LIBADD_TIMER]) + LIBS=$SAVE_LIBS + ++# Check library for the clock_gettime function ++SAVE_LIBS=$LIBS ++LIBS= ++LIBCLOCK_GETTIME= ++AC_SEARCH_LIBS([clock_gettime], [rt posix4], ++ [AC_DEFINE([HAVE_LIBRT], [1], ++ [Define if you have the librt library or equivalent.]) ++ LIBCLOCK_GETTIME="$LIBS"], ++ [AC_MSG_ERROR([unable to find library for the clock_gettime() function])]) ++ ++AC_SUBST([LIBCLOCK_GETTIME]) ++LIBS=$SAVE_LIBS ++ + # Check for presence of modern functions for setting file timestamps + AC_CHECK_FUNCS([ utimensat \ + futimens ]) +diff --git a/src/sss_client/common.c b/src/sss_client/common.c +index e5e0cbf854e4c977c03f9b1ca1ac90bfd8cbdb77..40252a35281dc4e94c712c3e7f8253af8b19b35a 100644 +--- a/src/sss_client/common.c ++++ b/src/sss_client/common.c +@@ -43,6 +43,7 @@ + #include + #define _(STRING) dgettext (PACKAGE, STRING) + #include "sss_cli.h" ++#include "common_private.h" + + #if HAVE_PTHREAD + #include +@@ -1113,13 +1114,7 @@ errno_t sss_strnlen(const char *str, size_t maxlen, size_t *len) + #if HAVE_PTHREAD + typedef void (*sss_mutex_init)(void); + +-struct sss_mutex { +- pthread_mutex_t mtx; +- +- int old_cancel_state; +-}; +- +-static struct sss_mutex sss_nss_mtx = { .mtx = PTHREAD_MUTEX_INITIALIZER }; ++struct sss_mutex sss_nss_mtx = { .mtx = PTHREAD_MUTEX_INITIALIZER }; + + static struct sss_mutex sss_pam_mtx = { .mtx = PTHREAD_MUTEX_INITIALIZER }; + +diff --git a/src/sss_client/common_private.h b/src/sss_client/common_private.h +new file mode 100644 +index 0000000000000000000000000000000000000000..a98d2c062caeecdbab02ecdaa6ae44d688a791bb +--- /dev/null ++++ b/src/sss_client/common_private.h +@@ -0,0 +1,41 @@ ++/* ++ SSSD ++ ++ SSS client - private calls ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 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 . ++*/ ++ ++#ifndef COMMON_PRIVATE_H_ ++#define COMMON_PRIVATE_H_ ++ ++#include "config.h" ++ ++#if HAVE_PTHREAD ++#include ++ ++struct sss_mutex { ++ pthread_mutex_t mtx; ++ ++ int old_cancel_state; ++}; ++ ++#endif /* HAVE_PTHREAD */ ++ ++#endif /* COMMON_PRIVATE_H_ */ +diff --git a/src/sss_client/idmap/common_ex.c b/src/sss_client/idmap/common_ex.c +new file mode 100644 +index 0000000000000000000000000000000000000000..5efe9fabed7896ce674615472dbb256c4eae2144 +--- /dev/null ++++ b/src/sss_client/idmap/common_ex.c +@@ -0,0 +1,105 @@ ++/* ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 Red Hat ++ ++ SSSD's enhanced NSS API ++ ++ 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 ++ ++#include "sss_cli.h" ++#include "common_private.h" ++ ++extern struct sss_mutex sss_nss_mtx; ++ ++#define SEC_FROM_MSEC(ms) ((ms) / 1000) ++#define NSEC_FROM_MSEC(ms) (((ms) % 1000) * 1000 * 1000) ++ ++/* adopted from timersub() defined in /usr/include/sys/time.h */ ++#define TIMESPECSUB(a, b, result) \ ++ do { \ ++ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ ++ (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \ ++ if ((result)->tv_nsec < 0) { \ ++ --(result)->tv_sec; \ ++ (result)->tv_nsec += 1000000000; \ ++ } \ ++ } while (0) ++ ++#define TIMESPEC_TO_MS(ts) ( ((ts)->tv_sec * 1000) \ ++ + ((ts)->tv_nsec) / (1000 * 1000) ) ++ ++static int sss_mt_timedlock(struct sss_mutex *m, struct timespec *endtime) ++{ ++ int ret; ++ ++ ret = pthread_mutex_timedlock(&m->mtx, endtime); ++ if (ret != 0) { ++ return ret; ++ } ++ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &m->old_cancel_state); ++ ++ return 0; ++} ++ ++int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms) ++{ ++ int ret; ++ int left; ++ struct timespec starttime; ++ struct timespec endtime; ++ struct timespec diff; ++ ++ /* make sure there is no overrun when calculating the time left */ ++ if (timeout_ms > INT_MAX) { ++ timeout_ms = INT_MAX; ++ } ++ ++ ret = clock_gettime(CLOCK_REALTIME, &starttime); ++ if (ret != 0) { ++ return ret; ++ } ++ endtime.tv_sec = starttime.tv_sec + SEC_FROM_MSEC(timeout_ms); ++ endtime.tv_nsec = starttime.tv_nsec + NSEC_FROM_MSEC(timeout_ms); ++ ++ ret = sss_mt_timedlock(&sss_nss_mtx, &endtime); ++ ++ if (ret == 0) { ++ ret = clock_gettime(CLOCK_REALTIME, &endtime); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if (timeout_ms == 0) { ++ *time_left_ms = 0; ++ } else { ++ TIMESPECSUB(&endtime, &starttime, &diff); ++ left = timeout_ms - TIMESPEC_TO_MS(&diff); ++ if (left <= 0) { ++ return EIO; ++ } else if (left > SSS_CLI_SOCKET_TIMEOUT) { ++ *time_left_ms = SSS_CLI_SOCKET_TIMEOUT; ++ } else { ++ *time_left_ms = left; ++ } ++ } ++ } ++ ++ return ret; ++} +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +new file mode 100644 +index 0000000000000000000000000000000000000000..582d1373ec35305cf128e04fd3d705457d304789 +--- /dev/null ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -0,0 +1,402 @@ ++/* ++ SSSD ++ ++ Extended NSS Responder Interface ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 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 ++ ++#include /* for MIN() */ ++ ++#include "sss_client/sss_cli.h" ++#include "sss_client/nss_mc.h" ++#include "sss_client/nss_common.h" ++#include "sss_client/idmap/sss_nss_idmap.h" ++#include "sss_client/idmap/sss_nss_idmap_private.h" ++ ++#ifndef discard_const ++#define discard_const(ptr) ((void *)((uintptr_t)(ptr))) ++#endif ++ ++struct sss_nss_initgr_rep { ++ gid_t *groups; ++ long int *ngroups; ++ long int *start; ++}; ++ ++struct nss_input { ++ union { ++ const char *name; ++ uid_t uid; ++ gid_t gid; ++ } input; ++ struct sss_cli_req_data rd; ++ enum sss_cli_command cmd; ++ union { ++ struct sss_nss_pw_rep pwrep; ++ struct sss_nss_gr_rep grrep; ++ struct sss_nss_initgr_rep initgrrep; ++ } result; ++}; ++ ++errno_t sss_nss_mc_get(struct nss_input *inp) ++{ ++ switch(inp->cmd) { ++ case SSS_NSS_GETPWNAM: ++ return sss_nss_mc_getpwnam(inp->input.name, (inp->rd.len - 1), ++ inp->result.pwrep.result, ++ inp->result.pwrep.buffer, ++ inp->result.pwrep.buflen); ++ break; ++ case SSS_NSS_GETPWUID: ++ return sss_nss_mc_getpwuid(inp->input.uid, ++ inp->result.pwrep.result, ++ inp->result.pwrep.buffer, ++ inp->result.pwrep.buflen); ++ break; ++ case SSS_NSS_GETGRNAM: ++ return sss_nss_mc_getgrnam(inp->input.name, (inp->rd.len - 1), ++ inp->result.grrep.result, ++ inp->result.grrep.buffer, ++ inp->result.grrep.buflen); ++ break; ++ case SSS_NSS_GETGRGID: ++ return sss_nss_mc_getgrgid(inp->input.gid, ++ inp->result.grrep.result, ++ inp->result.grrep.buffer, ++ inp->result.grrep.buflen); ++ break; ++ case SSS_NSS_INITGR: ++ return sss_nss_mc_initgroups_dyn(inp->input.name, (inp->rd.len - 1), ++ -1 /* currently ignored */, ++ inp->result.initgrrep.start, ++ inp->result.initgrrep.ngroups, ++ &(inp->result.initgrrep.groups), ++ *(inp->result.initgrrep.ngroups)); ++ break; ++ default: ++ return EINVAL; ++ } ++} ++ ++int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) ++{ ++ uint8_t *repbuf = NULL; ++ size_t replen; ++ size_t len; ++ uint32_t num_results; ++ int ret; ++ int time_left; ++ int errnop; ++ size_t c; ++ gid_t *new_groups; ++ size_t idx; ++ ++ ret = sss_nss_mc_get(inp); ++ switch (ret) { ++ case 0: ++ return 0; ++ case ERANGE: ++ return ERANGE; ++ case ENOENT: ++ /* fall through, we need to actively ask the parent ++ * if no entry is found */ ++ break; ++ default: ++ /* if using the mmaped cache failed, ++ * fall back to socket based comms */ ++ break; ++ } ++ ++ sss_nss_timedlock(timeout, &time_left); ++ ++ /* previous thread might already initialize entry in mmap cache */ ++ ret = sss_nss_mc_get(inp); ++ switch (ret) { ++ case 0: ++ ret = 0; ++ goto out; ++ case ERANGE: ++ ret = ERANGE; ++ goto out; ++ case ENOENT: ++ /* fall through, we need to actively ask the parent ++ * if no entry is found */ ++ break; ++ default: ++ /* if using the mmaped cache failed, ++ * fall back to socket based comms */ ++ break; ++ } ++ ++ ret = sss_nss_make_request_timeout(inp->cmd, &inp->rd, time_left, ++ &repbuf, &replen, &errnop); ++ if (ret != NSS_STATUS_SUCCESS) { ++ ret = errnop != 0 ? errnop : EIO; ++ goto out; ++ } ++ ++ /* Get number of results from repbuf. */ ++ SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL); ++ ++ /* no results if not found */ ++ if (num_results == 0) { ++ ret = ENOENT; ++ goto out; ++ } ++ ++ if (inp->cmd == SSS_NSS_INITGR) { ++ if ((*(inp->result.initgrrep.ngroups) - *(inp->result.initgrrep.start)) ++ < num_results) { ++ new_groups = realloc(inp->result.initgrrep.groups, ++ (num_results + *(inp->result.initgrrep.start)) ++ * sizeof(gid_t)); ++ if (new_groups == NULL) { ++ ret = ENOMEM; ++ goto out; ++ } ++ ++ inp->result.initgrrep.groups = new_groups; ++ } ++ *(inp->result.initgrrep.ngroups) = num_results ++ + *(inp->result.initgrrep.start); ++ ++ idx = 2 * sizeof(uint32_t); ++ for (c = 0; c < num_results; c++) { ++ SAFEALIGN_COPY_UINT32( ++ &(inp->result.initgrrep.groups[*(inp->result.initgrrep.start)]), ++ repbuf + idx, &idx); ++ *(inp->result.initgrrep.start) += 1; ++ } ++ ++ ret = 0; ++ goto out; ++ } ++ ++ /* only 1 result is accepted for this function */ ++ if (num_results != 1) { ++ ret = EBADMSG; ++ goto out; ++ } ++ ++ len = replen - 8; ++ if (inp->cmd == SSS_NSS_GETPWNAM || inp->cmd == SSS_NSS_GETPWUID) { ++ ret = sss_nss_getpw_readrep(&(inp->result.pwrep), repbuf+8, &len); ++ } else if (inp->cmd == SSS_NSS_GETGRNAM || inp->cmd == SSS_NSS_GETGRGID) { ++ ret = sss_nss_getgr_readrep(&(inp->result.grrep), repbuf+8, &len); ++ } else { ++ ret = EINVAL; ++ goto out; ++ } ++ if (ret) { ++ goto out; ++ } ++ ++ if (len == 0) { ++ /* no extra data */ ++ ret = 0; ++ goto out; ++ } ++ ++out: ++ free(repbuf); ++ ++ sss_nss_unlock(); ++ return ret; ++} ++ ++int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ uint32_t flags, unsigned int timeout) ++{ ++ int ret; ++ struct nss_input inp = { ++ .input.name = name, ++ .cmd = SSS_NSS_GETPWNAM, ++ .rd.data = name, ++ .result.pwrep.result = pwd, ++ .result.pwrep.buffer = buffer, ++ .result.pwrep.buflen = buflen}; ++ ++ if (buffer == NULL || buflen == 0) { ++ return ERANGE; ++ } ++ ++ ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ if (ret != 0) { ++ return EINVAL; ++ } ++ inp.rd.len++; ++ ++ *result = NULL; ++ ++ ret = sss_get_ex(&inp, flags, timeout); ++ if (ret == 0) { ++ *result = inp.result.pwrep.result; ++ } ++ return ret; ++} ++ ++int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ uint32_t flags, unsigned int timeout) ++{ ++ int ret; ++ uint32_t user_uid = uid; ++ struct nss_input inp = { ++ .input.uid = uid, ++ .cmd = SSS_NSS_GETPWUID, ++ .rd.len = sizeof(uint32_t), ++ .rd.data = &user_uid, ++ .result.pwrep.result = pwd, ++ .result.pwrep.buffer = buffer, ++ .result.pwrep.buflen = buflen}; ++ ++ if (buffer == NULL || buflen == 0) { ++ return ERANGE; ++ } ++ ++ *result = NULL; ++ ++ ret = sss_get_ex(&inp, flags, timeout); ++ if (ret == 0) { ++ *result = inp.result.pwrep.result; ++ } ++ return ret; ++} ++ ++int sss_nss_getgrnam_timeout(const char *name, struct group *grp, ++ char *buffer, size_t buflen, struct group **result, ++ uint32_t flags, unsigned int timeout) ++{ ++ int ret; ++ struct nss_input inp = { ++ .input.name = name, ++ .cmd = SSS_NSS_GETGRNAM, ++ .rd.data = name, ++ .result.grrep.result = grp, ++ .result.grrep.buffer = buffer, ++ .result.grrep.buflen = buflen}; ++ ++ if (buffer == NULL || buflen == 0) { ++ return ERANGE; ++ } ++ ++ ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ if (ret != 0) { ++ return EINVAL; ++ } ++ inp.rd.len++; ++ ++ *result = NULL; ++ ++ ret = sss_get_ex(&inp, flags, timeout); ++ if (ret == 0) { ++ *result = inp.result.grrep.result; ++ } ++ return ret; ++} ++ ++int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, ++ char *buffer, size_t buflen, struct group **result, ++ uint32_t flags, unsigned int timeout) ++{ ++ int ret; ++ uint32_t group_gid = gid; ++ struct nss_input inp = { ++ .input.gid = gid, ++ .cmd = SSS_NSS_GETGRGID, ++ .rd.len = sizeof(uint32_t), ++ .rd.data = &group_gid, ++ .result.grrep.result = grp, ++ .result.grrep.buffer = buffer, ++ .result.grrep.buflen = buflen}; ++ ++ if (buffer == NULL || buflen == 0) { ++ return ERANGE; ++ } ++ ++ *result = NULL; ++ ++ ret = sss_get_ex(&inp, flags, timeout); ++ if (ret == 0) { ++ *result = inp.result.grrep.result; ++ } ++ return ret; ++} ++ ++int sss_nss_getgrouplist_timeout(const char *name, gid_t group, ++ gid_t *groups, int *ngroups, ++ uint32_t flags, unsigned int timeout) ++{ ++ int ret; ++ gid_t *new_groups; ++ long int new_ngroups; ++ long int start = 1; ++ struct nss_input inp = { ++ .input.name = name, ++ .cmd = SSS_NSS_INITGR, ++ .rd.data = name}; ++ ++ if (groups == NULL || ngroups == NULL || *ngroups == 0) { ++ return EINVAL; ++ } ++ ++ ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ if (ret != 0) { ++ return ret; ++ } ++ inp.rd.len++; ++ ++ new_ngroups = MAX(1, *ngroups); ++ new_groups = malloc(new_ngroups * sizeof(gid_t)); ++ if (new_groups == NULL) { ++ free(discard_const(inp.rd.data)); ++ return ENOMEM; ++ } ++ new_groups[0] = group; ++ ++ inp.result.initgrrep.groups = new_groups, ++ inp.result.initgrrep.ngroups = &new_ngroups; ++ inp.result.initgrrep.start = &start; ++ ++ ++ ret = sss_get_ex(&inp, flags, timeout); ++ free(discard_const(inp.rd.data)); ++ if (ret != 0) { ++ free(new_groups); ++ return ret; ++ } ++ ++ memcpy(groups, new_groups, MIN(*ngroups, start) * sizeof(gid_t)); ++ free(new_groups); ++ ++ if (start > *ngroups) { ++ ret = ERANGE; ++ } else { ++ ret = 0; ++ } ++ *ngroups = start; ++ ++ return ret; ++} +diff --git a/src/sss_client/idmap/sss_nss_idmap.exports b/src/sss_client/idmap/sss_nss_idmap.exports +index 49dac6fc9351b0ca98cd46e83b85ec8ef0075a0d..788d05ecc3bd56fa88e68a98b9c8096cf7140a09 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.exports ++++ b/src/sss_client/idmap/sss_nss_idmap.exports +@@ -31,3 +31,13 @@ SSS_NSS_IDMAP_0.3.0 { + global: + sss_nss_getlistbycert; + } SSS_NSS_IDMAP_0.2.0; ++ ++SSS_NSS_IDMAP_0.4.0 { ++ # public functions ++ global: ++ sss_nss_getpwnam_timeout; ++ sss_nss_getpwuid_timeout; ++ sss_nss_getgrnam_timeout; ++ sss_nss_getgrgid_timeout; ++ sss_nss_getgrouplist_timeout; ++} SSS_NSS_IDMAP_0.3.0; +diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h +index cbf19479ff9ec6e0d6e07e1f7e48a1571e147740..2334b6cb3fb8ef62e4ce3a7187c7affaeaa034e7 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.h ++++ b/src/sss_client/idmap/sss_nss_idmap.h +@@ -26,6 +26,9 @@ + #define SSS_NSS_IDMAP_H_ + + #include ++#include ++#include ++#include + + /** + * Object types +@@ -159,4 +162,136 @@ int sss_nss_getlistbycert(const char *cert, char ***fq_name, + * @param[in] kv_list Key-value list returned by sss_nss_getorigbyname(). + */ + void sss_nss_free_kv(struct sss_nss_kv *kv_list); ++ ++/** ++ * Flags to control the behavior and the results for sss_*_ex() calls ++ */ ++ ++#define SSS_NSS_EX_FLAG_NO_FLAGS 0 ++ ++#ifdef IPA_389DS_PLUGIN_HELPER_CALLS ++ ++/** ++ * @brief Return user information based on the user name ++ * ++ * @param[in] name same as for getpwnam_r(3) ++ * @param[in] pwd same as for getpwnam_r(3) ++ * @param[in] buffer same as for getpwnam_r(3) ++ * @param[in] buflen same as for getpwnam_r(3) ++ * @param[out] result same as for getpwnam_r(3) ++ * @param[in] flags flags to control the behavior and the results of the ++ * call ++ * @param[in] timeout timeout in milliseconds ++ * ++ * @return ++ * - 0: ++ * - ENOENT: no user with the given name found ++ * - ERANGE: Insufficient buffer space supplied ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ uint32_t flags, unsigned int timeout); ++ ++/** ++ * @brief Return user information based on the user uid ++ * ++ * @param[in] uid same as for getpwuid_r(3) ++ * @param[in] pwd same as for getpwuid_r(3) ++ * @param[in] buffer same as for getpwuid_r(3) ++ * @param[in] buflen same as for getpwuid_r(3) ++ * @param[out] result same as for getpwuid_r(3) ++ * @param[in] flags flags to control the behavior and the results of the ++ * call ++ * @param[in] timeout timeout in milliseconds ++ * ++ * @return ++ * - 0: ++ * - ENOENT: no user with the given uid found ++ * - ERANGE: Insufficient buffer space supplied ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ uint32_t flags, unsigned int timeout); ++ ++/** ++ * @brief Return group information based on the group name ++ * ++ * @param[in] name same as for getgrnam_r(3) ++ * @param[in] pwd same as for getgrnam_r(3) ++ * @param[in] buffer same as for getgrnam_r(3) ++ * @param[in] buflen same as for getgrnam_r(3) ++ * @param[out] result same as for getgrnam_r(3) ++ * @param[in] flags flags to control the behavior and the results of the ++ * call ++ * @param[in] timeout timeout in milliseconds ++ * ++ * @return ++ * - 0: ++ * - ENOENT: no group with the given name found ++ * - ERANGE: Insufficient buffer space supplied ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getgrnam_timeout(const char *name, struct group *grp, ++ char *buffer, size_t buflen, struct group **result, ++ uint32_t flags, unsigned int timeout); ++ ++/** ++ * @brief Return group information based on the group gid ++ * ++ * @param[in] gid same as for getgrgid_r(3) ++ * @param[in] pwd same as for getgrgid_r(3) ++ * @param[in] buffer same as for getgrgid_r(3) ++ * @param[in] buflen same as for getgrgid_r(3) ++ * @param[out] result same as for getgrgid_r(3) ++ * @param[in] flags flags to control the behavior and the results of the ++ * call ++ * @param[in] timeout timeout in milliseconds ++ * ++ * @return ++ * - 0: ++ * - ENOENT: no group with the given gid found ++ * - ERANGE: Insufficient buffer space supplied ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, ++ char *buffer, size_t buflen, struct group **result, ++ uint32_t flags, unsigned int timeout); ++ ++/** ++ * @brief Return a list of groups to which a user belongs ++ * ++ * @param[in] name name of the user ++ * @param[in] group same as second argument of getgrouplist(3) ++ * @param[in] groups array of gid_t of size ngroups, will be filled ++ * with GIDs of groups the user belongs to ++ * @param[in,out] ngroups size of the groups array on input. On output it ++ * will contain the actual number of groups the ++ * user belongs to. With a return value of 0 the ++ * groups array was large enough to hold all group. ++ * With a return valu of ERANGE the array was not ++ * large enough and ngroups will have the needed ++ * size. ++ * @param[in] flags flags to control the behavior and the results of ++ * the call ++ * @param[in] timeout timeout in milliseconds ++ * ++ * @return ++ * - 0: success ++ * - ENOENT: no user with the given name found ++ * - ERANGE: Insufficient buffer space supplied ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getgrouplist_timeout(const char *name, gid_t group, ++ gid_t *groups, int *ngroups, ++ uint32_t flags, unsigned int timeout); ++#endif /* IPA_389DS_PLUGIN_HELPER_CALLS */ + #endif /* SSS_NSS_IDMAP_H_ */ +diff --git a/src/sss_client/idmap/sss_nss_idmap_private.h b/src/sss_client/idmap/sss_nss_idmap_private.h +new file mode 100644 +index 0000000000000000000000000000000000000000..afcd8e355981b9a2dc29a62bab143756b39ed654 +--- /dev/null ++++ b/src/sss_client/idmap/sss_nss_idmap_private.h +@@ -0,0 +1,30 @@ ++/* ++ SSSD ++ ++ NSS Responder ID-mapping interface - private calls ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 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 . ++*/ ++ ++#ifndef SSS_NSS_IDMAP_PRIVATE_H_ ++#define SSS_NSS_IDMAP_PRIVATE_H_ ++ ++int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms); ++ ++#endif /* SSS_NSS_IDMAP_PRIVATE_H_ */ +-- +2.13.6 + diff --git a/SOURCES/0024-KCM-Implement-an-internal-ccache-storage-and-retriev.patch b/SOURCES/0024-KCM-Implement-an-internal-ccache-storage-and-retriev.patch deleted file mode 100644 index a5e0fc2..0000000 --- a/SOURCES/0024-KCM-Implement-an-internal-ccache-storage-and-retriev.patch +++ /dev/null @@ -1,2153 +0,0 @@ -From 79f6ccd2dc3f0c1369d5a93678c88ee76ec761e0 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 7 Mar 2017 13:49:21 +0100 -Subject: [PATCH 24/36] KCM: Implement an internal ccache storage and retrieval - API -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In order for the KCM server to work with ccaches stored in different -locations, implement a middle-man between the KCM server and the ccache -storage. - -This module has asynchronous API because we can't assume anything about -where the ccaches are stored. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - Makefile.am | 9 + - configure.ac | 1 + - contrib/sssd.spec.in | 1 + - src/external/libuuid.m4 | 17 + - src/responder/kcm/kcmsrv_ccache.c | 1423 +++++++++++++++++++++++++++++++++ - src/responder/kcm/kcmsrv_ccache.h | 306 +++++++ - src/responder/kcm/kcmsrv_ccache_be.h | 204 +++++ - src/responder/kcm/kcmsrv_ccache_pvt.h | 62 ++ - src/responder/kcm/kcmsrv_pvt.h | 1 + - 9 files changed, 2024 insertions(+) - create mode 100644 src/external/libuuid.m4 - create mode 100644 src/responder/kcm/kcmsrv_ccache.c - create mode 100644 src/responder/kcm/kcmsrv_ccache.h - create mode 100644 src/responder/kcm/kcmsrv_ccache_be.h - create mode 100644 src/responder/kcm/kcmsrv_ccache_pvt.h - -diff --git a/Makefile.am b/Makefile.am -index 4248536e90370c1aab59549a9c18408ef314e6d4..a2b9dc49e95fa2d025f5174d2902866fab180a78 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -711,6 +711,9 @@ dist_noinst_HEADERS = \ - src/responder/secrets/secsrv_proxy.h \ - src/responder/kcm/kcm.h \ - src/responder/kcm/kcmsrv_pvt.h \ -+ src/responder/kcm/kcmsrv_ccache.h \ -+ src/responder/kcm/kcmsrv_ccache_pvt.h \ -+ src/responder/kcm/kcmsrv_ccache_be.h \ - src/sbus/sbus_client.h \ - src/sbus/sssd_dbus.h \ - src/sbus/sssd_dbus_meta.h \ -@@ -1488,16 +1491,22 @@ if BUILD_KCM - sssd_kcm_SOURCES = \ - src/responder/kcm/kcm.c \ - src/responder/kcm/kcmsrv_cmd.c \ -+ src/responder/kcm/kcmsrv_ccache.c \ - src/util/sss_sockets.c \ -+ src/util/sss_krb5.c \ -+ src/util/sss_iobuf.c \ - $(SSSD_RESPONDER_OBJ) \ - $(NULL) - sssd_kcm_CFLAGS = \ - $(AM_CFLAGS) \ - $(KRB5_CFLAGS) \ -+ $(UUID_CFLAGS) \ - $(NULL) - sssd_kcm_LDADD = \ - $(KRB5_LIBS) \ - $(SSSD_LIBS) \ -+ $(UUID_LIBS) \ -+ $(SYSTEMD_DAEMON_LIBS) \ - $(SSSD_INTERNAL_LTLIBS) \ - $(NULL) - endif -diff --git a/configure.ac b/configure.ac -index c363d48a806cc1998e85779a92b6b59b0e2a5c9c..cf5e2557ef0a1bd6374200aa33abea6c509d03aa 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -202,6 +202,7 @@ fi - - if test x$with_kcm = xyes; then - m4_include([src/external/libcurl.m4]) -+ m4_include([src/external/libuuid.m4]) - fi - # This variable is defined by external/libcurl.m4, but conditionals - # must be always evaluated -diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in -index 5c7c2af521a84ef2ca6cca7b2d6cd1f9b3057056..52d33b4de281dc1d91a9027ac1c8c878e66fb396 100644 ---- a/contrib/sssd.spec.in -+++ b/contrib/sssd.spec.in -@@ -222,6 +222,7 @@ BuildRequires: systemtap-sdt-devel - %endif - BuildRequires: http-parser-devel - BuildRequires: jansson-devel -+BuildRequires: libuuid-devel - - %description - Provides a set of daemons to manage access to remote directories and -diff --git a/src/external/libuuid.m4 b/src/external/libuuid.m4 -new file mode 100644 -index 0000000000000000000000000000000000000000..55411a2118bd787c9d50ba61f9cb791e1c76088d ---- /dev/null -+++ b/src/external/libuuid.m4 -@@ -0,0 +1,17 @@ -+AC_SUBST(UUID_LIBS) -+AC_SUBST(UUID_CFLAGS) -+ -+PKG_CHECK_MODULES([UUID], [uuid], [found_uuid=yes], [found_uuid=no]) -+ -+SSS_AC_EXPAND_LIB_DIR() -+AS_IF([test x"$found_uuid" = xyes], -+ [AC_CHECK_HEADERS([uuid/uuid.h], -+ [AC_CHECK_LIB([uuid], -+ [uuid_generate], -+ [UUID_LIBS="-L$sss_extra_libdir -luuid"], -+ [AC_MSG_ERROR([libuuid missing uuid_generate])], -+ [-L$sss_extra_libdir -luuid])], -+ [AC_MSG_ERROR([ -+You must have the header file uuid.h installed to build sssd -+with KCM responder. If you want to build sssd without KCM responder -+then specify --without-kcm when running configure.])])]) -diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c -new file mode 100644 -index 0000000000000000000000000000000000000000..2c565b8378e3ec297faf655d3c48d7ab902713d3 ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_ccache.c -@@ -0,0 +1,1423 @@ -+/* -+ SSSD -+ -+ KCM Server - the KCM ccache operations -+ -+ Copyright (C) Red Hat, 2016 -+ -+ 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 "config.h" -+ -+#include "util/crypto/sss_crypto.h" -+#include "util/util.h" -+#include "util/sss_krb5.h" -+#include "responder/kcm/kcmsrv_ccache.h" -+#include "responder/kcm/kcmsrv_ccache_pvt.h" -+#include "responder/kcm/kcmsrv_ccache_be.h" -+ -+static int kcm_cc_destructor(struct kcm_ccache *cc) -+{ -+ if (cc == NULL) { -+ return 0; -+ } -+ -+ krb5_free_principal(NULL, cc->client); -+ return 0; -+} -+ -+errno_t kcm_cc_new(TALLOC_CTX *mem_ctx, -+ krb5_context k5c, -+ struct cli_creds *owner, -+ const char *name, -+ krb5_principal princ, -+ struct kcm_ccache **_cc) -+{ -+ struct kcm_ccache *cc; -+ krb5_error_code kret; -+ errno_t ret; -+ -+ cc = talloc_zero(mem_ctx, struct kcm_ccache); -+ if (cc == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = kcm_check_name(name, owner); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Name %s is malformed\n", name); -+ return ret; -+ } -+ -+ cc->name = talloc_strdup(cc, name); -+ if (cc->name == NULL) { -+ talloc_free(cc); -+ return ENOMEM; -+ } -+ -+ uuid_generate(cc->uuid); -+ -+ kret = krb5_copy_principal(k5c, princ, &cc->client); -+ if (kret != 0) { -+ const char *err_msg = sss_krb5_get_error_message(k5c, kret); -+ DEBUG(SSSDBG_OP_FAILURE, -+ "krb5_copy_principal failed: [%d][%s]\n", kret, err_msg); -+ sss_krb5_free_error_message(k5c, err_msg); -+ talloc_free(cc); -+ return ERR_INTERNAL; -+ } -+ -+ cc->owner.uid = cli_creds_get_uid(owner); -+ cc->owner.gid = cli_creds_get_gid(owner); -+ cc->kdc_offset = INT32_MAX; -+ -+ talloc_set_destructor(cc, kcm_cc_destructor); -+ *_cc = cc; -+ return EOK; -+} -+ -+const char *kcm_cc_get_name(struct kcm_ccache *cc) -+{ -+ return cc ? cc->name : NULL; -+} -+ -+errno_t kcm_cc_get_uuid(struct kcm_ccache *cc, uuid_t _uuid) -+{ -+ if (cc == NULL) { -+ return EINVAL; -+ } -+ uuid_copy(_uuid, cc->uuid); -+ return EOK; -+} -+ -+krb5_principal kcm_cc_get_client_principal(struct kcm_ccache *cc) -+{ -+ return cc ? cc->client : NULL; -+} -+ -+bool kcm_cc_access(struct kcm_ccache *cc, -+ struct cli_creds *client) -+{ -+ bool ok; -+ uid_t uid = cli_creds_get_uid(client); -+ gid_t gid = cli_creds_get_gid(client); -+ -+ if (cc == NULL) { -+ return false; -+ } -+ -+ if (uid == 0 && gid == 0) { -+ /* root can access any ccache */ -+ return true; -+ } -+ -+ ok = ((cc->owner.uid == uid) && (cc->owner.gid == gid)); -+ if (!ok) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Client %"SPRIuid":%"SPRIgid" has no access to ccache %s\n", -+ cli_creds_get_uid(client), -+ cli_creds_get_gid(client), -+ cc->name); -+ } -+ return ok; -+} -+ -+int32_t kcm_cc_get_offset(struct kcm_ccache *cc) -+{ -+ return cc ? cc->kdc_offset : INT32_MAX; -+} -+ -+errno_t kcm_cc_store_cred_blob(struct kcm_ccache *cc, -+ struct sss_iobuf *cred_blob) -+{ -+ struct kcm_cred *kcreds; -+ uuid_t uuid; -+ errno_t ret; -+ -+ if (cc == NULL || cred_blob == NULL) { -+ return EINVAL; -+ } -+ -+ uuid_generate(uuid); -+ kcreds = kcm_cred_new(cc, uuid, cred_blob); -+ if (kcreds == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = kcm_cc_store_creds(cc, kcreds); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ return EOK; -+} -+ -+struct kcm_cred *kcm_cc_get_cred(struct kcm_ccache *cc) -+{ -+ if (cc == NULL) { -+ return NULL; -+ } -+ -+ return cc->creds; -+} -+ -+struct kcm_cred *kcm_cc_next_cred(struct kcm_cred *crd) -+{ -+ if (crd == NULL) { -+ return NULL; -+ } -+ -+ return crd->next; -+} -+ -+struct kcm_cred *kcm_cred_new(TALLOC_CTX *mem_ctx, -+ uuid_t uuid, -+ struct sss_iobuf *cred_blob) -+{ -+ struct kcm_cred *kcreds; -+ -+ kcreds = talloc_zero(mem_ctx, struct kcm_cred); -+ if (kcreds == NULL) { -+ return NULL; -+ } -+ -+ uuid_copy(kcreds->uuid, uuid); -+ kcreds->cred_blob = talloc_steal(kcreds, cred_blob); -+ return kcreds; -+} -+ -+/* Add a cred to ccache */ -+errno_t kcm_cc_store_creds(struct kcm_ccache *cc, -+ struct kcm_cred *crd) -+{ -+ DLIST_ADD(cc->creds, crd); -+ talloc_steal(cc, crd); -+ return EOK; -+} -+ -+errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t _uuid) -+{ -+ if (crd == NULL) { -+ return EINVAL; -+ } -+ uuid_copy(_uuid, crd->uuid); -+ return EOK; -+} -+ -+struct sss_iobuf *kcm_cred_get_creds(struct kcm_cred *crd) -+{ -+ return crd ? crd->cred_blob : NULL; -+} -+ -+struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ enum kcm_ccdb_be cc_be) -+{ -+ errno_t ret; -+ struct kcm_ccdb *ccdb = NULL; -+ -+ if (ev == NULL) { -+ return NULL; -+ } -+ -+ ccdb = talloc_zero(mem_ctx, struct kcm_ccdb); -+ if (ccdb == NULL) { -+ return NULL; -+ } -+ ccdb->ev = ev; -+ -+ switch (cc_be) { -+ case CCDB_BE_MEMORY: -+ DEBUG(SSSDBG_FUNC_DATA, "KCM back end: memory\n"); -+ /* Not implemented yet */ -+ break; -+ case CCDB_BE_SECRETS: -+ DEBUG(SSSDBG_FUNC_DATA, "KCM back end: sssd-secrets\n"); -+ /* Not implemented yet */ -+ break; -+ default: -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unknown ccache database\n"); -+ break; -+ } -+ -+ if (ccdb->ops == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Ccache database not initialized\n"); -+ talloc_free(ccdb); -+ return NULL; -+ } -+ -+ ret = ccdb->ops->init(ccdb); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize ccache database\n"); -+ talloc_free(ccdb); -+ return NULL; -+ } -+ -+ return ccdb; -+} -+ -+struct kcm_ccdb_nextid_state { -+ char *next_cc; -+ struct kcm_ccdb *db; -+ struct cli_creds *client; -+}; -+ -+static void kcm_ccdb_nextid_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_nextid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_nextid_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_nextid_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ state->client = client; -+ -+ if (ev == NULL || db == NULL || client == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ subreq = state->db->ops->nextid_send(mem_ctx, ev, state->db, client); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_nextid_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_nextid_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_nextid_state *state = tevent_req_data(req, -+ struct kcm_ccdb_nextid_state); -+ errno_t ret; -+ unsigned int nextid; -+ -+ ret = state->db->ops->nextid_recv(subreq, &nextid); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to generate next UID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ state->next_cc = talloc_asprintf(state, "%"SPRIuid":%u", -+ cli_creds_get_uid(state->client), -+ nextid); -+ if (state->next_cc == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed\n"); -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "generated %s\n", state->next_cc); -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_nextid_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ char **_next_cc) -+{ -+ struct kcm_ccdb_nextid_state *state = tevent_req_data(req, -+ struct kcm_ccdb_nextid_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_next_cc = talloc_steal(mem_ctx, state->next_cc); -+ return EOK; -+} -+ -+struct kcm_ccdb_list_state { -+ struct kcm_ccdb *db; -+ struct cli_creds *client; -+ -+ uuid_t *uuid_list; -+}; -+ -+static void kcm_ccdb_list_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_list_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_list_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_list_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ state->client = client; -+ -+ if (ev == NULL || db == NULL || client == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ subreq = state->db->ops->list_send(mem_ctx, -+ ev, -+ state->db, -+ client); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_list_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_list_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_list_state *state = tevent_req_data(req, -+ struct kcm_ccdb_list_state); -+ errno_t ret; -+ -+ ret = state->db->ops->list_recv(subreq, state, &state->uuid_list); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to list all ccaches [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_list_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ uuid_t **_uuid_list) -+{ -+ struct kcm_ccdb_list_state *state = tevent_req_data(req, -+ struct kcm_ccdb_list_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_uuid_list = talloc_steal(mem_ctx, state->uuid_list); -+ return EOK; -+} -+ -+struct kcm_ccdb_get_default_state { -+ struct kcm_ccdb *db; -+ uuid_t uuid; -+}; -+ -+static void kcm_ccdb_get_default_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_get_default_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_get_default_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_get_default_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ -+ if (ev == NULL || db == NULL || client == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ subreq = db->ops->get_default_send(mem_ctx, ev, db, client); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_get_default_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_get_default_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_get_default_state *state = tevent_req_data(req, -+ struct kcm_ccdb_get_default_state); -+ errno_t ret; -+ -+ ret = state->db->ops->get_default_recv(subreq, state->uuid); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to get the default ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_get_default_recv(struct tevent_req *req, -+ uuid_t *uuid) -+{ -+ struct kcm_ccdb_get_default_state *state = tevent_req_data(req, -+ struct kcm_ccdb_get_default_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ -+ if (uuid != NULL) { -+ /* The caller might supply a NULL dfl to just check if there is -+ * some default ccache -+ */ -+ uuid_copy(*uuid, state->uuid); -+ } -+ -+ return EOK; -+} -+ -+struct kcm_ccdb_set_default_state { -+ struct tevent_context *ev; -+ struct kcm_ccdb *db; -+ struct cli_creds *client; -+ uuid_t uuid; -+}; -+ -+static void kcm_ccdb_set_default_uuid_resolved(struct tevent_req *subreq); -+static void kcm_ccdb_set_default_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_set_default_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_set_default_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_set_default_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ state->ev = ev; -+ state->client = client; -+ uuid_copy(state->uuid, uuid); -+ -+ if (ev == NULL || db == NULL || client == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ if (uuid_is_null(uuid)) { -+ /* NULL UUID means to just reset the default to 'no default' */ -+ subreq = state->db->ops->set_default_send(state, -+ state->ev, -+ state->db, -+ state->client, -+ state->uuid); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_set_default_done, req); -+ } else { -+ /* Otherwise we need to check if the client can access the UUID -+ * about to be set as default -+ */ -+ subreq = db->ops->getbyuuid_send(state, ev, db, client, uuid); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_set_default_uuid_resolved, req); -+ } -+ -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_set_default_uuid_resolved(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_set_default_state *state = tevent_req_data(req, -+ struct kcm_ccdb_set_default_state); -+ errno_t ret; -+ bool ok; -+ struct kcm_ccache *cc; -+ -+ ret = state->db->ops->getbyuuid_recv(subreq, state, &cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to get cache by UUID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (cc == NULL) { -+ DEBUG(SSSDBG_TRACE_LIBS, "No cache found by UUID\n"); -+ tevent_req_error(req, ERR_KCM_CC_END); -+ return; -+ } -+ -+ ok = kcm_cc_access(cc, state->client); -+ if (!ok) { -+ tevent_req_error(req, EACCES); -+ return; -+ } -+ -+ subreq = state->db->ops->set_default_send(state, -+ state->ev, -+ state->db, -+ state->client, -+ state->uuid); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_set_default_done, req); -+} -+ -+static void kcm_ccdb_set_default_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_set_default_state *state = tevent_req_data(req, -+ struct kcm_ccdb_set_default_state); -+ errno_t ret; -+ -+ ret = state->db->ops->set_default_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to set the default ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_set_default_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+struct kcm_ccdb_getbyname_state { -+ struct kcm_ccdb *db; -+ struct cli_creds *client; -+ -+ struct kcm_ccache *cc; -+}; -+ -+static void kcm_ccdb_getbyname_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_getbyname_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ const char *name) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_getbyname_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_getbyname_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ state->client = client; -+ -+ if (ev == NULL || db == NULL || client == NULL || name == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ subreq = db->ops->getbyname_send(state, ev, db, client, name); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_getbyname_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_getbyname_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_getbyname_state *state = tevent_req_data(req, -+ struct kcm_ccdb_getbyname_state); -+ errno_t ret; -+ bool ok; -+ -+ ret = state->db->ops->getbyname_recv(subreq, state, &state->cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to get cache by name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (state->cc == NULL) { -+ DEBUG(SSSDBG_TRACE_LIBS, "No cache found by name\n"); -+ tevent_req_done(req); -+ return; -+ } -+ -+ ok = kcm_cc_access(state->cc, state->client); -+ if (!ok) { -+ tevent_req_error(req, EACCES); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_getbyname_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc) -+{ -+ struct kcm_ccdb_getbyname_state *state = tevent_req_data(req, -+ struct kcm_ccdb_getbyname_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_cc = talloc_steal(mem_ctx, state->cc); -+ return EOK; -+} -+ -+struct kcm_ccdb_getbyuuid_state { -+ struct kcm_ccdb *db; -+ struct cli_creds *client; -+ -+ struct kcm_ccache *cc; -+}; -+ -+static void kcm_ccdb_getbyuuid_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_getbyuuid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_getbyuuid_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_getbyuuid_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ state->client = client; -+ -+ if (ev == NULL || db == NULL || client == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ subreq = db->ops->getbyuuid_send(state, ev, db, client, uuid); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_getbyuuid_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_getbyuuid_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_getbyuuid_state *state = tevent_req_data(req, -+ struct kcm_ccdb_getbyuuid_state); -+ errno_t ret; -+ bool ok; -+ -+ ret = state->db->ops->getbyuuid_recv(subreq, state, &state->cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to get cache by UUID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (state->cc == NULL) { -+ DEBUG(SSSDBG_TRACE_LIBS, "No cache found by UUID\n"); -+ tevent_req_done(req); -+ return; -+ } -+ -+ ok = kcm_cc_access(state->cc, state->client); -+ if (!ok) { -+ tevent_req_error(req, EACCES); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_getbyuuid_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc) -+{ -+ struct kcm_ccdb_getbyuuid_state *state = tevent_req_data(req, -+ struct kcm_ccdb_getbyuuid_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_cc = talloc_steal(mem_ctx, state->cc); -+ return EOK; -+} -+ -+struct kcm_ccdb_name_by_uuid_state { -+ struct kcm_ccdb *db; -+ struct cli_creds *client; -+ -+ const char *name; -+}; -+ -+static void kcm_ccdb_name_by_uuid_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_name_by_uuid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_name_by_uuid_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, -+ &state, -+ struct kcm_ccdb_name_by_uuid_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ state->client = client; -+ -+ if (ev == NULL || db == NULL || client == NULL || uuid_is_null(uuid)) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ subreq = db->ops->name_by_uuid_send(state, ev, db, client, uuid); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_name_by_uuid_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_name_by_uuid_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_name_by_uuid_state *state = tevent_req_data(req, -+ struct kcm_ccdb_name_by_uuid_state); -+ errno_t ret; -+ -+ ret = state->db->ops->name_by_uuid_recv(subreq, state, &state->name); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to resolve cache by UUID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_name_by_uuid_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ const char **_name) -+{ -+ struct kcm_ccdb_name_by_uuid_state *state = tevent_req_data(req, -+ struct kcm_ccdb_name_by_uuid_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_name = talloc_steal(mem_ctx, state->name); -+ return EOK; -+} -+ -+struct kcm_ccdb_uuid_by_name_state { -+ struct kcm_ccdb *db; -+ struct cli_creds *client; -+ -+ uuid_t uuid; -+}; -+ -+static void kcm_ccdb_uuid_by_name_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_uuid_by_name_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ const char *name) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_uuid_by_name_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, -+ &state, -+ struct kcm_ccdb_uuid_by_name_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ state->client = client; -+ -+ if (ev == NULL || db == NULL || client == NULL || name == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ subreq = db->ops->uuid_by_name_send(state, ev, db, client, name); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_uuid_by_name_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_uuid_by_name_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_uuid_by_name_state *state = tevent_req_data(req, -+ struct kcm_ccdb_uuid_by_name_state); -+ errno_t ret; -+ -+ ret = state->db->ops->uuid_by_name_recv(subreq, state, state->uuid); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to resolve cache by UUID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_uuid_by_name_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ uuid_t _uuid) -+{ -+ struct kcm_ccdb_uuid_by_name_state *state = tevent_req_data(req, -+ struct kcm_ccdb_uuid_by_name_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ uuid_copy(_uuid, state->uuid); -+ return EOK; -+} -+ -+struct kcm_ccdb_create_cc_state { -+ struct kcm_ccdb *db; -+}; -+ -+static void kcm_ccdb_create_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_create_cc_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ struct kcm_ccache *cc) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_create_cc_state *state = NULL; -+ errno_t ret; -+ bool ok; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_create_cc_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ -+ if (ev == NULL || db == NULL || client == NULL || cc == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ ok = kcm_cc_access(cc, client); -+ if (!ok) { -+ ret = EACCES; -+ goto immediate; -+ } -+ -+ subreq = state->db->ops->create_send(mem_ctx, -+ ev, -+ state->db, -+ client, -+ cc); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_create_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_create_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_create_cc_state *state = tevent_req_data(req, -+ struct kcm_ccdb_create_cc_state); -+ errno_t ret; -+ -+ ret = state->db->ops->create_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to create ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_create_cc_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+void kcm_mod_ctx_clear(struct kcm_mod_ctx *mod_ctx) -+{ -+ if (mod_ctx == NULL) { -+ return; -+ } -+ -+ mod_ctx->kdc_offset = INT32_MAX; -+} -+ -+void kcm_mod_cc(struct kcm_ccache *cc, struct kcm_mod_ctx *mod_ctx) -+{ -+ if (cc == NULL || mod_ctx == NULL) { -+ return; -+ } -+ -+ if (mod_ctx->kdc_offset != INT32_MAX) { -+ cc->kdc_offset = mod_ctx->kdc_offset; -+ } -+ -+} -+ -+struct kcm_ccdb_mod_cc_state { -+ struct kcm_ccdb *db; -+}; -+ -+static void kcm_ccdb_mod_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_mod_cc_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid, -+ struct kcm_mod_ctx *mod_cc) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_mod_cc_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_mod_cc_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ -+ if (ev == NULL || db == NULL || client == NULL || mod_cc == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ subreq = state->db->ops->mod_send(mem_ctx, -+ ev, -+ state->db, -+ client, -+ uuid, -+ mod_cc); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_mod_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_mod_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_mod_cc_state *state = tevent_req_data(req, -+ struct kcm_ccdb_mod_cc_state); -+ errno_t ret; -+ -+ ret = state->db->ops->mod_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to create ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_mod_cc_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+struct kcm_ccdb_store_cred_blob_state { -+ struct kcm_ccdb *db; -+}; -+ -+static void kcm_ccdb_store_cred_blob_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_store_cred_blob_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid, -+ struct sss_iobuf *cred_blob) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_store_cred_blob_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_store_cred_blob_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ -+ if (ev == NULL || db == NULL || client == NULL || cred_blob == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ subreq = state->db->ops->store_cred_send(mem_ctx, -+ ev, -+ state->db, -+ client, -+ uuid, -+ cred_blob); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_store_cred_blob_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_store_cred_blob_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_store_cred_blob_state *state = tevent_req_data(req, -+ struct kcm_ccdb_store_cred_blob_state); -+ errno_t ret; -+ -+ ret = state->db->ops->store_cred_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to create ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_store_cred_blob_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+struct kcm_ccdb_delete_cc_state { -+ struct tevent_context *ev; -+ struct kcm_ccdb *db; -+ struct cli_creds *client; -+ uuid_t uuid; -+}; -+ -+static void kcm_ccdb_delete_done(struct tevent_req *subreq); -+static void kcm_ccdb_delete_get_default_done(struct tevent_req *subreq); -+static void kcm_ccdb_delete_default_reset_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_ccdb_delete_cc_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_ccdb_delete_cc_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_delete_cc_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->db = db; -+ state->ev = ev; -+ state->client = client; -+ uuid_copy(state->uuid, uuid); -+ -+ if (ev == NULL || db == NULL || client == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ subreq = state->db->ops->delete_send(state, -+ state->ev, -+ state->db, -+ state->client, -+ state->uuid); -+ tevent_req_set_callback(subreq, kcm_ccdb_delete_done, req); -+ -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_ccdb_delete_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_delete_cc_state *state = tevent_req_data(req, -+ struct kcm_ccdb_delete_cc_state); -+ errno_t ret; -+ -+ ret = state->db->ops->delete_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to delete ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ /* The delete operation must also check if the deleted ccache was -+ * the default and reset the default if it was -+ */ -+ subreq = state->db->ops->get_default_send(state, -+ state->ev, -+ state->db, -+ state->client); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_delete_get_default_done, req); -+} -+ -+static void kcm_ccdb_delete_get_default_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_delete_cc_state *state = tevent_req_data(req, -+ struct kcm_ccdb_delete_cc_state); -+ errno_t ret; -+ uuid_t dfl_uuid; -+ uuid_t null_uuid; -+ -+ ret = state->db->ops->get_default_recv(subreq, dfl_uuid); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to get the default ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (uuid_compare(dfl_uuid, state->uuid) != 0) { -+ /* The ccache about to be deleted was not the default, quit */ -+ tevent_req_done(req); -+ return; -+ } -+ -+ /* If we deleted the default ccache, reset the default ccache to 'none' */ -+ uuid_clear(null_uuid); -+ -+ subreq = state->db->ops->set_default_send(state, -+ state->ev, -+ state->db, -+ state->client, -+ null_uuid); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_ccdb_delete_default_reset_done, req); -+} -+ -+static void kcm_ccdb_delete_default_reset_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_ccdb_delete_cc_state *state = tevent_req_data(req, -+ struct kcm_ccdb_delete_cc_state); -+ errno_t ret; -+ -+ ret = state->db->ops->set_default_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to NULL the default ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_ccdb_delete_cc_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+void kcm_debug_uuid(uuid_t uuid) -+{ -+ char dbgbuf[UUID_STR_SIZE]; -+ -+ if (!(debug_level & SSSDBG_TRACE_ALL) || uuid == NULL) { -+ return; -+ } -+ -+ uuid_unparse(uuid, dbgbuf); -+ DEBUG(SSSDBG_TRACE_ALL, "UUID: %s\n", dbgbuf); -+} -+ -+errno_t kcm_check_name(const char *name, struct cli_creds *client) -+{ -+ char prefix[64]; -+ size_t prefix_len; -+ -+ prefix_len = snprintf(prefix, sizeof(prefix), -+ "%"SPRIuid, cli_creds_get_uid(client)); -+ -+ if (strncmp(name, prefix, prefix_len) != 0) { -+ return ERR_KCM_WRONG_CCNAME_FORMAT; -+ } -+ return EOK; -+} -diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h -new file mode 100644 -index 0000000000000000000000000000000000000000..130ae48ae30d5e1e2ab238a647a9b9dc76cc4945 ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_ccache.h -@@ -0,0 +1,306 @@ -+/* -+ SSSD -+ -+ KCM Server - the KCM ccache operations -+ -+ Copyright (C) Red Hat, 2016 -+ -+ 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 . -+*/ -+#ifndef _KCMSRV_CCACHE_H_ -+#define _KCMSRV_CCACHE_H_ -+ -+#include "config.h" -+ -+#include -+#include -+ -+#include "util/util.h" -+#include "util/sss_iobuf.h" -+#include "util/util_creds.h" -+ -+#define UUID_BYTES 16 -+#define UUID_STR_SIZE 37 -+ -+/* -+ * Credentials are opaque to the KCM server -+ * -+ * Each ccache has a unique UUID. -+ */ -+struct kcm_cred; -+ -+/* -+ * An opaque ccache type and its operations -+ * -+ * Contains zero or some KCM credentials. One credential in the cache -+ * is marked as the default one. The client can set and get the default -+ * cache (e.g. with kswitch) but one cache is always the default -- we -+ * fall back to the one created first. -+ * -+ * Each cache has a name and a UUID. Heimdal allows the name to be changed, -+ * we don't (yet, because the MIT client doesn't allow that either) -+ * -+ * Each ccache also stores a client principal. -+ */ -+struct kcm_ccache; -+ -+/* -+ * Create a new KCM ccache owned by mem_ctx on the -+ * memory level. -+ * -+ * When created, the ccache contains no credendials -+ */ -+errno_t kcm_cc_new(TALLOC_CTX *mem_ctx, -+ krb5_context k5c, -+ struct cli_creds *owner, -+ const char *name, -+ krb5_principal princ, -+ struct kcm_ccache **_cc); -+ -+/* -+ * Returns true if a client can access a ccache. -+ * -+ * Note that root can access any ccache */ -+bool kcm_cc_access(struct kcm_ccache *cc, -+ struct cli_creds *client); -+ -+/* -+ * Since the kcm_ccache structure is opaque, the kcmsrv_ccache -+ * layer contains a number of getsetters to read and write -+ * properties of the kcm_ccache structure -+ */ -+const char *kcm_cc_get_name(struct kcm_ccache *cc); -+errno_t kcm_cc_get_uuid(struct kcm_ccache *cc, uuid_t _uuid); -+krb5_principal kcm_cc_get_client_principal(struct kcm_ccache *cc); -+int32_t kcm_cc_get_offset(struct kcm_ccache *cc); -+ -+/* Mainly useful for creating a cred structure from a persistent -+ * storage -+ */ -+struct kcm_cred *kcm_cred_new(TALLOC_CTX *mem_ctx, -+ uuid_t uuid, -+ struct sss_iobuf *cred_blob); -+ -+/* Add a cred to ccache */ -+errno_t kcm_cc_store_creds(struct kcm_ccache *cc, -+ struct kcm_cred *crd); -+ -+errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t uuid); -+ -+/* -+ * At the moment, the credentials are stored without unmarshalling -+ * them, just as the clients sends the credentials. -+ */ -+struct sss_iobuf *kcm_cred_get_creds(struct kcm_cred *crd); -+errno_t kcm_cc_store_cred_blob(struct kcm_ccache *cc, -+ struct sss_iobuf *cred_blob); -+ /* -+ * The KCM server can call kcm_cred_get_creds to fetch the first -+ * credential, then iterate over the credentials with -+ * kcm_cc_next_cred until it returns NULL -+ */ -+struct kcm_cred *kcm_cc_get_cred(struct kcm_ccache *cc); -+struct kcm_cred *kcm_cc_next_cred(struct kcm_cred *crd); -+ -+enum kcm_ccdb_be { -+ CCDB_BE_MEMORY, -+ CCDB_BE_SECRETS, -+}; -+ -+/* An opaque database that contains all the ccaches */ -+struct kcm_ccdb; -+ -+/* -+ * Initialize a ccache database of type cc_be -+ */ -+struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ enum kcm_ccdb_be cc_be); -+ -+/* -+ * In KCM, each ccache name is usually in the form of "UID: -+ * -+ * The is generated by the KCM ccache database. Use this function -+ * to retrieve the next number -+ */ -+struct tevent_req *kcm_ccdb_nextid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client); -+errno_t kcm_ccdb_nextid_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ char **_nextid); -+ -+/* -+ * List all ccaches that belong to a given client -+ * -+ * The cc_list the recv function returns is NULL-terminated. -+ * -+ * NOTE: Contrary to how Heimdal behaves, root CAN NOT list all ccaches -+ * of all users. This is a deliberate decision to treat root as any other -+ * user, except it can access a ccache of another user by name, just not -+ * list them. -+ * -+ * If a client has no ccaches, the function returns OK, but an empty list -+ * containing just the NULL sentinel. -+ */ -+struct tevent_req *kcm_ccdb_list_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client); -+errno_t kcm_ccdb_list_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ uuid_t **_uuid_list); -+ -+/* -+ * Retrieve a ccache by name. -+ * -+ * If there is no such ccache, return EOK, but a NULL _cc pointer -+ */ -+struct tevent_req *kcm_ccdb_getbyname_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ const char *name); -+errno_t kcm_ccdb_getbyname_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc); -+ -+/* -+ * Retrieve a ccache by UUID -+ * -+ * If there is no such ccache, return EOK, but a NULL _cc pointer -+ */ -+struct tevent_req *kcm_ccdb_getbyuuid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid); -+errno_t kcm_ccdb_getbyuuid_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc); -+ -+/* -+ * Retrieve the default ccache. If there is no default cache, -+ * return EOK, but a NULL UUID. -+ */ -+struct tevent_req *kcm_ccdb_get_default_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client); -+errno_t kcm_ccdb_get_default_recv(struct tevent_req *req, -+ uuid_t *uuid); -+ -+/* -+ * Translating name to UUID is often considerably faster than doing a full -+ * CC retrieval, hence this function and the converse. If the UUID cannot -+ * be found in the database, return ERR_KCM_CC_END -+ */ -+struct tevent_req *kcm_ccdb_name_by_uuid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid); -+errno_t kcm_ccdb_name_by_uuid_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ const char **_name); -+ -+/* -+ * Translating UUID to name is often considerably faster than doing a full -+ * CC retrieval, hence this function and the converse. If the UUID cannot -+ * be found in the database, return ERR_KCM_CC_END -+ */ -+struct tevent_req *kcm_ccdb_uuid_by_name_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ const char *name); -+errno_t kcm_ccdb_uuid_by_name_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ uuid_t _uuid); -+ -+/* -+ * Set the default ccache. Passing a NULL UUID is a legal operation -+ * that 'unsets' the default ccache. -+ */ -+struct tevent_req *kcm_ccdb_set_default_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid); -+errno_t kcm_ccdb_set_default_recv(struct tevent_req *req); -+ -+/* -+ * Add a ccache to the database. -+ */ -+struct tevent_req *kcm_ccdb_create_cc_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ struct kcm_ccache *cc); -+errno_t kcm_ccdb_create_cc_recv(struct tevent_req *req); -+ -+/* -+ * Modify cache properties in a db -+ */ -+struct kcm_mod_ctx { -+ int32_t kdc_offset; -+ /* More settable properties (like name, when we support renames -+ * will be added later -+ */ -+}; -+ -+void kcm_mod_ctx_clear(struct kcm_mod_ctx *mod_ctx); -+void kcm_mod_cc(struct kcm_ccache *cc, struct kcm_mod_ctx *mod_ctx); -+ -+struct tevent_req *kcm_ccdb_mod_cc_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid, -+ struct kcm_mod_ctx *mod_cc); -+errno_t kcm_ccdb_mod_cc_recv(struct tevent_req *req); -+ -+/* -+ * Store a credential in a cache -+ */ -+struct tevent_req *kcm_ccdb_store_cred_blob_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid, -+ struct sss_iobuf *cred_blob); -+errno_t kcm_ccdb_store_cred_blob_recv(struct tevent_req *req); -+ -+/* -+ * Delete a ccache from the database -+ */ -+struct tevent_req *kcm_ccdb_delete_cc_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid); -+errno_t kcm_ccdb_delete_cc_recv(struct tevent_req *req); -+ -+void kcm_debug_uuid(uuid_t uuid); -+ -+/* -+ * The KCM clients are not allowed (except root) to create ccaches -+ * with arbitrary names. Instead, we assert that the ccache name -+ * begins with UID where UID is the stringified representation of -+ * the client's UID number -+ */ -+errno_t kcm_check_name(const char *name, struct cli_creds *client); -+ -+#endif /* _KCMSRV_CCACHE_H_ */ -diff --git a/src/responder/kcm/kcmsrv_ccache_be.h b/src/responder/kcm/kcmsrv_ccache_be.h -new file mode 100644 -index 0000000000000000000000000000000000000000..1bd2b6981e227675866e82e0a5389445cac4df66 ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_ccache_be.h -@@ -0,0 +1,204 @@ -+/* -+ SSSD -+ -+ KCM Server - the KCM ccache database interface -+ -+ This file should only be included from the ccache.c module. -+ -+ Copyright (C) Red Hat, 2016 -+ -+ 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 . -+*/ -+ -+#ifndef _KCMSRV_CCACHE_BE_ -+#define _KCMSRV_CCACHE_BE_ -+ -+#include "config.h" -+ -+#include -+#include "responder/kcm/kcmsrv_ccache.h" -+ -+typedef errno_t -+(*ccdb_init_fn)(struct kcm_ccdb *db); -+ -+typedef struct tevent_req * -+(*ccdb_nextid_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client); -+typedef errno_t -+(*ccdb_nextid_recv_fn)(struct tevent_req *req, -+ unsigned int *_nextid); -+ -+typedef struct tevent_req * -+(*ccdb_set_default_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid); -+typedef errno_t -+(*ccdb_set_default_recv_fn)(struct tevent_req *req); -+ -+typedef struct tevent_req * -+(*ccdb_get_default_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client); -+typedef errno_t -+(*ccdb_get_default_recv_fn)(struct tevent_req *req, -+ uuid_t dfl); -+ -+ -+typedef struct tevent_req * -+(*ccdb_list_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client); -+typedef errno_t -+(*ccdb_list_recv_fn)(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ uuid_t **_uuid_list); -+ -+typedef struct tevent_req * -+(*ccdb_getbyname_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ const char *name); -+typedef errno_t -+(*ccdb_getbyname_recv_fn)(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc); -+ -+typedef struct tevent_req * -+(*ccdb_getbyuuid_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid); -+typedef errno_t -+(*ccdb_getbyuuid_recv_fn)(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc); -+ -+typedef struct tevent_req * -+(*ccdb_name_by_uuid_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid); -+typedef errno_t -+(*ccdb_name_by_uuid_recv_fn)(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ const char **_name); -+ -+typedef struct tevent_req * -+(*ccdb_uuid_by_name_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ const char *name); -+typedef errno_t -+(*ccdb_uuid_by_name_recv_fn)(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ uuid_t _uuid); -+ -+typedef struct tevent_req * -+(*ccdb_create_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ struct kcm_ccache *cc); -+typedef errno_t -+(*ccdb_create_recv_fn)(struct tevent_req *req); -+ -+typedef struct tevent_req * -+(*ccdb_mod_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid, -+ struct kcm_mod_ctx *mod_cc); -+typedef errno_t -+(*ccdb_mod_recv_fn)(struct tevent_req *req); -+ -+typedef struct tevent_req * -+(*kcm_ccdb_store_cred_blob_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid, -+ struct sss_iobuf *cred_blob); -+typedef errno_t -+(*kcm_ccdb_store_cred_blob_recv_fn)(struct tevent_req *req); -+ -+typedef struct tevent_req * -+(*ccdb_delete_send_fn)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid); -+typedef errno_t -+(*ccdb_delete_recv_fn)(struct tevent_req *req); -+ -+/* -+ * Each ccache back end (for example memory or secrets) must implement -+ * all these functions. The functions are wrapped by the kcm_ccdb -+ * interface that performs additional sanity checks or contains shared -+ * logic such as access checks but in general doesn't assume anything -+ * about how the operations work. -+ */ -+struct kcm_ccdb_ops { -+ ccdb_init_fn init; -+ -+ ccdb_nextid_send_fn nextid_send; -+ ccdb_nextid_recv_fn nextid_recv; -+ -+ ccdb_set_default_send_fn set_default_send; -+ ccdb_set_default_recv_fn set_default_recv; -+ -+ ccdb_get_default_send_fn get_default_send; -+ ccdb_get_default_recv_fn get_default_recv; -+ -+ ccdb_list_send_fn list_send; -+ ccdb_list_recv_fn list_recv; -+ -+ ccdb_getbyname_send_fn getbyname_send; -+ ccdb_getbyname_recv_fn getbyname_recv; -+ -+ ccdb_getbyuuid_send_fn getbyuuid_send; -+ ccdb_getbyuuid_recv_fn getbyuuid_recv; -+ -+ ccdb_name_by_uuid_send_fn name_by_uuid_send; -+ ccdb_name_by_uuid_recv_fn name_by_uuid_recv; -+ -+ ccdb_uuid_by_name_send_fn uuid_by_name_send; -+ ccdb_uuid_by_name_recv_fn uuid_by_name_recv; -+ -+ ccdb_create_send_fn create_send; -+ ccdb_create_recv_fn create_recv; -+ -+ ccdb_mod_send_fn mod_send; -+ ccdb_mod_recv_fn mod_recv; -+ -+ kcm_ccdb_store_cred_blob_send_fn store_cred_send; -+ kcm_ccdb_store_cred_blob_recv_fn store_cred_recv; -+ -+ ccdb_delete_send_fn delete_send; -+ ccdb_delete_recv_fn delete_recv; -+}; -+ -+extern const struct kcm_ccdb_ops ccdb_mem_ops; -+ -+#endif /* _KCMSRV_CCACHE_BE_ */ -diff --git a/src/responder/kcm/kcmsrv_ccache_pvt.h b/src/responder/kcm/kcmsrv_ccache_pvt.h -new file mode 100644 -index 0000000000000000000000000000000000000000..0cc24c2b8cd4d44080d2aa4384f7b2a73520c5a0 ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_ccache_pvt.h -@@ -0,0 +1,62 @@ -+/* -+ SSSD -+ -+ KCM Server - the KCM ccache operations - private structures -+ -+ Should be accessed only from the ccache layer. -+ -+ Copyright (C) Red Hat, 2016 -+ -+ 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 . -+*/ -+#ifndef _KCMSRV_CCACHE_PVT_H -+#define _KCMSRV_CCACHE_PVT_H -+ -+#include "responder/kcm/kcmsrv_ccache.h" -+#include "responder/kcm/kcmsrv_ccache_be.h" -+ -+struct kcm_ccache_owner { -+ uid_t uid; -+ gid_t gid; -+}; -+ -+struct kcm_cred { -+ struct sss_iobuf *cred_blob; -+ /* Randomly generated 16 bytes */ -+ uuid_t uuid; -+ -+ struct kcm_cred *next; -+ struct kcm_cred *prev; -+}; -+ -+struct kcm_ccdb { -+ enum kcm_ccdb_be cc_be_type; -+ struct tevent_context *ev; -+ -+ void *db_handle; -+ const struct kcm_ccdb_ops *ops; -+}; -+ -+struct kcm_ccache { -+ const char *name; -+ struct kcm_ccache_owner owner; -+ uuid_t uuid; -+ -+ krb5_principal client; -+ int32_t kdc_offset; -+ -+ struct kcm_cred *creds; -+}; -+ -+#endif /* _KCMSRV_CCACHE_PVT_H */ -diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h -index fd1fd9fa32d59a323d465def68999f24f84e3923..a29680246c1e616da75e1bbff951ce2fad66fb65 100644 ---- a/src/responder/kcm/kcmsrv_pvt.h -+++ b/src/responder/kcm/kcmsrv_pvt.h -@@ -46,6 +46,7 @@ struct kcm_data { - */ - struct kcm_resp_ctx { - krb5_context k5c; -+ struct kcm_ccdb *db; - }; - - /* --- -2.9.3 - diff --git a/SOURCES/0024-NSS-add-_EX-version-of-some-requests.patch b/SOURCES/0024-NSS-add-_EX-version-of-some-requests.patch new file mode 100644 index 0000000..e97d92d --- /dev/null +++ b/SOURCES/0024-NSS-add-_EX-version-of-some-requests.patch @@ -0,0 +1,606 @@ +From 8c6cb61cc65af7d3f243476dca66fb8f4750df80 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 11 Oct 2017 14:54:54 +0200 +Subject: [PATCH 24/31] NSS: add *_EX version of some requests + +To be able to send the flags to the SSSD responder new request types +with an _EX postfix are added which expect and additional 32bit flag +field after the name or the id of the requested object. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit cf93f7c2f2031078bbbff095dae01eb4f8deff85) +--- + src/responder/nss/nss_cmd.c | 76 +++++++++++++++++++++----- + src/responder/nss/nss_protocol.c | 81 ++++++++++++++++++++++++++++ + src/responder/nss/nss_protocol.h | 8 +++ + src/sss_client/idmap/sss_nss_ex.c | 110 +++++++++++++++++++++++++++----------- + src/sss_client/sss_cli.h | 7 +++ + 5 files changed, 237 insertions(+), 45 deletions(-) + +diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c +index ebf66dfe0444b83aed20d58d36ddf70d2f4fa1f9..974eaccc93cea3a330007735676da69eb9b84141 100644 +--- a/src/responder/nss/nss_cmd.c ++++ b/src/responder/nss/nss_cmd.c +@@ -54,6 +54,7 @@ static void nss_getby_done(struct tevent_req *subreq); + static void nss_getlistby_done(struct tevent_req *subreq); + + static errno_t nss_getby_name(struct cli_ctx *cli_ctx, ++ bool ex_version, + enum cache_req_type type, + const char **attrs, + enum sss_mc_type memcache, +@@ -64,6 +65,7 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + struct tevent_req *subreq; + const char *rawname; + errno_t ret; ++ uint32_t flags = 0; + + cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn); + if (cmd_ctx == NULL) { +@@ -71,7 +73,11 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + goto done; + } + +- ret = nss_protocol_parse_name(cli_ctx, &rawname); ++ if (ex_version) { ++ ret = nss_protocol_parse_name_ex(cli_ctx, &rawname, &flags); ++ } else { ++ ret = nss_protocol_parse_name(cli_ctx, &rawname); ++ } + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request message!\n"); + goto done; +@@ -108,6 +114,7 @@ done: + } + + static errno_t nss_getby_id(struct cli_ctx *cli_ctx, ++ bool ex_version, + enum cache_req_type type, + const char **attrs, + enum sss_mc_type memcache, +@@ -118,6 +125,7 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + struct tevent_req *subreq; + uint32_t id; + errno_t ret; ++ uint32_t flags = 0; + + cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn); + if (cmd_ctx == NULL) { +@@ -125,7 +133,11 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + goto done; + } + +- ret = nss_protocol_parse_id(cli_ctx, &id); ++ if (ex_version) { ++ ret = nss_protocol_parse_id_ex(cli_ctx, &id, &flags); ++ } else { ++ ret = nss_protocol_parse_id(cli_ctx, &id); ++ } + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request message!\n"); + goto done; +@@ -766,14 +778,26 @@ static errno_t nss_endent(struct cli_ctx *cli_ctx, + + static errno_t nss_cmd_getpwnam(struct cli_ctx *cli_ctx) + { +- return nss_getby_name(cli_ctx, CACHE_REQ_USER_BY_NAME, NULL, SSS_MC_PASSWD, +- nss_protocol_fill_pwent); ++ return nss_getby_name(cli_ctx, false, CACHE_REQ_USER_BY_NAME, NULL, ++ SSS_MC_PASSWD, nss_protocol_fill_pwent); + } + + static errno_t nss_cmd_getpwuid(struct cli_ctx *cli_ctx) + { +- return nss_getby_id(cli_ctx, CACHE_REQ_USER_BY_ID, NULL, SSS_MC_PASSWD, +- nss_protocol_fill_pwent); ++ return nss_getby_id(cli_ctx, false, CACHE_REQ_USER_BY_ID, NULL, ++ SSS_MC_PASSWD, nss_protocol_fill_pwent); ++} ++ ++static errno_t nss_cmd_getpwnam_ex(struct cli_ctx *cli_ctx) ++{ ++ return nss_getby_name(cli_ctx, true, CACHE_REQ_USER_BY_NAME, NULL, ++ SSS_MC_PASSWD, nss_protocol_fill_pwent); ++} ++ ++static errno_t nss_cmd_getpwuid_ex(struct cli_ctx *cli_ctx) ++{ ++ return nss_getby_id(cli_ctx, true, CACHE_REQ_USER_BY_ID, NULL, ++ SSS_MC_PASSWD, nss_protocol_fill_pwent); + } + + static errno_t nss_cmd_setpwent(struct cli_ctx *cli_ctx) +@@ -809,16 +833,29 @@ static errno_t nss_cmd_endpwent(struct cli_ctx *cli_ctx) + + static errno_t nss_cmd_getgrnam(struct cli_ctx *cli_ctx) + { +- return nss_getby_name(cli_ctx, CACHE_REQ_GROUP_BY_NAME, NULL, SSS_MC_GROUP, +- nss_protocol_fill_grent); ++ return nss_getby_name(cli_ctx, false, CACHE_REQ_GROUP_BY_NAME, NULL, ++ SSS_MC_GROUP, nss_protocol_fill_grent); + } + + static errno_t nss_cmd_getgrgid(struct cli_ctx *cli_ctx) + { +- return nss_getby_id(cli_ctx, CACHE_REQ_GROUP_BY_ID, NULL, SSS_MC_GROUP, +- nss_protocol_fill_grent); ++ return nss_getby_id(cli_ctx, false, CACHE_REQ_GROUP_BY_ID, NULL, ++ SSS_MC_GROUP, nss_protocol_fill_grent); + } + ++static errno_t nss_cmd_getgrnam_ex(struct cli_ctx *cli_ctx) ++{ ++ return nss_getby_name(cli_ctx, true, CACHE_REQ_GROUP_BY_NAME, NULL, ++ SSS_MC_GROUP, nss_protocol_fill_grent); ++} ++ ++static errno_t nss_cmd_getgrgid_ex(struct cli_ctx *cli_ctx) ++{ ++ return nss_getby_id(cli_ctx, true, CACHE_REQ_GROUP_BY_ID, NULL, ++ SSS_MC_GROUP, nss_protocol_fill_grent); ++} ++ ++ + static errno_t nss_cmd_setgrent(struct cli_ctx *cli_ctx) + { + struct nss_ctx *nss_ctx; +@@ -852,7 +889,13 @@ static errno_t nss_cmd_endgrent(struct cli_ctx *cli_ctx) + + static errno_t nss_cmd_initgroups(struct cli_ctx *cli_ctx) + { +- return nss_getby_name(cli_ctx, CACHE_REQ_INITGROUPS, NULL, ++ return nss_getby_name(cli_ctx, false, CACHE_REQ_INITGROUPS, NULL, ++ SSS_MC_INITGROUPS, nss_protocol_fill_initgr); ++} ++ ++static errno_t nss_cmd_initgroups_ex(struct cli_ctx *cli_ctx) ++{ ++ return nss_getby_name(cli_ctx, true, CACHE_REQ_INITGROUPS, NULL, + SSS_MC_INITGROUPS, nss_protocol_fill_initgr); + } + +@@ -943,7 +986,7 @@ static errno_t nss_cmd_getsidbyname(struct cli_ctx *cli_ctx) + { + const char *attrs[] = { SYSDB_SID_STR, NULL }; + +- return nss_getby_name(cli_ctx, CACHE_REQ_OBJECT_BY_NAME, attrs, ++ return nss_getby_name(cli_ctx, false, CACHE_REQ_OBJECT_BY_NAME, attrs, + SSS_MC_NONE, nss_protocol_fill_sid); + } + +@@ -951,7 +994,7 @@ static errno_t nss_cmd_getsidbyid(struct cli_ctx *cli_ctx) + { + const char *attrs[] = { SYSDB_SID_STR, NULL }; + +- return nss_getby_id(cli_ctx, CACHE_REQ_OBJECT_BY_ID, attrs, ++ return nss_getby_id(cli_ctx, false, CACHE_REQ_OBJECT_BY_ID, attrs, + SSS_MC_NONE, nss_protocol_fill_sid); + } + +@@ -1006,7 +1049,7 @@ static errno_t nss_cmd_getorigbyname(struct cli_ctx *cli_ctx) + attrs = defattrs; + } + +- return nss_getby_name(cli_ctx, CACHE_REQ_OBJECT_BY_NAME, attrs, ++ return nss_getby_name(cli_ctx, false, CACHE_REQ_OBJECT_BY_NAME, attrs, + SSS_MC_NONE, nss_protocol_fill_orig); + } + +@@ -1051,6 +1094,11 @@ struct sss_cmd_table *get_nss_cmds(void) + { SSS_NSS_GETORIGBYNAME, nss_cmd_getorigbyname }, + { SSS_NSS_GETNAMEBYCERT, nss_cmd_getnamebycert }, + { SSS_NSS_GETLISTBYCERT, nss_cmd_getlistbycert }, ++ { SSS_NSS_GETPWNAM_EX, nss_cmd_getpwnam_ex }, ++ { SSS_NSS_GETPWUID_EX, nss_cmd_getpwuid_ex }, ++ { SSS_NSS_GETGRNAM_EX, nss_cmd_getgrnam_ex }, ++ { SSS_NSS_GETGRGID_EX, nss_cmd_getgrgid_ex }, ++ { SSS_NSS_INITGR_EX, nss_cmd_initgroups_ex }, + { SSS_CLI_NULL, NULL } + }; + +diff --git a/src/responder/nss/nss_protocol.c b/src/responder/nss/nss_protocol.c +index 06fc4d00a7877a7990402f4f2633ddc0bd640b41..17bfc4f4e71960a72e9e04622eac95b94a865ec7 100644 +--- a/src/responder/nss/nss_protocol.c ++++ b/src/responder/nss/nss_protocol.c +@@ -134,6 +134,61 @@ nss_protocol_parse_name(struct cli_ctx *cli_ctx, const char **_rawname) + } + + errno_t ++nss_protocol_parse_name_ex(struct cli_ctx *cli_ctx, const char **_rawname, ++ uint32_t *_flags) ++{ ++ struct cli_protocol *pctx; ++ const char *rawname; ++ uint8_t *body; ++ size_t blen; ++ uint8_t *p; ++ uint32_t flags; ++ ++ pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol); ++ ++ sss_packet_get_body(pctx->creq->in, &body, &blen); ++ ++ if (blen < 1 + sizeof(uint32_t)) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Body too short!\n"); ++ return EINVAL; ++ } ++ ++ /* If first argument not terminated fail. */ ++ if (body[blen - 1 - sizeof(uint32_t)] != '\0') { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Body is not null terminated!\n"); ++ return EINVAL; ++ } ++ ++ p = memchr(body, '\0', blen); ++ ++ /* If the body isn't valid UTF-8, fail */ ++ if (!sss_utf8_check(body, (p - body))) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "First argument is not UTF-8 string!\n"); ++ return EINVAL; ++ } ++ ++ rawname = (const char *)body; ++ if (rawname[0] == '\0') { ++ DEBUG(SSSDBG_CRIT_FAILURE, "An empty name was provided!\n"); ++ return EINVAL; ++ } ++ ++ p++; ++ if ((p - body) + sizeof(uint32_t) != blen) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Body has unexpected size!\n"); ++ return EINVAL; ++ } ++ ++ SAFEALIGN_COPY_UINT32(&flags, p, NULL); ++ p += sizeof(uint32_t); ++ ++ *_rawname = rawname; ++ *_flags = flags; ++ ++ return EOK; ++} ++ ++errno_t + nss_protocol_parse_id(struct cli_ctx *cli_ctx, uint32_t *_id) + { + struct cli_protocol *pctx; +@@ -157,6 +212,32 @@ nss_protocol_parse_id(struct cli_ctx *cli_ctx, uint32_t *_id) + } + + errno_t ++nss_protocol_parse_id_ex(struct cli_ctx *cli_ctx, uint32_t *_id, ++ uint32_t *_flags) ++{ ++ struct cli_protocol *pctx; ++ uint8_t *body; ++ size_t blen; ++ uint32_t id; ++ uint32_t flags; ++ ++ pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol); ++ ++ sss_packet_get_body(pctx->creq->in, &body, &blen); ++ ++ if (blen != 2 * sizeof(uint32_t)) { ++ return EINVAL; ++ } ++ ++ SAFEALIGN_COPY_UINT32(&id, body, NULL); ++ SAFEALIGN_COPY_UINT32(&flags, body + sizeof(uint32_t), NULL); ++ ++ *_id = id; ++ ++ return EOK; ++} ++ ++errno_t + nss_protocol_parse_limit(struct cli_ctx *cli_ctx, uint32_t *_limit) + { + return nss_protocol_parse_id(cli_ctx, _limit); +diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h +index 417b0891615dcb8771d49f7b2f4d276342ca3150..ca5b040237dc18acdca9a7a3a7a7dbb64265aa95 100644 +--- a/src/responder/nss/nss_protocol.h ++++ b/src/responder/nss/nss_protocol.h +@@ -89,9 +89,17 @@ errno_t + nss_protocol_parse_name(struct cli_ctx *cli_ctx, const char **_rawname); + + errno_t ++nss_protocol_parse_name_ex(struct cli_ctx *cli_ctx, const char **_rawname, ++ uint32_t *_flags); ++ ++errno_t + nss_protocol_parse_id(struct cli_ctx *cli_ctx, uint32_t *_id); + + errno_t ++nss_protocol_parse_id_ex(struct cli_ctx *cli_ctx, uint32_t *_id, ++ uint32_t *_flags); ++ ++errno_t + nss_protocol_parse_limit(struct cli_ctx *cli_ctx, uint32_t *_limit); + + errno_t +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +index 582d1373ec35305cf128e04fd3d705457d304789..dc7610a4e528b5126f0d25d84cd3c1a22f683b75 100644 +--- a/src/sss_client/idmap/sss_nss_ex.c ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -61,31 +61,37 @@ errno_t sss_nss_mc_get(struct nss_input *inp) + { + switch(inp->cmd) { + case SSS_NSS_GETPWNAM: +- return sss_nss_mc_getpwnam(inp->input.name, (inp->rd.len - 1), ++ case SSS_NSS_GETPWNAM_EX: ++ return sss_nss_mc_getpwnam(inp->input.name, strlen(inp->input.name), + inp->result.pwrep.result, + inp->result.pwrep.buffer, + inp->result.pwrep.buflen); + break; + case SSS_NSS_GETPWUID: ++ case SSS_NSS_GETPWUID_EX: + return sss_nss_mc_getpwuid(inp->input.uid, + inp->result.pwrep.result, + inp->result.pwrep.buffer, + inp->result.pwrep.buflen); + break; + case SSS_NSS_GETGRNAM: +- return sss_nss_mc_getgrnam(inp->input.name, (inp->rd.len - 1), ++ case SSS_NSS_GETGRNAM_EX: ++ return sss_nss_mc_getgrnam(inp->input.name, strlen(inp->input.name), + inp->result.grrep.result, + inp->result.grrep.buffer, + inp->result.grrep.buflen); + break; + case SSS_NSS_GETGRGID: ++ case SSS_NSS_GETGRGID_EX: + return sss_nss_mc_getgrgid(inp->input.gid, + inp->result.grrep.result, + inp->result.grrep.buffer, + inp->result.grrep.buflen); + break; + case SSS_NSS_INITGR: +- return sss_nss_mc_initgroups_dyn(inp->input.name, (inp->rd.len - 1), ++ case SSS_NSS_INITGR_EX: ++ return sss_nss_mc_initgroups_dyn(inp->input.name, ++ strlen(inp->input.name), + -1 /* currently ignored */, + inp->result.initgrrep.start, + inp->result.initgrrep.ngroups, +@@ -163,7 +169,7 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + goto out; + } + +- if (inp->cmd == SSS_NSS_INITGR) { ++ if (inp->cmd == SSS_NSS_INITGR || inp->cmd == SSS_NSS_INITGR_EX) { + if ((*(inp->result.initgrrep.ngroups) - *(inp->result.initgrrep.start)) + < num_results) { + new_groups = realloc(inp->result.initgrrep.groups, +@@ -198,15 +204,24 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + } + + len = replen - 8; +- if (inp->cmd == SSS_NSS_GETPWNAM || inp->cmd == SSS_NSS_GETPWUID) { ++ ++ switch(inp->cmd) { ++ case SSS_NSS_GETPWNAM: ++ case SSS_NSS_GETPWUID: ++ case SSS_NSS_GETPWNAM_EX: ++ case SSS_NSS_GETPWUID_EX: + ret = sss_nss_getpw_readrep(&(inp->result.pwrep), repbuf+8, &len); +- } else if (inp->cmd == SSS_NSS_GETGRNAM || inp->cmd == SSS_NSS_GETGRGID) { ++ break; ++ case SSS_NSS_GETGRNAM: ++ case SSS_NSS_GETGRGID: ++ case SSS_NSS_GETGRNAM_EX: ++ case SSS_NSS_GETGRGID_EX: + ret = sss_nss_getgr_readrep(&(inp->result.grrep), repbuf+8, &len); +- } else { ++ break; ++ default: + ret = EINVAL; +- goto out; + } +- if (ret) { ++ if (ret != 0) { + goto out; + } + +@@ -223,6 +238,39 @@ out: + return ret; + } + ++static int make_name_flag_req_data(const char *name, uint32_t flags, ++ struct sss_cli_req_data *rd) ++{ ++ size_t len; ++ size_t name_len; ++ uint8_t *data; ++ int ret; ++ ++ if (name == NULL) { ++ return EINVAL; ++ } ++ ++ ret = sss_strnlen(name, SSS_NAME_MAX, &name_len); ++ if (ret != 0) { ++ return ret; ++ } ++ name_len++; ++ ++ len = name_len + sizeof(uint32_t); ++ data = malloc(len); ++ if (data == NULL) { ++ return ENOMEM; ++ } ++ ++ memcpy(data, name, name_len); ++ SAFEALIGN_COPY_UINT32(data + name_len, &flags, NULL); ++ ++ rd->len = len; ++ rd->data = data; ++ ++ return 0; ++} ++ + int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, + char *buffer, size_t buflen, + struct passwd **result, +@@ -231,8 +279,7 @@ int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, + int ret; + struct nss_input inp = { + .input.name = name, +- .cmd = SSS_NSS_GETPWNAM, +- .rd.data = name, ++ .cmd = SSS_NSS_GETPWNAM_EX, + .result.pwrep.result = pwd, + .result.pwrep.buffer = buffer, + .result.pwrep.buflen = buflen}; +@@ -241,15 +288,15 @@ int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, + return ERANGE; + } + +- ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { +- return EINVAL; ++ return ret; + } +- inp.rd.len++; + + *result = NULL; + + ret = sss_get_ex(&inp, flags, timeout); ++ free(discard_const(inp.rd.data)); + if (ret == 0) { + *result = inp.result.pwrep.result; + } +@@ -262,12 +309,12 @@ int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd, + uint32_t flags, unsigned int timeout) + { + int ret; +- uint32_t user_uid = uid; ++ uint32_t req_data[2]; + struct nss_input inp = { + .input.uid = uid, +- .cmd = SSS_NSS_GETPWUID, +- .rd.len = sizeof(uint32_t), +- .rd.data = &user_uid, ++ .cmd = SSS_NSS_GETPWUID_EX, ++ .rd.len = 2 * sizeof(uint32_t), ++ .rd.data = &req_data, + .result.pwrep.result = pwd, + .result.pwrep.buffer = buffer, + .result.pwrep.buflen = buflen}; +@@ -276,6 +323,8 @@ int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd, + return ERANGE; + } + ++ SAFEALIGN_COPY_UINT32(&req_data[0], &uid, NULL); ++ SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL); + *result = NULL; + + ret = sss_get_ex(&inp, flags, timeout); +@@ -292,8 +341,7 @@ int sss_nss_getgrnam_timeout(const char *name, struct group *grp, + int ret; + struct nss_input inp = { + .input.name = name, +- .cmd = SSS_NSS_GETGRNAM, +- .rd.data = name, ++ .cmd = SSS_NSS_GETGRNAM_EX, + .result.grrep.result = grp, + .result.grrep.buffer = buffer, + .result.grrep.buflen = buflen}; +@@ -302,15 +350,15 @@ int sss_nss_getgrnam_timeout(const char *name, struct group *grp, + return ERANGE; + } + +- ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { +- return EINVAL; ++ return ret; + } +- inp.rd.len++; + + *result = NULL; + + ret = sss_get_ex(&inp, flags, timeout); ++ free(discard_const(inp.rd.data)); + if (ret == 0) { + *result = inp.result.grrep.result; + } +@@ -322,12 +370,12 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, + uint32_t flags, unsigned int timeout) + { + int ret; +- uint32_t group_gid = gid; ++ uint32_t req_data[2]; + struct nss_input inp = { + .input.gid = gid, +- .cmd = SSS_NSS_GETGRGID, +- .rd.len = sizeof(uint32_t), +- .rd.data = &group_gid, ++ .cmd = SSS_NSS_GETGRGID_EX, ++ .rd.len = 2 * sizeof(uint32_t), ++ .rd.data = &req_data, + .result.grrep.result = grp, + .result.grrep.buffer = buffer, + .result.grrep.buflen = buflen}; +@@ -336,6 +384,8 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, + return ERANGE; + } + ++ SAFEALIGN_COPY_UINT32(&req_data[0], &gid, NULL); ++ SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL); + *result = NULL; + + ret = sss_get_ex(&inp, flags, timeout); +@@ -355,18 +405,16 @@ int sss_nss_getgrouplist_timeout(const char *name, gid_t group, + long int start = 1; + struct nss_input inp = { + .input.name = name, +- .cmd = SSS_NSS_INITGR, +- .rd.data = name}; ++ .cmd = SSS_NSS_INITGR_EX}; + + if (groups == NULL || ngroups == NULL || *ngroups == 0) { + return EINVAL; + } + +- ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { + return ret; + } +- inp.rd.len++; + + new_ngroups = MAX(1, *ngroups); + new_groups = malloc(new_ngroups * sizeof(gid_t)); +diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h +index 5329651a9385d138b8ea7237cb5cf4e2b8e5f371..9d2cc00c9957f5680548461129e3e6b777da5091 100644 +--- a/src/sss_client/sss_cli.h ++++ b/src/sss_client/sss_cli.h +@@ -79,6 +79,9 @@ enum sss_cli_command { + SSS_NSS_GETPWENT = 0x0014, + SSS_NSS_ENDPWENT = 0x0015, + ++ SSS_NSS_GETPWNAM_EX = 0x0019, ++ SSS_NSS_GETPWUID_EX = 0x001A, ++ + /* group */ + + SSS_NSS_GETGRNAM = 0x0021, +@@ -88,6 +91,10 @@ enum sss_cli_command { + SSS_NSS_ENDGRENT = 0x0025, + SSS_NSS_INITGR = 0x0026, + ++ SSS_NSS_GETGRNAM_EX = 0x0029, ++ SSS_NSS_GETGRGID_EX = 0x002A, ++ SSS_NSS_INITGR_EX = 0x002E, ++ + #if 0 + /* aliases */ + +-- +2.13.6 + diff --git a/SOURCES/0025-KCM-Add-a-in-memory-credential-storage.patch b/SOURCES/0025-KCM-Add-a-in-memory-credential-storage.patch deleted file mode 100644 index 6bfffe6..0000000 --- a/SOURCES/0025-KCM-Add-a-in-memory-credential-storage.patch +++ /dev/null @@ -1,907 +0,0 @@ -From e7aa9061532b1ac139e155e7e9881c2447675e3c Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 7 Mar 2017 13:49:43 +0100 -Subject: [PATCH 25/36] KCM: Add a in-memory credential storage -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Implements a simple back end for the ccache module that lets the KCM -server store credentials directly in memory. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - Makefile.am | 1 + - src/responder/kcm/kcm.c | 13 +- - src/responder/kcm/kcmsrv_ccache.c | 2 +- - src/responder/kcm/kcmsrv_ccache_mem.c | 805 ++++++++++++++++++++++++++++++++++ - 4 files changed, 817 insertions(+), 4 deletions(-) - create mode 100644 src/responder/kcm/kcmsrv_ccache_mem.c - -diff --git a/Makefile.am b/Makefile.am -index a2b9dc49e95fa2d025f5174d2902866fab180a78..5605c1a53c44fd9e83394e80b7f71828df1d39b6 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -1492,6 +1492,7 @@ sssd_kcm_SOURCES = \ - src/responder/kcm/kcm.c \ - src/responder/kcm/kcmsrv_cmd.c \ - src/responder/kcm/kcmsrv_ccache.c \ -+ src/responder/kcm/kcmsrv_ccache_mem.c \ - src/util/sss_sockets.c \ - src/util/sss_krb5.c \ - src/util/sss_iobuf.c \ -diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c -index 90a6999c5e39d48a1a2ea8168d171612a65077d5..2c12ef215ce3967df183e51c20590c5f439d278f 100644 ---- a/src/responder/kcm/kcm.c -+++ b/src/responder/kcm/kcm.c -@@ -22,9 +22,9 @@ - #include "config.h" - - #include --#include - - #include "responder/kcm/kcm.h" -+#include "responder/kcm/kcmsrv_ccache.h" - #include "responder/kcm/kcmsrv_pvt.h" - #include "responder/common/responder.h" - #include "util/util.h" -@@ -110,7 +110,8 @@ static int kcm_data_destructor(void *ptr) - return 0; - } - --static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx) -+static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev) - { - struct kcm_resp_ctx *kcm_data; - krb5_error_code kret; -@@ -121,6 +122,12 @@ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx) - return NULL; - } - -+ kcm_data->db = kcm_ccdb_init(kcm_data, ev, CCDB_BE_MEMORY); -+ if (kcm_data->db == NULL) { -+ talloc_free(kcm_data); -+ return NULL; -+ } -+ - kret = krb5_init_context(&kcm_data->k5c); - if (kret != EOK) { - talloc_free(kcm_data); -@@ -169,7 +176,7 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx, - goto fail; - } - -- kctx->kcm_data = kcm_data_setup(kctx); -+ kctx->kcm_data = kcm_data_setup(kctx, ev); - if (kctx->kcm_data == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, - "fatal error initializing responder data\n"); -diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c -index 2c565b8378e3ec297faf655d3c48d7ab902713d3..2ae120269b0c62275ba2acdff6d6daa8b7077708 100644 ---- a/src/responder/kcm/kcmsrv_ccache.c -+++ b/src/responder/kcm/kcmsrv_ccache.c -@@ -240,7 +240,7 @@ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, - switch (cc_be) { - case CCDB_BE_MEMORY: - DEBUG(SSSDBG_FUNC_DATA, "KCM back end: memory\n"); -- /* Not implemented yet */ -+ ccdb->ops = &ccdb_mem_ops; - break; - case CCDB_BE_SECRETS: - DEBUG(SSSDBG_FUNC_DATA, "KCM back end: sssd-secrets\n"); -diff --git a/src/responder/kcm/kcmsrv_ccache_mem.c b/src/responder/kcm/kcmsrv_ccache_mem.c -new file mode 100644 -index 0000000000000000000000000000000000000000..1c4f3df8d3b35b0428a143d4b545562d9cc0e574 ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_ccache_mem.c -@@ -0,0 +1,805 @@ -+/* -+ SSSD -+ -+ KCM Server - ccache in-memory storage -+ -+ Copyright (C) Red Hat, 2016 -+ -+ 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 "config.h" -+ -+#include -+#include -+ -+#include "util/util.h" -+#include "responder/kcm/kcmsrv_ccache_pvt.h" -+#include "responder/kcm/kcmsrv_ccache_be.h" -+ -+struct ccdb_mem; -+ -+/* -+ * The KCM memory database is just a double-linked list of kcm_ccache structures -+ */ -+struct ccache_mem_wrap { -+ struct kcm_ccache *cc; -+ bool is_default; -+ -+ struct ccache_mem_wrap *next; -+ struct ccache_mem_wrap *prev; -+ -+ struct ccdb_mem *mem_be; -+}; -+ -+struct ccdb_mem { -+ /* Both ccaches and the next-id are kept in memory */ -+ struct ccache_mem_wrap *head; -+ unsigned int nextid; -+}; -+ -+/* In order to provide a consistent interface, we need to let the caller -+ * of getbyXXX own the ccache, therefore the memory back end returns a shallow -+ * copy of the ccache -+ */ -+static struct kcm_ccache *kcm_ccache_dup(TALLOC_CTX *mem_ctx, -+ struct kcm_ccache *in) -+{ -+ struct kcm_ccache *out; -+ -+ out = talloc_zero(mem_ctx, struct kcm_ccache); -+ if (out == NULL) { -+ return NULL; -+ } -+ memcpy(out, in, sizeof(struct kcm_ccache)); -+ -+ return out; -+} -+ -+static struct ccache_mem_wrap *memdb_get_by_uuid(struct ccdb_mem *memdb, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ uid_t uid; -+ struct ccache_mem_wrap *ccwrap = NULL; -+ struct ccache_mem_wrap *out = NULL; -+ -+ uid = cli_creds_get_uid(client); -+ -+ DLIST_FOR_EACH(ccwrap, memdb->head) { -+ if (ccwrap->cc == NULL) { -+ /* since KCM stores ccaches, better not crash.. */ -+ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n"); -+ continue; -+ } -+ -+ if (ccwrap->cc->owner.uid == uid) { -+ if (uuid_compare(uuid, ccwrap->cc->uuid) == 0) { -+ out = ccwrap; -+ break; -+ } -+ } -+ } -+ -+ return out; -+} -+ -+static struct ccache_mem_wrap *memdb_get_by_name(struct ccdb_mem *memdb, -+ struct cli_creds *client, -+ const char *name) -+{ -+ uid_t uid; -+ struct ccache_mem_wrap *ccwrap = NULL; -+ struct ccache_mem_wrap *out = NULL; -+ -+ uid = cli_creds_get_uid(client); -+ -+ DLIST_FOR_EACH(ccwrap, memdb->head) { -+ if (ccwrap->cc == NULL) { -+ /* since KCM stores ccaches, better not crash.. */ -+ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n"); -+ continue; -+ } -+ -+ if (ccwrap->cc->owner.uid == uid) { -+ if (strcmp(ccwrap->cc->name, name) == 0) { -+ out = ccwrap; -+ break; -+ } -+ } -+ } -+ -+ return out; -+} -+ -+/* Since with the in-memory database, the database operations are just -+ * fake-async wrappers around otherwise sync operations, we don't often -+ * need any state, so we use this empty structure instead -+ */ -+struct ccdb_mem_dummy_state { -+}; -+ -+static int ccwrap_destructor(void *ptr) -+{ -+ struct ccache_mem_wrap *ccwrap = talloc_get_type(ptr, struct ccache_mem_wrap); -+ -+ if (ccwrap == NULL) { -+ return 0; -+ } -+ -+ if (ccwrap->cc != NULL) { -+ if (ccwrap->cc->creds) { -+ safezero(sss_iobuf_get_data(ccwrap->cc->creds->cred_blob), -+ sss_iobuf_get_size(ccwrap->cc->creds->cred_blob)); -+ } -+ } -+ -+ -+ DLIST_REMOVE(ccwrap->mem_be->head, ccwrap); -+ -+ return 0; -+} -+ -+static errno_t ccdb_mem_init(struct kcm_ccdb *db) -+{ -+ struct ccdb_mem *memdb = NULL; -+ -+ memdb = talloc_zero(db, struct ccdb_mem); -+ if (memdb == NULL) { -+ return ENOMEM; -+ } -+ db->db_handle = memdb; -+ -+ return EOK; -+} -+ -+struct ccdb_mem_nextid_state { -+ unsigned int nextid; -+}; -+ -+static struct tevent_req *ccdb_mem_nextid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client) -+{ -+ struct tevent_req *req = NULL; -+ struct ccdb_mem_nextid_state *state = NULL; -+ struct ccdb_mem *memdb = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_nextid_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ if (memdb == NULL) { -+ ret = EIO; -+ goto immediate; -+ } -+ -+ state->nextid = memdb->nextid++; -+ -+ ret = EOK; -+immediate: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static errno_t ccdb_mem_nextid_recv(struct tevent_req *req, -+ unsigned int *_nextid) -+{ -+ struct ccdb_mem_nextid_state *state = tevent_req_data(req, -+ struct ccdb_mem_nextid_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_nextid = state->nextid; -+ return EOK; -+} -+ -+struct ccdb_mem_list_state { -+ uuid_t *uuid_list; -+}; -+ -+static struct tevent_req *ccdb_mem_list_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client) -+{ -+ struct tevent_req *req = NULL; -+ struct ccache_mem_wrap *ccwrap = NULL; -+ struct ccdb_mem_list_state *state = NULL; -+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ size_t num_ccaches = 0; -+ size_t cc_index = 0; -+ errno_t ret; -+ uid_t uid; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_list_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ uid = cli_creds_get_uid(client); -+ -+ DLIST_FOR_EACH(ccwrap, memdb->head) { -+ if (ccwrap->cc->owner.uid == uid) { -+ num_ccaches++; -+ } -+ } -+ -+ state->uuid_list = talloc_zero_array(state, uuid_t, num_ccaches+1); -+ if (state->uuid_list == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ cc_index = 0; -+ DLIST_FOR_EACH(ccwrap, memdb->head) { -+ if (ccwrap->cc->owner.uid == uid) { -+ uuid_copy(state->uuid_list[cc_index], ccwrap->cc->uuid); -+ cc_index++; -+ } -+ } -+ uuid_clear(state->uuid_list[num_ccaches]); -+ -+ ret = EOK; -+immediate: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static errno_t ccdb_mem_list_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ uuid_t **_uuid_list) -+{ -+ struct ccdb_mem_list_state *state = tevent_req_data(req, -+ struct ccdb_mem_list_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_uuid_list = talloc_steal(mem_ctx, state->uuid_list); -+ return EOK; -+} -+ -+static struct tevent_req *ccdb_mem_set_default_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ struct tevent_req *req = NULL; -+ struct ccdb_mem_dummy_state *state = NULL; -+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ struct ccache_mem_wrap *ccwrap = NULL; -+ uid_t uid = cli_creds_get_uid(client); -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ /* Reset all ccache defaults first */ -+ DLIST_FOR_EACH(ccwrap, memdb->head) { -+ if (ccwrap->cc == NULL) { -+ /* since KCM stores ccaches, better not crash.. */ -+ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n"); -+ continue; -+ } -+ -+ if (ccwrap->cc->owner.uid == uid) { -+ ccwrap->is_default = false; -+ } -+ } -+ -+ /* Then set the default for the right ccache. This also allows to -+ * pass a null uuid to just reset the old ccache (for example after -+ * deleting the default -+ */ -+ ccwrap = memdb_get_by_uuid(memdb, client, uuid); -+ if (ccwrap != NULL) { -+ ccwrap->is_default = true; -+ } -+ -+ tevent_req_done(req); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static errno_t ccdb_mem_set_default_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+struct ccdb_mem_get_default_state { -+ uuid_t dfl_uuid; -+}; -+ -+static struct tevent_req *ccdb_mem_get_default_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client) -+{ -+ struct tevent_req *req = NULL; -+ struct ccdb_mem_get_default_state *state = NULL; -+ struct ccache_mem_wrap *ccwrap = NULL; -+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ uid_t uid = cli_creds_get_uid(client); -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_get_default_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ -+ /* Reset all ccache defaults first */ -+ DLIST_FOR_EACH(ccwrap, memdb->head) { -+ if (ccwrap->cc == NULL) { -+ /* since KCM stores ccaches, better not crash.. */ -+ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n"); -+ continue; -+ } -+ -+ if (ccwrap->cc->owner.uid == uid && ccwrap->is_default == true) { -+ break; -+ } -+ } -+ -+ if (ccwrap == NULL) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "No ccache marked as default, returning null ccache\n"); -+ uuid_clear(state->dfl_uuid); -+ } else { -+ uuid_copy(state->dfl_uuid, ccwrap->cc->uuid); -+ } -+ -+ tevent_req_done(req); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static errno_t ccdb_mem_get_default_recv(struct tevent_req *req, -+ uuid_t dfl) -+{ -+ struct ccdb_mem_get_default_state *state = tevent_req_data(req, -+ struct ccdb_mem_get_default_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ -+ uuid_copy(dfl, state->dfl_uuid); -+ return EOK; -+} -+ -+struct ccdb_mem_getbyuuid_state { -+ struct kcm_ccache *cc; -+}; -+ -+static struct tevent_req *ccdb_mem_getbyuuid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ struct tevent_req *req = NULL; -+ struct ccdb_mem_getbyuuid_state *state = NULL; -+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ struct ccache_mem_wrap *ccwrap = NULL; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_getbyuuid_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ ccwrap = memdb_get_by_uuid(memdb, client, uuid); -+ if (ccwrap != NULL) { -+ state->cc = kcm_ccache_dup(state, ccwrap->cc); -+ } -+ -+ tevent_req_done(req); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static errno_t ccdb_mem_getbyuuid_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc) -+{ -+ struct ccdb_mem_getbyuuid_state *state = tevent_req_data(req, -+ struct ccdb_mem_getbyuuid_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_cc = talloc_steal(mem_ctx, state->cc); -+ return EOK; -+} -+ -+struct ccdb_mem_getbyname_state { -+ struct kcm_ccache *cc; -+}; -+ -+static struct tevent_req *ccdb_mem_getbyname_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ const char *name) -+{ -+ struct tevent_req *req = NULL; -+ struct ccdb_mem_getbyname_state *state = NULL; -+ struct ccache_mem_wrap *ccwrap = NULL; -+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_getbyname_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ ccwrap = memdb_get_by_name(memdb, client, name); -+ if (ccwrap != NULL) { -+ state->cc = kcm_ccache_dup(state, ccwrap->cc); -+ } -+ -+ tevent_req_done(req); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static errno_t ccdb_mem_getbyname_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc) -+{ -+ struct ccdb_mem_getbyname_state *state = tevent_req_data(req, -+ struct ccdb_mem_getbyname_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_cc = talloc_steal(mem_ctx, state->cc); -+ return EOK; -+} -+ -+struct ccdb_mem_name_by_uuid_state { -+ const char *name; -+}; -+ -+struct tevent_req *ccdb_mem_name_by_uuid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ struct tevent_req *req = NULL; -+ struct ccdb_mem_name_by_uuid_state *state = NULL; -+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ struct ccache_mem_wrap *ccwrap = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_name_by_uuid_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ ccwrap = memdb_get_by_uuid(memdb, client, uuid); -+ if (ccwrap == NULL) { -+ ret = ERR_KCM_CC_END; -+ goto immediate; -+ } -+ -+ state->name = talloc_strdup(state, ccwrap->cc->name); -+ if (state->name == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ ret = EOK; -+immediate: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+errno_t ccdb_mem_name_by_uuid_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ const char **_name) -+{ -+ struct ccdb_mem_name_by_uuid_state *state = tevent_req_data(req, -+ struct ccdb_mem_name_by_uuid_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_name = talloc_steal(mem_ctx, state->name); -+ return EOK; -+} -+ -+struct ccdb_mem_uuid_by_name_state { -+ uuid_t uuid; -+}; -+ -+struct tevent_req *ccdb_mem_uuid_by_name_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ const char *name) -+{ -+ struct tevent_req *req = NULL; -+ struct ccdb_mem_uuid_by_name_state *state = NULL; -+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ struct ccache_mem_wrap *ccwrap = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_uuid_by_name_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ ccwrap = memdb_get_by_name(memdb, client, name); -+ if (ccwrap == NULL) { -+ ret = ERR_KCM_CC_END; -+ goto immediate; -+ } -+ -+ uuid_copy(state->uuid, ccwrap->cc->uuid); -+ -+ ret = EOK; -+immediate: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+errno_t ccdb_mem_uuid_by_name_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ uuid_t _uuid) -+{ -+ struct ccdb_mem_uuid_by_name_state *state = tevent_req_data(req, -+ struct ccdb_mem_uuid_by_name_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ uuid_copy(_uuid, state->uuid); -+ return EOK; -+} -+ -+static struct tevent_req *ccdb_mem_create_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ struct kcm_ccache *cc) -+{ -+ struct tevent_req *req = NULL; -+ struct ccdb_mem_dummy_state *state = NULL; -+ struct ccache_mem_wrap *ccwrap; -+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ ccwrap = talloc_zero(memdb, struct ccache_mem_wrap); -+ if (ccwrap == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ ccwrap->cc = cc; -+ ccwrap->mem_be = memdb; -+ talloc_steal(ccwrap, cc); -+ -+ DLIST_ADD(memdb->head, ccwrap); -+ talloc_set_destructor((TALLOC_CTX *) ccwrap, ccwrap_destructor); -+ -+ ret = EOK; -+immediate: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static errno_t ccdb_mem_create_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+static struct tevent_req *ccdb_mem_mod_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid, -+ struct kcm_mod_ctx *mod_cc) -+{ -+ errno_t ret; -+ struct tevent_req *req = NULL; -+ struct ccdb_mem_dummy_state *state = NULL; -+ struct ccache_mem_wrap *ccwrap = NULL; -+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ /* UUID is immutable, so search by that */ -+ ccwrap = memdb_get_by_uuid(memdb, client, uuid); -+ if (ccwrap == NULL) { -+ ret = ERR_KCM_CC_END; -+ goto immediate; -+ } -+ -+ kcm_mod_cc(ccwrap->cc, mod_cc); -+ -+ ret = EOK; -+immediate: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static errno_t ccdb_mem_mod_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+static struct tevent_req *ccdb_mem_store_cred_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid, -+ struct sss_iobuf *cred_blob) -+{ -+ struct tevent_req *req = NULL; -+ struct ccdb_mem_dummy_state *state = NULL; -+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ struct ccache_mem_wrap *ccwrap = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ ccwrap = memdb_get_by_uuid(memdb, client, uuid); -+ if (ccwrap == NULL) { -+ ret = ERR_KCM_CC_END; -+ goto immediate; -+ } -+ -+ ret = kcm_cc_store_cred_blob(ccwrap->cc, cred_blob); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot store credentials to ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ -+ ret = EOK; -+immediate: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static errno_t ccdb_mem_store_cred_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+static struct tevent_req *ccdb_mem_delete_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ struct tevent_req *req = NULL; -+ struct ccdb_mem_dummy_state *state = NULL; -+ struct ccache_mem_wrap *ccwrap; -+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ ccwrap = memdb_get_by_uuid(memdb, client, uuid); -+ if (ccwrap == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "BUG: Attempting to free unknown ccache\n"); -+ ret = ERR_KCM_CC_END; -+ goto immediate; -+ } -+ -+ ret = EOK; -+ /* Destructor takes care of everything */ -+ talloc_free(ccwrap); -+immediate: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static errno_t ccdb_mem_delete_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+const struct kcm_ccdb_ops ccdb_mem_ops = { -+ .init = ccdb_mem_init, -+ -+ .nextid_send = ccdb_mem_nextid_send, -+ .nextid_recv = ccdb_mem_nextid_recv, -+ -+ .set_default_send = ccdb_mem_set_default_send, -+ .set_default_recv = ccdb_mem_set_default_recv, -+ -+ .get_default_send = ccdb_mem_get_default_send, -+ .get_default_recv = ccdb_mem_get_default_recv, -+ -+ .list_send = ccdb_mem_list_send, -+ .list_recv = ccdb_mem_list_recv, -+ -+ .getbyname_send = ccdb_mem_getbyname_send, -+ .getbyname_recv = ccdb_mem_getbyname_recv, -+ -+ .getbyuuid_send = ccdb_mem_getbyuuid_send, -+ .getbyuuid_recv = ccdb_mem_getbyuuid_recv, -+ -+ .name_by_uuid_send = ccdb_mem_name_by_uuid_send, -+ .name_by_uuid_recv = ccdb_mem_name_by_uuid_recv, -+ -+ .uuid_by_name_send = ccdb_mem_uuid_by_name_send, -+ .uuid_by_name_recv = ccdb_mem_uuid_by_name_recv, -+ -+ .create_send = ccdb_mem_create_send, -+ .create_recv = ccdb_mem_create_recv, -+ -+ .mod_send = ccdb_mem_mod_send, -+ .mod_recv = ccdb_mem_mod_recv, -+ -+ .store_cred_send = ccdb_mem_store_cred_send, -+ .store_cred_recv = ccdb_mem_store_cred_recv, -+ -+ .delete_send = ccdb_mem_delete_send, -+ .delete_recv = ccdb_mem_delete_recv, -+}; --- -2.9.3 - diff --git a/SOURCES/0025-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch b/SOURCES/0025-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch new file mode 100644 index 0000000..637d39b --- /dev/null +++ b/SOURCES/0025-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch @@ -0,0 +1,149 @@ +From 21633dc4ad13c0ebae0f2b4e4f4188556202113e Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 12 Oct 2017 10:42:41 +0200 +Subject: [PATCH 25/31] NSS: add support for SSS_NSS_EX_FLAG_NO_CACHE + +If SSS_NSS_EX_FLAG_NO_CACHE is set the object is refresh by directly +looking it up in the backend. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit ac6b267ff3df6d0417062a128ec16b184ea2c1b7) +--- + src/responder/nss/nss_cmd.c | 8 ++++ + src/sss_client/idmap/sss_nss_ex.c | 71 ++++++++++++++++++++---------------- + src/sss_client/idmap/sss_nss_idmap.h | 4 ++ + 3 files changed, 52 insertions(+), 31 deletions(-) + +diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c +index 974eaccc93cea3a330007735676da69eb9b84141..c5ddd2f2cc2122cd169ea991b94a14eb5bad095f 100644 +--- a/src/responder/nss/nss_cmd.c ++++ b/src/responder/nss/nss_cmd.c +@@ -92,6 +92,10 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + goto done; + } + ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { ++ cache_req_data_set_bypass_cache(data, true); ++ } ++ + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, + data, memcache, rawname, 0); + if (subreq == NULL) { +@@ -152,6 +156,10 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + goto done; + } + ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { ++ cache_req_data_set_bypass_cache(data, true); ++ } ++ + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, + data, memcache, NULL, id); + if (subreq == NULL) { +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +index dc7610a4e528b5126f0d25d84cd3c1a22f683b75..edb3ea652ef7032b76c8f815b9f83fe185a669ea 100644 +--- a/src/sss_client/idmap/sss_nss_ex.c ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -115,42 +115,51 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + size_t c; + gid_t *new_groups; + size_t idx; ++ bool skip_mc = false; + +- ret = sss_nss_mc_get(inp); +- switch (ret) { +- case 0: +- return 0; +- case ERANGE: +- return ERANGE; +- case ENOENT: +- /* fall through, we need to actively ask the parent +- * if no entry is found */ +- break; +- default: +- /* if using the mmaped cache failed, +- * fall back to socket based comms */ +- break; ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { ++ skip_mc = true; ++ } ++ ++ if (!skip_mc) { ++ ret = sss_nss_mc_get(inp); ++ switch (ret) { ++ case 0: ++ return 0; ++ case ERANGE: ++ return ERANGE; ++ case ENOENT: ++ /* fall through, we need to actively ask the parent ++ * if no entry is found */ ++ break; ++ default: ++ /* if using the mmaped cache failed, ++ * fall back to socket based comms */ ++ break; ++ } + } + + sss_nss_timedlock(timeout, &time_left); + +- /* previous thread might already initialize entry in mmap cache */ +- ret = sss_nss_mc_get(inp); +- switch (ret) { +- case 0: +- ret = 0; +- goto out; +- case ERANGE: +- ret = ERANGE; +- goto out; +- case ENOENT: +- /* fall through, we need to actively ask the parent +- * if no entry is found */ +- break; +- default: +- /* if using the mmaped cache failed, +- * fall back to socket based comms */ +- break; ++ if (!skip_mc) { ++ /* previous thread might already initialize entry in mmap cache */ ++ ret = sss_nss_mc_get(inp); ++ switch (ret) { ++ case 0: ++ ret = 0; ++ goto out; ++ case ERANGE: ++ ret = ERANGE; ++ goto out; ++ case ENOENT: ++ /* fall through, we need to actively ask the parent ++ * if no entry is found */ ++ break; ++ default: ++ /* if using the mmaped cache failed, ++ * fall back to socket based comms */ ++ break; ++ } + } + + ret = sss_nss_make_request_timeout(inp->cmd, &inp->rd, time_left, +diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h +index 2334b6cb3fb8ef62e4ce3a7187c7affaeaa034e7..1649830afbb80c617fd339f054aef8bc8e585fb9 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.h ++++ b/src/sss_client/idmap/sss_nss_idmap.h +@@ -169,6 +169,10 @@ void sss_nss_free_kv(struct sss_nss_kv *kv_list); + + #define SSS_NSS_EX_FLAG_NO_FLAGS 0 + ++/** Always request data from the server side, client must be privileged to do ++ * so, see nss_trusted_users option in man sssd.conf for details */ ++#define SSS_NSS_EX_FLAG_NO_CACHE (1 << 0) ++ + #ifdef IPA_389DS_PLUGIN_HELPER_CALLS + + /** +-- +2.13.6 + diff --git a/SOURCES/0026-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch b/SOURCES/0026-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch new file mode 100644 index 0000000..e0dd792 --- /dev/null +++ b/SOURCES/0026-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch @@ -0,0 +1,112 @@ +From 102ea8cf91207d3dc05537d5c558d98e4756027a Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 23 Oct 2017 18:26:55 +0200 +Subject: [PATCH 26/31] CACHE_REQ: Add cache_req_data_set_bypass_dp() + +Similar to cache_req_data_set_bypass_cache() +cache_req_data_set_bypass_dp() can be used to control how the cache_req +framework performs the lookup. If cache_req_data_set_bypass_dp() is used +with 'true' only a cache lookup is performed and no request is send to +the backend even if no entry was found. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 52e675ec4b160720515c81ae8c0e5a95feb50c57) +--- + src/responder/common/cache_req/cache_req.c | 15 +++++++++++++++ + src/responder/common/cache_req/cache_req.h | 3 +++ + src/responder/common/cache_req/cache_req_data.c | 12 ++++++++++++ + src/responder/common/cache_req/cache_req_private.h | 2 ++ + 4 files changed, 32 insertions(+) + +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index 5fed7a2ab8beded2fee91f679a12f9a0ff6013ec..110df561101be538e3f0496addfa2e14e42ea918 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -142,6 +142,13 @@ cache_req_create(TALLOC_CTX *mem_ctx, + + cr->cache_first = rctx->cache_first; + cr->bypass_cache = cr->plugin->bypass_cache || cr->data->bypass_cache; ++ cr->bypass_dp = cr->data->bypass_dp; ++ if (cr->bypass_cache && cr->bypass_dp) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, ++ "Cannot bypass cache and dp at the same time!"); ++ talloc_free(cr); ++ return NULL; ++ } + + return cr; + } +@@ -661,6 +668,14 @@ static bool cache_req_search_schema(struct cache_req *cr, + if (!first_iteration) { + return false; + } ++ } else if (cr->bypass_dp) { ++ /* The caller wants to lookup only in the cache */ ++ bypass_cache = false; ++ bypass_dp = true; ++ ++ if (!first_iteration) { ++ return false; ++ } + } else if (input_domain != NULL) { + /* We will search only one domain. */ + bypass_cache = false; +diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h +index c04b2fba6f0445dcfcc9cfe1b5963ac975c39118..2c88853887fc816bba2182d9d9beaa32fa384158 100644 +--- a/src/responder/common/cache_req/cache_req.h ++++ b/src/responder/common/cache_req/cache_req.h +@@ -127,6 +127,9 @@ void + cache_req_data_set_bypass_cache(struct cache_req_data *data, + bool bypass_cache); + ++void ++cache_req_data_set_bypass_dp(struct cache_req_data *data, ++ bool bypass_dp); + /* Output data. */ + + struct cache_req_result { +diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c +index 48264a321dc603f9708ba71c44542363b11a71ba..ed378274a9a0a68ede8ac99805f3ea4a041382e6 100644 +--- a/src/responder/common/cache_req/cache_req_data.c ++++ b/src/responder/common/cache_req/cache_req_data.c +@@ -365,3 +365,15 @@ cache_req_data_set_bypass_cache(struct cache_req_data *data, + + data->bypass_cache = bypass_cache; + } ++ ++void ++cache_req_data_set_bypass_dp(struct cache_req_data *data, ++ bool bypass_dp) ++{ ++ if (data == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_data should never be NULL\n"); ++ return; ++ } ++ ++ data->bypass_dp = bypass_dp; ++} +diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h +index 9b706ff7d678f543effb77089857a7e8a42a9c51..0f630542d38a277d1819063fa4134bd7d2525c90 100644 +--- a/src/responder/common/cache_req/cache_req_private.h ++++ b/src/responder/common/cache_req/cache_req_private.h +@@ -42,6 +42,7 @@ struct cache_req { + struct sss_domain_info *domain; + bool cache_first; + bool bypass_cache; ++ bool bypass_dp; + /* Only contact domains with this type */ + enum cache_req_dom_type req_dom_type; + +@@ -90,6 +91,7 @@ struct cache_req_data { + } svc; + + bool bypass_cache; ++ bool bypass_dp; + }; + + struct tevent_req * +-- +2.13.6 + diff --git a/SOURCES/0026-KCM-Implement-KCM-server-operations.patch b/SOURCES/0026-KCM-Implement-KCM-server-operations.patch deleted file mode 100644 index 56f486a..0000000 --- a/SOURCES/0026-KCM-Implement-KCM-server-operations.patch +++ /dev/null @@ -1,2326 +0,0 @@ -From 5287b672cbba97a5c30ca79954101bd134a30eca Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 23 Sep 2016 14:49:09 +0200 -Subject: [PATCH 26/36] KCM: Implement KCM server operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Implements the actual KCM server operations. On a high level, each -operation unmarhalls the needed data from the input buffer, calls into -the ccache db and marshalls a response. - -Only the operations that are also implemented by the MIT client are -implemented by our KCM server. - -Resolves: - https://pagure.io/SSSD/sssd/issue/2887 - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - Makefile.am | 2 + - src/responder/kcm/kcmsrv_cmd.c | 151 +++- - src/responder/kcm/kcmsrv_ops.c | 1954 ++++++++++++++++++++++++++++++++++++++++ - src/responder/kcm/kcmsrv_ops.h | 45 + - 4 files changed, 2143 insertions(+), 9 deletions(-) - create mode 100644 src/responder/kcm/kcmsrv_ops.c - create mode 100644 src/responder/kcm/kcmsrv_ops.h - -diff --git a/Makefile.am b/Makefile.am -index 5605c1a53c44fd9e83394e80b7f71828df1d39b6..49b4cabf9ee3ce1417f955c972376894f3709b33 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -714,6 +714,7 @@ dist_noinst_HEADERS = \ - src/responder/kcm/kcmsrv_ccache.h \ - src/responder/kcm/kcmsrv_ccache_pvt.h \ - src/responder/kcm/kcmsrv_ccache_be.h \ -+ src/responder/kcm/kcmsrv_ops.h \ - src/sbus/sbus_client.h \ - src/sbus/sssd_dbus.h \ - src/sbus/sssd_dbus_meta.h \ -@@ -1493,6 +1494,7 @@ sssd_kcm_SOURCES = \ - src/responder/kcm/kcmsrv_cmd.c \ - src/responder/kcm/kcmsrv_ccache.c \ - src/responder/kcm/kcmsrv_ccache_mem.c \ -+ src/responder/kcm/kcmsrv_ops.c \ - src/util/sss_sockets.c \ - src/util/sss_krb5.c \ - src/util/sss_iobuf.c \ -diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c -index cbf70353730d8a4e03d8f75c97395f4ef007e77f..537e88953fd1a190a9a73bcdd430d8e0db8f9291 100644 ---- a/src/responder/kcm/kcmsrv_cmd.c -+++ b/src/responder/kcm/kcmsrv_cmd.c -@@ -23,10 +23,10 @@ - - #include "config.h" - #include "util/util.h" --#include "util/sss_iobuf.h" - #include "responder/common/responder.h" - #include "responder/kcm/kcmsrv_pvt.h" - #include "responder/kcm/kcm.h" -+#include "responder/kcm/kcmsrv_ops.h" - - /* The first four bytes of a message is always the size */ - #define KCM_MSG_LEN_SIZE 4 -@@ -133,7 +133,6 @@ static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf, - { - size_t lc = 0; - size_t mc = 0; -- uint16_t opcode = 0; - uint16_t opcode_be = 0; - uint32_t len_be = 0; - uint32_t msglen; -@@ -162,7 +161,7 @@ static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf, - return EBADMSG; - } - -- /* First 16 bits are 8 bit major and 8bit major protocol version */ -+ /* First 16 bits are 8 bit major and 8bit minor protocol version */ - SAFEALIGN_COPY_UINT8_CHECK(&proto_maj, - reqbuf->v_msg.kiov_base + mc, - reqbuf->v_msg.kiov_len, -@@ -191,8 +190,16 @@ static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf, - reqbuf->v_msg.kiov_len, - &mc); - -- opcode = be16toh(opcode_be); -- DEBUG(SSSDBG_TRACE_LIBS, "Received operation code %"PRIu16"\n", opcode); -+ op_io->op = kcm_get_opt(be16toh(opcode_be)); -+ if (op_io->op == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Did not find a KCM operation handler for the requested opcode\n"); -+ return ERR_KCM_MALFORMED_IN_PKT; -+ } -+ -+ /* The operation only receives the payload, not the opcode or the protocol info */ -+ op_io->request.data = reqbuf->v_msg.kiov_base + mc; -+ op_io->request.length = reqbuf->v_msg.nprocessed - mc; - - return EOK; - } -@@ -240,6 +247,46 @@ static errno_t kcm_failbuf_construct(errno_t ret, - c = 0; - SAFEALIGN_SETMEM_UINT32(repbuf->rcbuf, htobe32(ret), &c); - -+ DEBUG(SSSDBG_TRACE_LIBS, "Sent reply with error %d\n", ret); -+ return EOK; -+} -+ -+/* retcode is 0 if the operation at least ran, non-zero if there -+ * was some kind of internal KCM error, like input couldn't be parsed -+ */ -+static errno_t kcm_output_construct(struct kcm_op_io *op_io, -+ struct kcm_repbuf *repbuf) -+{ -+ size_t c; -+ size_t replen; -+ -+ replen = sss_iobuf_get_len(op_io->reply); -+ if (replen > KCM_PACKET_MAX_SIZE) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Reply exceeds the KCM protocol limit, aborting\n"); -+ return E2BIG; -+ } -+ -+ DEBUG(SSSDBG_TRACE_LIBS, -+ "Sending a reply with %zu bytes of payload\n", replen); -+ c = 0; -+ SAFEALIGN_SETMEM_UINT32(repbuf->lenbuf, htobe32(replen), &c); -+ -+ c = 0; -+ SAFEALIGN_SETMEM_UINT32(repbuf->rcbuf, 0, &c); -+ -+ if (replen > 0) { -+ c = 0; -+ SAFEALIGN_MEMCPY_CHECK(repbuf->msgbuf, -+ sss_iobuf_get_data(op_io->reply), -+ replen, -+ repbuf->v_msg.kiov_len, -+ &c); -+ -+ /* Length of the buffer to send to KCM client */ -+ repbuf->v_msg.kiov_len = replen; -+ } -+ - return EOK; - } - -@@ -260,7 +307,8 @@ static void kcm_reply_error(struct cli_ctx *cctx, - - ret = kcm_failbuf_construct(kerr, repbuf); - if (ret != EOK) { -- /* If we can't construct the reply buffer, just terminate the client */ -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot construct the reply buffer, terminating client\n"); - talloc_free(cctx); - return; - } -@@ -268,6 +316,24 @@ static void kcm_reply_error(struct cli_ctx *cctx, - TEVENT_FD_WRITEABLE(cctx->cfde); - } - -+static void kcm_send_reply(struct cli_ctx *cctx, -+ struct kcm_op_io *op_io, -+ struct kcm_repbuf *repbuf) -+{ -+ errno_t ret; -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Sending a reply\n"); -+ ret = kcm_output_construct(op_io, repbuf); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot construct the reply buffer, terminating client\n"); -+ kcm_reply_error(cctx, ret, repbuf); -+ return; -+ } -+ -+ TEVENT_FD_WRITEABLE(cctx->cfde); -+} -+ - /** - * Request-reply dispatcher - */ -@@ -285,17 +351,67 @@ struct kcm_req_ctx { - struct kcm_op_io op_io; - }; - -+static void kcm_cmd_request_done(struct tevent_req *req); -+ -+static errno_t kcm_cmd_dispatch(struct kcm_req_ctx *req_ctx) -+{ -+ struct tevent_req *req; -+ struct cli_ctx *cctx; -+ -+ cctx = req_ctx->cctx; -+ -+ req = kcm_cmd_send(req_ctx, cctx->ev, req_ctx->kctx->kcm_data, -+ req_ctx->cctx->creds, -+ &req_ctx->op_io.request, -+ req_ctx->op_io.op); -+ if (req == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to schedule KCM operation.\n"); -+ return ENOMEM; -+ } -+ -+ tevent_req_set_callback(req, kcm_cmd_request_done, req_ctx); -+ return EOK; -+} -+ -+static void kcm_cmd_request_done(struct tevent_req *req) -+{ -+ struct kcm_req_ctx *req_ctx; -+ struct cli_ctx *cctx; -+ errno_t ret; -+ -+ req_ctx = tevent_req_callback_data(req, struct kcm_req_ctx); -+ cctx = req_ctx->cctx; -+ -+ ret = kcm_cmd_recv(req_ctx, req, -+ &req_ctx->op_io.reply); -+ talloc_free(req); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "KCM operation failed [%d]: %s\n", ret, sss_strerror(ret)); -+ kcm_reply_error(cctx, ret, &req_ctx->repbuf); -+ return; -+ } -+ -+ kcm_send_reply(cctx, &req_ctx->op_io, &req_ctx->repbuf); -+} -+ - static errno_t kcm_recv_data(int fd, struct kcm_reqbuf *reqbuf) - { - errno_t ret; - - ret = kcm_read_iovec(fd, &reqbuf->v_len); - if (ret != EOK) { -+ /* Not all errors are fatal, hence we don't print DEBUG messages -+ * here, but in the caller -+ */ - return ret; - } - - ret = kcm_read_iovec(fd, &reqbuf->v_msg); - if (ret != EOK) { -+ /* Not all errors are fatal, hence we don't print DEBUG messages -+ * here, but in the caller -+ */ - return ret; - } - -@@ -389,7 +505,15 @@ static void kcm_recv(struct cli_ctx *cctx) - /* do not read anymore, client is done sending */ - TEVENT_FD_NOT_READABLE(cctx->cfde); - -- kcm_reply_error(cctx, ret, &req->repbuf); -+ ret = kcm_cmd_dispatch(req); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "Failed to dispatch KCM operation [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto fail; -+ } -+ -+ /* Dispatched request resumes in kcm_cmd_request_done */ - return; - - fail: -@@ -406,16 +530,25 @@ static int kcm_send_data(struct cli_ctx *cctx) - - ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_len); - if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to write the length iovec [%d]: %s\n", -+ ret, sss_strerror(ret)); - return ret; - } - - ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_rc); - if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to write the retcode iovec [%d]: %s\n", -+ ret, sss_strerror(ret)); - return ret; - } - - ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_msg); - if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to write the msg iovec [%d]: %s\n", -+ ret, sss_strerror(ret)); - return ret; - } - -@@ -428,7 +561,7 @@ static void kcm_send(struct cli_ctx *cctx) - - ret = kcm_send_data(cctx); - if (ret == EAGAIN) { -- /* not all data was sent, loop again */ -+ DEBUG(SSSDBG_TRACE_ALL, "Sending data again..\n"); - return; - } else if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n"); -@@ -436,7 +569,7 @@ static void kcm_send(struct cli_ctx *cctx) - return; - } - -- /* ok all sent */ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "All data sent!\n"); - TEVENT_FD_NOT_WRITEABLE(cctx->cfde); - TEVENT_FD_READABLE(cctx->cfde); - talloc_zfree(cctx->state_ctx); -diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c -new file mode 100644 -index 0000000000000000000000000000000000000000..50e8cc635424e15d53e3c8d122c5525044f59c8a ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_ops.c -@@ -0,0 +1,1954 @@ -+/* -+ SSSD -+ -+ KCM Server - the KCM server operations -+ -+ Copyright (C) Red Hat, 2016 -+ -+ 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 "config.h" -+ -+#include -+ -+#include "util/sss_iobuf.h" -+#include "util/sss_krb5.h" -+#include "util/util_creds.h" -+#include "responder/kcm/kcm.h" -+#include "responder/kcm/kcmsrv_pvt.h" -+#include "responder/kcm/kcmsrv_ops.h" -+#include "responder/kcm/kcmsrv_ccache.h" -+ -+#define KCM_REPLY_MAX 2048 -+ -+struct kcm_op_ctx { -+ struct kcm_resp_ctx *kcm_data; -+ struct cli_creds *client; -+ -+ struct sss_iobuf *input; -+ struct sss_iobuf *reply; -+}; -+ -+/* Each operation follows the same pattern and is implemented using -+ * functions with this prototype. The operation receives an op_ctx -+ * that serves as a state of the operation and can be used to keep -+ * track of any temporary data. The operation writes its output data -+ * into the op_ctx reply IO buffer and returns the op_ret status code -+ * separately. -+ * -+ * The operation always returns EOK unless an internal error occurs, -+ * the result of the operation is stored in the op_ret variable -+ */ -+typedef struct tevent_req* -+(*kcm_srv_send_method)(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx); -+typedef errno_t -+(*kcm_srv_recv_method)(struct tevent_req *req, -+ uint32_t *_op_ret); -+ -+struct kcm_op { -+ const char *name; -+ kcm_srv_send_method fn_send; -+ kcm_srv_recv_method fn_recv; -+}; -+ -+struct kcm_cmd_state { -+ struct kcm_op *op; -+ -+ struct kcm_op_ctx *op_ctx; -+ struct sss_iobuf *reply; -+ -+ uint32_t op_ret; -+}; -+ -+static void kcm_cmd_done(struct tevent_req *subreq); -+ -+struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_resp_ctx *kcm_data, -+ struct cli_creds *client, -+ struct kcm_data *input, -+ struct kcm_op *op) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_cmd_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_cmd_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op = op; -+ -+ if (op == NULL) { -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ DEBUG(SSSDBG_TRACE_FUNC, "KCM operation %s\n", op->name); -+ DEBUG(SSSDBG_TRACE_LIBS, "%zu bytes on KCM input\n", input->length); -+ -+ state->reply = sss_iobuf_init_empty(state, -+ KCM_REPLY_MAX, -+ KCM_REPLY_MAX); -+ if (state->reply == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ if (op->fn_send == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "KCM op %s has no handler\n", kcm_opt_name(op)); -+ ret = ERR_KCM_OP_NOT_IMPLEMENTED; -+ goto immediate; -+ } -+ -+ /* Allocating op_ctx on the heap makes it possible for operations to use -+ * op_ctx as their temporary context and avoid tmp_ctx altogether -+ */ -+ state->op_ctx = talloc_zero(state, struct kcm_op_ctx); -+ if (state->op_ctx == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ state->op_ctx->kcm_data = kcm_data; -+ state->op_ctx->client = client; -+ -+ state->op_ctx->input = sss_iobuf_init_readonly(state->op_ctx, -+ input->data, -+ input->length); -+ if (state->op_ctx->input == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ /* -+ * The internal operation returns the opcode and the buffer separately. -+ * The KCM server reply to the client also always contains zero if the -+ * operation ran to completion, both are uint32_t. -+ * FIXME: -+ * Alternatively, we could extend iobuf API so that we can just pass -+ * the reply's buffer+sizeof(2*uint32_t) and avoid the useless allocations -+ */ -+ state->op_ctx->reply = sss_iobuf_init_empty( -+ state, -+ KCM_REPLY_MAX - 2*sizeof(uint32_t), -+ KCM_REPLY_MAX - 2*sizeof(uint32_t)); -+ if (state->reply == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ subreq = op->fn_send(state, ev, state->op_ctx); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_cmd_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_cmd_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ struct kcm_cmd_state *state = tevent_req_data(req, struct kcm_cmd_state); -+ errno_t ret; -+ krb5_error_code kerr; -+ -+ ret = state->op->fn_recv(subreq, &state->op_ret); -+ talloc_free(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "op receive function failed [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "KCM operation %s returned [%d]: %s\n", -+ kcm_opt_name(state->op), state->op_ret, sss_strerror(state->op_ret)); -+ -+ kerr = sss2krb5_error(state->op_ret); -+ -+ /* The first four bytes of the reply is the operation status code */ -+ ret = sss_iobuf_write_uint32(state->reply, htobe32(kerr)); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ ret = sss_iobuf_write_len(state->reply, -+ sss_iobuf_get_data(state->op_ctx->reply), -+ sss_iobuf_get_len(state->op_ctx->reply)); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+errno_t kcm_cmd_recv(TALLOC_CTX *mem_ctx, -+ struct tevent_req *req, -+ struct sss_iobuf **_reply) -+{ -+ struct kcm_cmd_state *state = NULL; -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ -+ state = tevent_req_data(req, struct kcm_cmd_state); -+ -+ *_reply = talloc_steal(mem_ctx, state->reply); -+ return EOK; -+} -+ -+/* ======= KCM operations ======= */ -+ -+/* Operations that don't return any extra information except for the op_ret -+ * can use this macro in the _recv function to avoid code duplication -+ */ -+#define KCM_OP_RET_FROM_TYPE(req, state_type, _op_ret_out) do { \ -+ state_type *state = NULL; \ -+ state = tevent_req_data(req, state_type); \ -+ TEVENT_REQ_RETURN_ON_ERROR(req); \ -+ *_op_ret_out = state->op_ret; \ -+ return EOK; \ -+} while(0); -+ -+struct kcm_op_common_state { -+ uint32_t op_ret; -+ struct kcm_op_ctx *op_ctx; -+ struct tevent_context *ev; -+}; -+ -+static errno_t kcm_op_common_recv(struct tevent_req *req, -+ uint32_t *_op_ret) -+{ -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_op_ret = state->op_ret; -+ return EOK; -+} -+ -+/* () -> (name) */ -+static void kcm_op_gen_new_done(struct tevent_req *subreq); -+ -+static struct tevent_req *kcm_op_gen_new_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_common_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ -+ subreq = kcm_ccdb_nextid_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_gen_new_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_gen_new_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ char *newid; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ -+ ret = kcm_ccdb_nextid_recv(subreq, state, &newid); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot generate a new ID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "Generated a new ID %s\n", newid); -+ -+ ret = sss_iobuf_write_stringz(state->op_ctx->reply, newid); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot write generated ID %d: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+/* (princ) -> () */ -+struct kcm_op_initialize_state { -+ uint32_t op_ret; -+ struct kcm_op_ctx *op_ctx; -+ struct tevent_context *ev; -+ -+ struct kcm_ccache *new_cc; -+ const char *name; -+ krb5_principal princ; -+}; -+ -+static void kcm_op_initialize_got_byname(struct tevent_req *subreq); -+static void kcm_op_initialize_cc_create_done(struct tevent_req *subreq); -+static void kcm_op_initialize_cc_delete_done(struct tevent_req *subreq); -+static void kcm_op_initialize_create_step(struct tevent_req *req); -+static void kcm_op_initialize_got_default(struct tevent_req *subreq); -+static void kcm_op_initialize_set_default_done(struct tevent_req *subreq); -+ -+static struct tevent_req *kcm_op_initialize_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_initialize_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_initialize_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ state->ev = ev; -+ -+ ret = sss_iobuf_read_stringz(op_ctx->input, &state->name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot read input name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ DEBUG(SSSDBG_TRACE_LIBS, "Initializing ccache %s\n", state->name); -+ -+ ret = kcm_check_name(state->name, op_ctx->client); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Name %s is malformed [%d]: %s\n", -+ state->name, ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ -+ ret = sss_krb5_unmarshal_princ(op_ctx, op_ctx->input, &state->princ); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot unmarshal principal [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ -+ subreq = kcm_ccdb_getbyname_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client, -+ state->name); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_initialize_got_byname, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_initialize_got_byname(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_initialize_state *state = tevent_req_data(req, -+ struct kcm_op_initialize_state); -+ bool ok; -+ uuid_t uuid; -+ -+ ret = kcm_ccdb_getbyname_recv(subreq, state, &state->new_cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get ccache by name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (state->new_cc != NULL) { -+ ok = kcm_cc_access(state->new_cc, state->op_ctx->client); -+ if (!ok) { -+ state->op_ret = EACCES; -+ tevent_req_done(req); -+ return; -+ } -+ -+ ret = kcm_cc_get_uuid(state->new_cc, uuid); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get new ccache UUID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return; -+ } -+ -+ /* Nuke any previous cache and its contents during initialization */ -+ subreq = kcm_ccdb_delete_cc_send(state, -+ state->ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client, -+ uuid); -+ if (subreq == NULL) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_op_initialize_cc_delete_done, req); -+ return; -+ } -+ -+ kcm_op_initialize_create_step(req); -+} -+ -+static void kcm_op_initialize_cc_delete_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ errno_t ret; -+ -+ ret = kcm_ccdb_delete_cc_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot delete ccache from the db %d: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ kcm_op_initialize_create_step(req); -+} -+ -+static void kcm_op_initialize_create_step(struct tevent_req *req) -+{ -+ struct tevent_req *subreq; -+ struct kcm_op_initialize_state *state = tevent_req_data(req, -+ struct kcm_op_initialize_state); -+ errno_t ret; -+ -+ ret = kcm_cc_new(state->op_ctx, -+ state->op_ctx->kcm_data->k5c, -+ state->op_ctx->client, -+ state->name, -+ state->princ, -+ &state->new_cc); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot create new ccache %d: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ subreq = kcm_ccdb_create_cc_send(state, -+ state->ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client, -+ state->new_cc); -+ if (subreq == NULL) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_op_initialize_cc_create_done, req); -+} -+ -+static void kcm_op_initialize_cc_create_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_initialize_state *state = tevent_req_data(req, -+ struct kcm_op_initialize_state); -+ errno_t ret; -+ -+ ret = kcm_ccdb_create_cc_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot add ccache to db %d: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ /* If there was no previous default ccache, set this one as default */ -+ subreq = kcm_ccdb_get_default_send(state, state->ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client); -+ if (subreq == NULL) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_op_initialize_got_default, req); -+} -+ -+static void kcm_op_initialize_got_default(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_initialize_state *state = tevent_req_data(req, -+ struct kcm_op_initialize_state); -+ errno_t ret; -+ uuid_t dfl_uuid; -+ uuid_t old_dfl_uuid; -+ -+ ret = kcm_ccdb_get_default_recv(subreq, &old_dfl_uuid); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get default ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (uuid_is_null(old_dfl_uuid) == false) { -+ /* If there was a previous default ccache, switch to the initialized -+ * one by default -+ */ -+ ret = kcm_cc_get_uuid(state->new_cc, dfl_uuid); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get new ccache UUID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return; -+ } -+ -+ subreq = kcm_ccdb_set_default_send(state, -+ state->ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client, -+ dfl_uuid); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_op_initialize_set_default_done, req); -+ return; -+ } -+ -+ /* ENOENT, done */ -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+static void kcm_op_initialize_set_default_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_initialize_state *state = tevent_req_data(req, -+ struct kcm_op_initialize_state); -+ errno_t ret; -+ -+ ret = kcm_ccdb_set_default_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot set default ccache %d: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+static errno_t kcm_op_initialize_recv(struct tevent_req *req, -+ uint32_t *_op_ret) -+{ -+ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_initialize_state, _op_ret); -+} -+ -+/* (name) -> () */ -+static void kcm_op_destroy_getbyname_done(struct tevent_req *subreq); -+static void kcm_op_destroy_delete_done(struct tevent_req *subreq); -+ -+static struct tevent_req *kcm_op_destroy_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_common_state *state = NULL; -+ errno_t ret; -+ const char *name; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ state->ev = ev; -+ -+ ret = sss_iobuf_read_stringz(op_ctx->input, &name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot unmarshall input name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "Destroying credentials of %s\n", name); -+ -+ subreq = kcm_ccdb_uuid_by_name_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client, -+ name); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_destroy_getbyname_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_destroy_getbyname_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ uuid_t uuid; -+ -+ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, uuid); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get matching ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ subreq = kcm_ccdb_delete_cc_send(state, -+ state->ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client, -+ uuid); -+ if (subreq == NULL) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_op_destroy_delete_done, req); -+} -+ -+static void kcm_op_destroy_delete_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ -+ ret = kcm_ccdb_delete_cc_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot delete ccache from the db [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+/* (name, cred) -> () */ -+struct kcm_op_store_state { -+ uint32_t op_ret; -+ struct kcm_op_ctx *op_ctx; -+ struct tevent_context *ev; -+ -+ struct sss_iobuf *cred_blob; -+}; -+ -+static void kcm_op_store_getbyname_done(struct tevent_req *subreq); -+static void kcm_op_store_done(struct tevent_req *subreq); -+ -+static struct tevent_req *kcm_op_store_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_store_state *state = NULL; -+ errno_t ret; -+ const char *name; -+ size_t creds_len; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_store_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ state->ev = ev; -+ -+ ret = sss_iobuf_read_stringz(op_ctx->input, &name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot unmarshall input name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "Storing credentials for %s\n", name); -+ -+ creds_len = sss_iobuf_get_size(op_ctx->input) - strlen(name) -1; -+ if (creds_len > KCM_REPLY_MAX) { -+ /* Protects against underflows and in general adds sanity */ -+ ret = E2BIG; -+ goto immediate; -+ } -+ -+ state->cred_blob = sss_iobuf_init_empty(state, -+ creds_len, -+ creds_len); -+ if (state->cred_blob == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ ret = sss_iobuf_read(op_ctx->input, -+ creds_len, -+ sss_iobuf_get_data(state->cred_blob), -+ NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot unmarshall input cred blob [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ -+ subreq = kcm_ccdb_uuid_by_name_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client, -+ name); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_store_getbyname_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_store_getbyname_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_store_state *state = tevent_req_data(req, -+ struct kcm_op_store_state); -+ uuid_t uuid; -+ -+ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, uuid); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get ccache by name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ subreq = kcm_ccdb_store_cred_blob_send(state, state->ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client, -+ uuid, -+ state->cred_blob); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_op_store_done, req); -+} -+ -+static void kcm_op_store_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_store_state *state = tevent_req_data(req, -+ struct kcm_op_store_state); -+ -+ ret = kcm_ccdb_store_cred_blob_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot store credentials [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+static errno_t kcm_op_store_recv(struct tevent_req *req, -+ uint32_t *_op_ret) -+{ -+ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_store_state, _op_ret); -+} -+ -+/* (name) -> (princ) */ -+static void kcm_op_get_principal_getbyname_done(struct tevent_req *subreq); -+ -+static struct tevent_req *kcm_op_get_principal_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_common_state *state = NULL; -+ errno_t ret; -+ const char *name; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ -+ ret = sss_iobuf_read_stringz(op_ctx->input, &name); -+ if (ret != EOK) { -+ goto immediate; -+ } -+ DEBUG(SSSDBG_TRACE_LIBS, "Requested principal %s\n", name); -+ -+ subreq = kcm_ccdb_getbyname_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client, -+ name); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_get_principal_getbyname_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_get_principal_getbyname_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct kcm_ccache *cc; -+ krb5_principal princ; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ -+ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get ccache by name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (cc == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that name\n"); -+ state->op_ret = ERR_NO_MATCHING_CREDS; -+ tevent_req_done(req); -+ return; -+ } -+ -+ /* Marshall the principal to the reply */ -+ princ = kcm_cc_get_client_principal(cc); -+ if (princ == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Credentials with no principal?\n"); -+ tevent_req_error(req, EIO); -+ return; -+ } -+ -+ ret = sss_krb5_marshal_princ(princ, state->op_ctx->reply); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot marshall principal [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+/* (name) -> (uuid, ...) */ -+static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq); -+ -+static struct tevent_req * -+kcm_op_get_cred_uuid_list_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_common_state *state = NULL; -+ errno_t ret; -+ const char *name; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ -+ ret = sss_iobuf_read_stringz(op_ctx->input, &name); -+ if (ret != EOK) { -+ goto immediate; -+ } -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "Returning UUID list for %s\n", name); -+ -+ subreq = kcm_ccdb_getbyname_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client, -+ name); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_get_cred_uuid_getbyname_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct kcm_ccache *cc; -+ struct kcm_cred *crd; -+ uuid_t uuid; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ -+ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get ccache by name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (cc == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n"); -+ state->op_ret = ERR_NO_CREDS; -+ tevent_req_done(req); -+ return; -+ } -+ -+ for (crd = kcm_cc_get_cred(cc); -+ crd != NULL; -+ crd = kcm_cc_next_cred(crd)) { -+ ret = kcm_cred_get_uuid(crd, uuid); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "Credential has no UUID, skipping\n"); -+ continue; -+ } -+ -+ kcm_debug_uuid(uuid); -+ -+ ret = sss_iobuf_write_len(state->op_ctx->reply, -+ uuid, UUID_BYTES); -+ if (ret != EOK) { -+ char uuid_errbuf[UUID_STR_SIZE]; -+ uuid_parse(uuid_errbuf, uuid); -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Cannot marshall UUID %s [%d]: %s\n", -+ uuid_errbuf, ret, sss_strerror(ret)); -+ continue; -+ } -+ } -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+/* (name, uuid) -> (cred) */ -+static void kcm_op_get_cred_by_uuid_getbyname_done(struct tevent_req *subreq); -+ -+static struct tevent_req * -+kcm_op_get_cred_by_uuid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_common_state *state = NULL; -+ errno_t ret; -+ const char *name; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ -+ ret = sss_iobuf_read_stringz(op_ctx->input, &name); -+ if (ret != EOK) { -+ goto immediate; -+ } -+ DEBUG(SSSDBG_TRACE_LIBS, "Returning creds by UUID for %s\n", name); -+ -+ subreq = kcm_ccdb_getbyname_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client, -+ name); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_get_cred_by_uuid_getbyname_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_get_cred_by_uuid_getbyname_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ errno_t ret; -+ struct kcm_ccache *cc; -+ struct kcm_cred *crd; -+ uuid_t uuid_in; -+ uuid_t uuid; -+ struct sss_iobuf *cred_blob; -+ -+ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get ccache by name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (cc == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that name\n"); -+ state->op_ret = ERR_NO_MATCHING_CREDS; -+ tevent_req_done(req); -+ return; -+ } -+ -+ ret = sss_iobuf_read_len(state->op_ctx->input, -+ UUID_BYTES, uuid_in); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot read input UUID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ for (crd = kcm_cc_get_cred(cc); -+ crd != NULL; -+ crd = kcm_cc_next_cred(crd)) { -+ ret = kcm_cred_get_uuid(crd, uuid); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Cannot get UUID from creds, skipping\n"); -+ continue; -+ } -+ -+ if (uuid_compare(uuid, uuid_in) == 0) { -+ break; -+ } -+ kcm_debug_uuid(uuid); -+ } -+ -+ if (crd == NULL) { -+ state->op_ret = ERR_KCM_CC_END; -+ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n"); -+ tevent_req_done(req); -+ return; -+ } -+ -+ cred_blob = kcm_cred_get_creds(crd); -+ if (cred_blob == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Credentials lack the creds blob\n"); -+ state->op_ret = ERR_NO_CREDS; -+ tevent_req_done(req); -+ return; -+ } -+ -+ ret = sss_iobuf_write_len(state->op_ctx->reply, -+ sss_iobuf_get_data(cred_blob), -+ sss_iobuf_get_size(cred_blob)); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot write ccache blob [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+/* (name, flags, credtag) -> () */ -+/* FIXME */ -+static struct tevent_req * -+kcm_op_remove_cred_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct kcm_op_common_state *state = NULL; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ -+ state->op_ret = ERR_KCM_OP_NOT_IMPLEMENTED; -+ tevent_req_post(req, ev); -+ tevent_req_done(req); -+ return req; -+} -+ -+/* () -> (uuid, ...) */ -+static void kcm_op_get_cache_uuid_list_done(struct tevent_req *subreq); -+ -+static struct tevent_req * -+kcm_op_get_cache_uuid_list_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_common_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "Returning full UUID list\n"); -+ -+ subreq = kcm_ccdb_list_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_get_cache_uuid_list_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_get_cache_uuid_list_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ errno_t ret; -+ uuid_t *uuid_list; -+ -+ ret = kcm_ccdb_list_recv(subreq, state, &uuid_list); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot list the ccache DB [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (uuid_list == NULL || uuid_list[0] == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "Nothing to list\n"); -+ state->op_ret = ERR_NO_MATCHING_CREDS; -+ tevent_req_done(req); -+ return; -+ } -+ -+ for (int i = 0; -+ uuid_is_null(uuid_list[i]) == false; -+ i++) { -+ kcm_debug_uuid(uuid_list[i]); -+ -+ ret = sss_iobuf_write_len(state->op_ctx->reply, -+ uuid_list[i], -+ UUID_BYTES); -+ if (ret != EOK) { -+ char uuid_errbuf[UUID_STR_SIZE]; -+ uuid_parse(uuid_errbuf, uuid_list[i]); -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Cannot marshall UUID %s [%d]: %s\n", -+ uuid_errbuf, ret, sss_strerror(ret)); -+ tevent_req_done(req); -+ return; -+ } -+ } -+ -+ tevent_req_done(req); -+} -+ -+/* (uuid) -> (name) */ -+static void kcm_op_get_cache_by_uuid_done(struct tevent_req *subreq); -+ -+static struct tevent_req * -+kcm_op_get_cache_by_uuid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_common_state *state = NULL; -+ errno_t ret; -+ uuid_t uuid_in; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "Retrieving cache by UUID\n"); -+ -+ ret = sss_iobuf_read_len(op_ctx->input, -+ UUID_BYTES, uuid_in); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot read input UUID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ kcm_debug_uuid(uuid_in); -+ -+ subreq = kcm_ccdb_getbyuuid_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client, -+ uuid_in); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_get_cache_by_uuid_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_get_cache_by_uuid_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct kcm_ccache *cc; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ const char *name; -+ -+ ret = kcm_ccdb_getbyuuid_recv(subreq, state, &cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get ccahe by UUID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (cc == NULL) { -+ state->op_ret = ERR_KCM_CC_END; -+ tevent_req_done(req); -+ return; -+ } -+ -+ name = kcm_cc_get_name(cc); -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Found %s by UUID\n", name); -+ -+ ret = sss_iobuf_write_stringz(state->op_ctx->reply, -+ name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot write output name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+/* () -> (name) */ -+struct kcm_op_get_default_ccache_state { -+ uint32_t op_ret; -+ struct kcm_op_ctx *op_ctx; -+ struct tevent_context *ev; -+ -+ const char *name; -+}; -+ -+static void kcm_op_get_get_default_done(struct tevent_req *subreq); -+static void kcm_op_get_default_ccache_byuuid_done(struct tevent_req *subreq); -+static void kcm_op_get_default_ccache_list_done(struct tevent_req *subreq); -+static errno_t -+kcm_op_get_default_ccache_reply_step(struct kcm_op_get_default_ccache_state *state); -+ -+static struct tevent_req * -+kcm_op_get_default_ccache_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_get_default_ccache_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, -+ struct kcm_op_get_default_ccache_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ state->ev = ev; -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "Getting client's default ccache\n"); -+ -+ subreq = kcm_ccdb_get_default_send(state, ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_get_get_default_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_get_get_default_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ struct kcm_op_get_default_ccache_state *state = tevent_req_data(req, -+ struct kcm_op_get_default_ccache_state); -+ errno_t ret; -+ uuid_t dfl_uuid; -+ -+ ret = kcm_ccdb_get_default_recv(subreq, &dfl_uuid); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get default ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (uuid_is_null(dfl_uuid) == true) { -+ /* No cache marked as default -- get an existing ccache for ID -+ * and treat the default as simply the first one -+ */ -+ subreq = kcm_ccdb_list_send(state, state->ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_op_get_default_ccache_list_done, req); -+ return; -+ } -+ -+ /* Existing default */ -+ subreq = kcm_ccdb_name_by_uuid_send(state, -+ state->ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client, -+ dfl_uuid); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_op_get_default_ccache_byuuid_done, req); -+ return; -+} -+ -+static void kcm_op_get_default_ccache_byuuid_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ struct kcm_op_get_default_ccache_state *state = tevent_req_data(req, -+ struct kcm_op_get_default_ccache_state); -+ errno_t ret; -+ -+ ret = kcm_ccdb_name_by_uuid_recv(subreq, state, &state->name); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get ccahe by UUID [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ ret = kcm_op_get_default_ccache_reply_step(state); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+static void kcm_op_get_default_ccache_list_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ struct kcm_op_get_default_ccache_state *state = tevent_req_data(req, -+ struct kcm_op_get_default_ccache_state); -+ errno_t ret; -+ uuid_t *uuid_list; -+ -+ ret = kcm_ccdb_list_recv(subreq, state, &uuid_list); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot list ccaches [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (uuid_list == NULL || uuid_is_null(uuid_list[0])) { -+ /* No cache at all, just send back a reply */ -+ ret = kcm_op_get_default_ccache_reply_step(state); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+ return; -+ } -+ -+ /* Otherwise resolve the first cache and use it as a default */ -+ subreq = kcm_ccdb_name_by_uuid_send(state, -+ state->ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client, -+ uuid_list[0]); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_op_get_default_ccache_byuuid_done, req); -+ return; -+} -+ -+static errno_t -+kcm_op_get_default_ccache_reply_step(struct kcm_op_get_default_ccache_state *state) -+{ -+ errno_t ret; -+ -+ if (state->name == NULL) { -+ state->name = talloc_asprintf(state, -+ "%"SPRIuid, -+ cli_creds_get_uid(state->op_ctx->client)); -+ if (state->name == NULL) { -+ return ENOMEM; -+ } -+ } -+ DEBUG(SSSDBG_TRACE_INTERNAL, "The default ccache is %s\n", state->name); -+ -+ ret = sss_iobuf_write_stringz(state->op_ctx->reply, state->name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot write output name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return ret; -+ } -+ -+ return EOK; -+} -+ -+static errno_t kcm_op_get_default_ccache_recv(struct tevent_req *req, -+ uint32_t *_op_ret) -+{ -+ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_get_default_ccache_state, _op_ret); -+} -+ -+/* (name) -> () */ -+static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq); -+static void kcm_op_set_default_done(struct tevent_req *subreq); -+ -+static struct tevent_req * -+kcm_op_set_default_ccache_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_common_state *state = NULL; -+ errno_t ret; -+ const char *name; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ state->ev = ev; -+ -+ ret = sss_iobuf_read_stringz(op_ctx->input, &name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot read input name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ DEBUG(SSSDBG_TRACE_LIBS, "Setting default ccache %s\n", name); -+ -+ subreq = kcm_ccdb_uuid_by_name_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client, -+ name); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_set_default_ccache_getbyname_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ uuid_t dfl_uuid; -+ -+ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, dfl_uuid); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get ccache by name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ subreq = kcm_ccdb_set_default_send(state, -+ state->ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client, -+ dfl_uuid); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_op_set_default_done, req); -+ return; -+} -+ -+static void kcm_op_set_default_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ -+ ret = kcm_ccdb_set_default_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot set default ccache %d: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+/* (name) -> (offset) */ -+static void kcm_op_get_kdc_offset_getbyname_done(struct tevent_req *subreq); -+ -+static struct tevent_req * -+kcm_op_get_kdc_offset_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_common_state *state = NULL; -+ errno_t ret; -+ const char *name; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ -+ ret = sss_iobuf_read_stringz(op_ctx->input, &name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot read input name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ DEBUG(SSSDBG_TRACE_LIBS, "Requested offset for principal %s\n", name); -+ -+ subreq = kcm_ccdb_getbyname_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client, -+ name); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_get_kdc_offset_getbyname_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_get_kdc_offset_getbyname_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct kcm_ccache *cc; -+ int32_t offset; -+ int32_t offset_be; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_common_state *state = tevent_req_data(req, -+ struct kcm_op_common_state); -+ -+ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get matching ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (cc == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "No matching credentials\n"); -+ state->op_ret = ERR_NO_MATCHING_CREDS; -+ tevent_req_done(req); -+ return; -+ } -+ -+ offset = kcm_cc_get_offset(cc); -+ DEBUG(SSSDBG_TRACE_LIBS, "KDC offset: %"PRIu32"\n", offset); -+ -+ offset_be = htobe32(offset); -+ ret = sss_iobuf_write_int32(state->op_ctx->reply, offset_be); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot write KDC offset [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+/* (name, offset) -> () */ -+/* () -> (name) */ -+struct kcm_op_set_kdc_offset_state { -+ uint32_t op_ret; -+ struct kcm_op_ctx *op_ctx; -+ struct tevent_context *ev; -+}; -+ -+static void kcm_op_set_kdc_offset_getbyname_done(struct tevent_req *subreq); -+static void kcm_op_set_kdc_offset_mod_done(struct tevent_req *subreq); -+ -+static struct tevent_req * -+kcm_op_set_kdc_offset_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_op_ctx *op_ctx) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct kcm_op_set_kdc_offset_state *state = NULL; -+ errno_t ret; -+ const char *name; -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_set_kdc_offset_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->op_ctx = op_ctx; -+ state->ev = ev; -+ -+ ret = sss_iobuf_read_stringz(op_ctx->input, &name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot read input name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ DEBUG(SSSDBG_TRACE_LIBS, "Setting offset for principal %s\n", name); -+ -+ subreq = kcm_ccdb_uuid_by_name_send(state, ev, -+ op_ctx->kcm_data->db, -+ op_ctx->client, -+ name); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, kcm_op_set_kdc_offset_getbyname_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_op_set_kdc_offset_getbyname_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct kcm_mod_ctx *mod_ctx; -+ int32_t offset_be; -+ uuid_t uuid; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_set_kdc_offset_state *state = tevent_req_data(req, -+ struct kcm_op_set_kdc_offset_state); -+ -+ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, uuid); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get matching ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ ret = sss_iobuf_read_int32(state->op_ctx->input, &offset_be); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot read KDC offset [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ mod_ctx = talloc(state, struct kcm_mod_ctx); -+ if (mod_ctx == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ -+ kcm_mod_ctx_clear(mod_ctx); -+ mod_ctx->kdc_offset = be32toh(offset_be); -+ -+ subreq = kcm_ccdb_mod_cc_send(state, -+ state->ev, -+ state->op_ctx->kcm_data->db, -+ state->op_ctx->client, -+ uuid, -+ mod_ctx); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, kcm_op_set_kdc_offset_mod_done, req); -+} -+ -+static void kcm_op_set_kdc_offset_mod_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct kcm_op_set_kdc_offset_state *state = tevent_req_data(req, -+ struct kcm_op_set_kdc_offset_state); -+ -+ ret = kcm_ccdb_mod_cc_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot modify ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ state->op_ret = EOK; -+ tevent_req_done(req); -+} -+ -+static errno_t kcm_op_set_kdc_offset_recv(struct tevent_req *req, -+ uint32_t *_op_ret) -+{ -+ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_set_kdc_offset_state, _op_ret); -+} -+ -+static struct kcm_op kcm_optable[] = { -+ { "NOOP", NULL, NULL }, -+ { "GET_NAME", NULL, NULL }, -+ { "RESOLVE", NULL, NULL }, -+ { "GEN_NEW", kcm_op_gen_new_send, NULL }, -+ { "INITIALIZE", kcm_op_initialize_send, kcm_op_initialize_recv }, -+ { "DESTROY", kcm_op_destroy_send, NULL }, -+ { "STORE", kcm_op_store_send, kcm_op_store_recv }, -+ { "RETRIEVE", NULL, NULL }, -+ { "GET_PRINCIPAL", kcm_op_get_principal_send, NULL }, -+ { "GET_CRED_UUID_LIST", kcm_op_get_cred_uuid_list_send, NULL }, -+ { "GET_CRED_BY_UUID", kcm_op_get_cred_by_uuid_send, NULL }, -+ { "REMOVE_CRED", kcm_op_remove_cred_send, NULL }, -+ { "SET_FLAGS", NULL, NULL }, -+ { "CHOWN", NULL, NULL }, -+ { "CHMOD", NULL, NULL }, -+ { "GET_INITIAL_TICKET", NULL, NULL }, -+ { "GET_TICKET", NULL, NULL }, -+ { "MOVE_CACHE", NULL, NULL }, -+ { "GET_CACHE_UUID_LIST", kcm_op_get_cache_uuid_list_send, NULL }, -+ { "GET_CACHE_BY_UUID", kcm_op_get_cache_by_uuid_send, NULL }, -+ { "GET_DEFAULT_CACHE", kcm_op_get_default_ccache_send, kcm_op_get_default_ccache_recv }, -+ { "SET_DEFAULT_CACHE", kcm_op_set_default_ccache_send, NULL }, -+ { "GET_KDC_OFFSET", kcm_op_get_kdc_offset_send, NULL }, -+ { "SET_KDC_OFFSET", kcm_op_set_kdc_offset_send, kcm_op_set_kdc_offset_recv }, -+ { "ADD_NTLM_CRED", NULL, NULL }, -+ { "HAVE_NTLM_CRED", NULL, NULL }, -+ { "DEL_NTLM_CRED", NULL, NULL }, -+ { "DO_NTLM_AUTH", NULL, NULL }, -+ { "GET_NTLM_USER_LIST", NULL, NULL }, -+ -+ { NULL, NULL, NULL } -+}; -+ -+struct kcm_op *kcm_get_opt(uint16_t opcode) -+{ -+ struct kcm_op *op; -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, -+ "The client requested operation %"PRIu16"\n", opcode); -+ -+ if (opcode >= KCM_OP_SENTINEL) { -+ return NULL; -+ } -+ -+ op = &kcm_optable[opcode]; -+ if (op->fn_recv == NULL) { -+ op->fn_recv = kcm_op_common_recv; -+ } -+ return op; -+} -+ -+const char *kcm_opt_name(struct kcm_op *op) -+{ -+ if (op == NULL || op->name == NULL) { -+ return "Unknown operation"; -+ } -+ -+ return op->name; -+} -diff --git a/src/responder/kcm/kcmsrv_ops.h b/src/responder/kcm/kcmsrv_ops.h -new file mode 100644 -index 0000000000000000000000000000000000000000..8e6feaf56a10b73c8b6375aea9ef26c392b5b492 ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_ops.h -@@ -0,0 +1,45 @@ -+/* -+ SSSD -+ -+ KCM Server - private header file -+ -+ Copyright (C) Red Hat, 2016 -+ -+ 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 . -+*/ -+ -+#ifndef __KCMSRV_OPS_H__ -+#define __KCMSRV_OPS_H__ -+ -+#include "config.h" -+ -+#include -+#include "util/sss_iobuf.h" -+#include "responder/kcm/kcmsrv_pvt.h" -+ -+struct kcm_op; -+struct kcm_op *kcm_get_opt(uint16_t opcode); -+const char *kcm_opt_name(struct kcm_op *op); -+ -+struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_resp_ctx *kcm_data, -+ struct cli_creds *client, -+ struct kcm_data *input, -+ struct kcm_op *op); -+errno_t kcm_cmd_recv(TALLOC_CTX *mem_ctx, -+ struct tevent_req *req, -+ struct sss_iobuf **_reply); -+ -+#endif /* __KCMSRV_OPS_H__ */ --- -2.9.3 - diff --git a/SOURCES/0027-MAN-Add-a-manual-page-for-sssd-kcm.patch b/SOURCES/0027-MAN-Add-a-manual-page-for-sssd-kcm.patch deleted file mode 100644 index 39a1629..0000000 --- a/SOURCES/0027-MAN-Add-a-manual-page-for-sssd-kcm.patch +++ /dev/null @@ -1,278 +0,0 @@ -From 14d42e26c2050c1941874e83761fae69585ddc27 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 8 Mar 2017 17:46:09 +0100 -Subject: [PATCH 27/36] MAN: Add a manual page for sssd-kcm -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - contrib/sssd.spec.in | 1 + - src/man/Makefile.am | 9 ++- - src/man/po/po4a.cfg | 1 + - src/man/sssd-kcm.8.xml | 193 +++++++++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 203 insertions(+), 1 deletion(-) - create mode 100644 src/man/sssd-kcm.8.xml - -diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in -index 52d33b4de281dc1d91a9027ac1c8c878e66fb396..1d4d020415ee28292bb4d88c78de205465d812f1 100644 ---- a/contrib/sssd.spec.in -+++ b/contrib/sssd.spec.in -@@ -1206,6 +1206,7 @@ done - %config(noreplace) %{_sysconfdir}/krb5.conf.d/kcm_default_ccache - %{_unitdir}/sssd-kcm.socket - %{_unitdir}/sssd-kcm.service -+%{_mandir}/man8/sssd-kcm.8* - %endif - - %pre common -diff --git a/src/man/Makefile.am b/src/man/Makefile.am -index 142d6e2743f814294e3d92c8342070b8230bb3e5..3a063614f085691652db32d76315375466e0d3de 100644 ---- a/src/man/Makefile.am -+++ b/src/man/Makefile.am -@@ -27,6 +27,9 @@ endif - if BUILD_SECRETS - SEC_CONDS = ;with_secrets - endif -+if BUILD_SECRETS -+KCM_CONDS = ;with_kcm -+endif - if GPO_DEFAULT_ENFORCING - GPO_CONDS = ;gpo_default_enforcing - else -@@ -40,7 +43,7 @@ FILES_CONDS = ;enable_files_domain - else - FILES_CONDS = ;no_enable_files_domain - endif --CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SEC_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS) -+CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SEC_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS)$(KCM_CONDS) - - - #Special Rules: -@@ -85,6 +88,10 @@ if BUILD_SECRETS - man_MANS += sssd-secrets.5 - endif - -+if BUILD_KCM -+man_MANS += sssd-kcm.8 -+endif -+ - if BUILD_NFS_IDMAP - man_MANS += sss_rpcidmapd.5 - endif -diff --git a/src/man/po/po4a.cfg b/src/man/po/po4a.cfg -index d1f6ac39f841c61ae3d2393fb3402dc21b9cbd69..a02f97e777fa76615e4d5cbcfc788956706d8cd0 100644 ---- a/src/man/po/po4a.cfg -+++ b/src/man/po/po4a.cfg -@@ -31,6 +31,7 @@ - [type:docbook] sssctl.8.xml $lang:$(builddir)/$lang/sssctl.8.xml - [type:docbook] sssd-files.5.xml $lang:$(builddir)/$lang/sssd-files.5.xml - [type:docbook] sssd-secrets.5.xml $lang:$(builddir)/$lang/sssd-secrets.5.xml -+[type:docbook] sssd-kcm.8.xml $lang:$(builddir)/$lang/sssd-kcm.8.xml - [type:docbook] include/service_discovery.xml $lang:$(builddir)/$lang/include/service_discovery.xml opt:"-k 0" - [type:docbook] include/upstream.xml $lang:$(builddir)/$lang/include/upstream.xml opt:"-k 0" - [type:docbook] include/failover.xml $lang:$(builddir)/$lang/include/failover.xml opt:"-k 0" -diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml -new file mode 100644 -index 0000000000000000000000000000000000000000..5dc93838e48723bdb470c0a9c8575bd17c7593e8 ---- /dev/null -+++ b/src/man/sssd-kcm.8.xml -@@ -0,0 +1,193 @@ -+ -+ -+ -+SSSD Manual pages -+ -+ -+ -+ -+ sssd-kcm -+ 8 -+ File Formats and Conventions -+ -+ -+ -+ sssd-kcm -+ SSSD Kerberos Cache Manager -+ -+ -+ -+ DESCRIPTION -+ -+ This manual page describes the configuration of the SSSD Kerberos -+ Cache Manager (KCM). KCM is a process that stores, tracks and -+ manages Kerberos credential caches. It originates in the Heimdal -+ Kerberos project, although the MIT Kerberos library also provides -+ client side (more details on that below) support for the KCM -+ credential cache. -+ -+ -+ In a setup where Kerberos caches are managed by KCM, the -+ Kerberos library (typically used through an application, like -+ e.g., -+ -+ kinit1 -+ , -+ is a "KCM client" and the KCM daemon -+ is being referred to as a "KCM server". The client -+ and server communicate over a UNIX socket. -+ -+ -+ The KCM server keeps track of each credential caches's owner and -+ performs access check control based on the UID and GID of the -+ KCM client. The root user has access to all credential caches. -+ -+ -+ The KCM credential cache has several interesting properties: -+ -+ -+ -+ since the process runs in userspace, it is subject to UID namespacing, ulike the kernel keyring -+ -+ -+ -+ -+ unlike the kernel keyring-based cache, which is shared between all containers, the KCM server is a separate process whose entry point is a UNIX socket -+ -+ -+ -+ -+ the SSSD implementation stores the ccaches in the SSSD -+ -+ sssd-secrets5 -+ -+ secrets store, allowing the ccaches to survive KCM server restarts or machine reboots. -+ -+ -+ -+ This allows the system to use a collection-aware credential -+ cache, yet share the credential cache between some or no -+ containers by bind-mounting the socket. -+ -+ -+ -+ -+ USING THE KCM CREDENTIAL CACHE -+ -+ In order to use KCM credential cache, it must be selected as the default -+ credential type in -+ -+ krb5.conf5 -+ , -+ The credentials cache name must be only KCM: -+ without any template expansions. For example: -+ -+[libdefaults] -+ default_ccache_name = KCM: -+ -+ -+ -+ Next, make sure the Kerberos client libraries and the KCM server must agree -+ on the UNIX socket path. By default, both use the same path -+ /var/run/.heim_org.h5l.kcm-socket. To configure -+ the Kerberos library, change its kcm_socket option which -+ is described in the -+ -+ krb5.conf5 -+ -+ manual page. -+ -+ -+ Finally, make sure the SSSD KCM server can be contacted. -+ The KCM service is typically socket-activated by -+ -+ systemd -+ 1 -+ . -+ Unlike -+ other SSSD services, it cannot be started by adding the -+ kcm string to the service -+ directive. -+ -+systemctl start sssd-kcm.socket -+systemctl enable sssd-kcm.socket -+systemctl enable sssd-kcm.service -+ -+ Please note your distribution may already configure the units -+ for you. -+ -+ -+ -+ -+ THE CREDENTIAL CACHE STORAGE -+ -+ The credential caches are stored in the SSSD secrets service (see -+ -+ sssd-secrets5 -+ -+ for more details). Therefore it is important that also the sssd-secrets -+ service is enabled and its socket is started: -+ -+systemctl start sssd-secrets.socket -+systemctl enable sssd-secrets.socket -+systemctl enable sssd-secrets.service -+ -+ Your distribution should already set the dependencies between the services. -+ -+ -+ -+ -+ CONFIGURATION OPTIONS -+ -+ The KCM service is configured in the kcm -+ section of the sssd.conf file. Please note that currently, -+ is it not sufficient to restart the sssd-kcm service, because -+ the sssd configuration is only parsed and read to an internal -+ configuration database by the sssd service. Therefore you -+ must restart the sssd service if you change anything in the -+ kcm section of sssd.conf. -+ For a detailed syntax reference, refer to the FILE FORMAT section of the -+ -+ sssd.conf -+ 5 -+ manual page. -+ -+ -+ The generic SSSD service options such as -+ debug_level or fd_limit are -+ accepted by the kcm service. Please refer to the -+ -+ sssd.conf -+ 5 -+ manual page for a complete list. In addition, -+ there are some KCM-specific options as well. -+ -+ -+ -+ socket_path (string) -+ -+ -+ The socket the KCM service will listen on. -+ -+ -+ Default: /var/run/.heim_org.h5l.kcm-socket -+ -+ -+ -+ -+ -+ -+ -+ SEE ALSO -+ -+ -+ sssd8 -+ , -+ -+ sssd.conf5 -+ , -+ -+ -+ -+ --- -2.9.3 - diff --git a/SOURCES/0027-nss-make-memcache_delete_entry-public.patch b/SOURCES/0027-nss-make-memcache_delete_entry-public.patch new file mode 100644 index 0000000..6d0c026 --- /dev/null +++ b/SOURCES/0027-nss-make-memcache_delete_entry-public.patch @@ -0,0 +1,49 @@ +From fd798bd98d932bc847afc60817f5fdb744eee2a4 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 24 Oct 2017 12:50:43 +0200 +Subject: [PATCH 27/31] nss: make memcache_delete_entry() public + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit a7d6ca275d6b2e5d396cbefb18d0ee880011e271) +--- + src/responder/nss/nss_get_object.c | 2 +- + src/responder/nss/nss_private.h | 8 ++++++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/responder/nss/nss_get_object.c b/src/responder/nss/nss_get_object.c +index e56480af5e3369963d2e8bb17d74d1603af8e014..15faced006f754134415e766284377f0c86af0ac 100644 +--- a/src/responder/nss/nss_get_object.c ++++ b/src/responder/nss/nss_get_object.c +@@ -86,7 +86,7 @@ memcache_delete_entry_by_id(struct nss_ctx *nss_ctx, + return ret; + } + +-static errno_t ++errno_t + memcache_delete_entry(struct nss_ctx *nss_ctx, + struct resp_ctx *rctx, + struct sss_domain_info *domain, +diff --git a/src/responder/nss/nss_private.h b/src/responder/nss/nss_private.h +index a0b573d6ecba2d8ba6f55db0adcd7ee29cbec991..5fc19d26be9adda4d967086e7b239e49a78866ee 100644 +--- a/src/responder/nss/nss_private.h ++++ b/src/responder/nss/nss_private.h +@@ -92,6 +92,14 @@ struct sss_cmd_table *get_nss_cmds(void); + + int nss_connection_setup(struct cli_ctx *cli_ctx); + ++errno_t ++memcache_delete_entry(struct nss_ctx *nss_ctx, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ const char *name, ++ uint32_t id, ++ enum sss_mc_type type); ++ + struct tevent_req * + nss_get_object_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +-- +2.13.6 + diff --git a/SOURCES/0028-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch b/SOURCES/0028-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch new file mode 100644 index 0000000..04cc5a0 --- /dev/null +++ b/SOURCES/0028-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch @@ -0,0 +1,365 @@ +From fe54de0824cac1822d6f9485165adc64bf4e0fa7 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 24 Oct 2017 14:10:53 +0200 +Subject: [PATCH 28/31] NSS: add support for SSS_NSS_EX_FLAG_INVALIDATE_CACHE + +The patch adds support for the SSS_NSS_EX_FLAG_INVALIDATE_CACHE flag and +makes the existing code more flexible and handle additional flags. + +If SSS_NSS_EX_FLAG_INVALIDATE_CACHE is set the requested object is only +looked up in the cache and if it was found on-disk and memory cache +entries will be invalidated. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 55f7d8034d783c01789d76a2b9ffc901045e8af8) +--- + src/responder/nss/nss_cmd.c | 141 +++++++++++++++++++++++++++++++-- + src/responder/nss/nss_protocol.c | 1 + + src/responder/nss/nss_protocol.h | 1 + + src/responder/nss/nss_protocol_grent.c | 9 ++- + src/responder/nss/nss_protocol_pwent.c | 6 +- + src/sss_client/idmap/sss_nss_ex.c | 20 ++++- + src/sss_client/idmap/sss_nss_idmap.h | 8 +- + 7 files changed, 171 insertions(+), 15 deletions(-) + +diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c +index c5ddd2f2cc2122cd169ea991b94a14eb5bad095f..545257a0be7e91e9de767a57848bb77c5791db4e 100644 +--- a/src/responder/nss/nss_cmd.c ++++ b/src/responder/nss/nss_cmd.c +@@ -50,6 +50,26 @@ nss_cmd_ctx_create(TALLOC_CTX *mem_ctx, + return cmd_ctx; + } + ++static errno_t eval_flags(struct nss_cmd_ctx *cmd_ctx, ++ struct cache_req_data *data) ++{ ++ if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 ++ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Flags SSS_NSS_EX_FLAG_NO_CACHE and " ++ "SSS_NSS_EX_FLAG_INVALIDATE_CACHE are " ++ "mutually exclusive.\n"); ++ return EINVAL; ++ } ++ ++ if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { ++ cache_req_data_set_bypass_cache(data, true); ++ } else if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ cache_req_data_set_bypass_dp(data, true); ++ } ++ ++ return EOK; ++} ++ + static void nss_getby_done(struct tevent_req *subreq); + static void nss_getlistby_done(struct tevent_req *subreq); + +@@ -65,7 +85,6 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + struct tevent_req *subreq; + const char *rawname; + errno_t ret; +- uint32_t flags = 0; + + cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn); + if (cmd_ctx == NULL) { +@@ -73,8 +92,9 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + goto done; + } + ++ cmd_ctx->flags = 0; + if (ex_version) { +- ret = nss_protocol_parse_name_ex(cli_ctx, &rawname, &flags); ++ ret = nss_protocol_parse_name_ex(cli_ctx, &rawname, &cmd_ctx->flags); + } else { + ret = nss_protocol_parse_name(cli_ctx, &rawname); + } +@@ -92,8 +112,10 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + goto done; + } + +- if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { +- cache_req_data_set_bypass_cache(data, true); ++ ret = eval_flags(cmd_ctx, data); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "eval_flags failed.\n"); ++ goto done; + } + + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, +@@ -129,7 +151,6 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + struct tevent_req *subreq; + uint32_t id; + errno_t ret; +- uint32_t flags = 0; + + cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn); + if (cmd_ctx == NULL) { +@@ -138,7 +159,7 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + } + + if (ex_version) { +- ret = nss_protocol_parse_id_ex(cli_ctx, &id, &flags); ++ ret = nss_protocol_parse_id_ex(cli_ctx, &id, &cmd_ctx->flags); + } else { + ret = nss_protocol_parse_id(cli_ctx, &id); + } +@@ -156,8 +177,10 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + goto done; + } + +- if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { +- cache_req_data_set_bypass_cache(data, true); ++ ret = eval_flags(cmd_ctx, data); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "eval_flags failed.\n"); ++ goto done; + } + + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, +@@ -425,6 +448,98 @@ done: + return EOK; + } + ++static errno_t invalidate_cache(struct nss_cmd_ctx *cmd_ctx, ++ struct cache_req_result *result) ++{ ++ int ret; ++ enum sss_mc_type memcache_type; ++ const char *name; ++ char *output_name = NULL; ++ bool is_user; ++ struct sysdb_attrs *attrs = NULL; ++ ++ switch (cmd_ctx->type) { ++ case CACHE_REQ_INITGROUPS: ++ case CACHE_REQ_INITGROUPS_BY_UPN: ++ memcache_type = SSS_MC_INITGROUPS; ++ is_user = true; ++ break; ++ case CACHE_REQ_USER_BY_NAME: ++ case CACHE_REQ_USER_BY_ID: ++ memcache_type = SSS_MC_PASSWD; ++ is_user = true; ++ break; ++ case CACHE_REQ_GROUP_BY_NAME: ++ case CACHE_REQ_GROUP_BY_ID: ++ memcache_type = SSS_MC_GROUP; ++ is_user = false; ++ break; ++ default: ++ /* nothing to do */ ++ return EOK; ++ } ++ ++ /* Find output name to invalidate memory cache entry*/ ++ name = sss_get_name_from_msg(result->domain, result->msgs[0]); ++ if (name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Found object has no name.\n"); ++ return EINVAL; ++ } ++ ret = sss_output_fqname(cmd_ctx, result->domain, name, ++ cmd_ctx->nss_ctx->rctx->override_space, ++ &output_name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_output_fqname failed.\n"); ++ return ret; ++ } ++ ++ memcache_delete_entry(cmd_ctx->nss_ctx, cmd_ctx->nss_ctx->rctx, NULL, ++ output_name, 0, memcache_type); ++ if (memcache_type == SSS_MC_INITGROUPS) { ++ /* Invalidate the passwd data as well */ ++ memcache_delete_entry(cmd_ctx->nss_ctx, cmd_ctx->nss_ctx->rctx, ++ result->domain, output_name, 0, SSS_MC_PASSWD); ++ } ++ talloc_free(output_name); ++ ++ /* Use sysdb name to invalidate disk cache entry */ ++ name = ldb_msg_find_attr_as_string(result->msgs[0], SYSDB_NAME, NULL); ++ if (name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Found object has no name.\n"); ++ return EINVAL; ++ } ++ ++ if (memcache_type == SSS_MC_INITGROUPS) { ++ attrs = sysdb_new_attrs(cmd_ctx); ++ if (attrs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); ++ return ENOMEM; ++ } ++ ++ ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, 1); ++ if (ret != EOK) { ++ talloc_free(attrs); ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_time_t failed.\n"); ++ return ret; ++ } ++ ++ ret = sysdb_set_user_attr(result->domain, name, attrs, SYSDB_MOD_REP); ++ talloc_free(attrs); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_user_attr failed.\n"); ++ return ret; ++ } ++ } ++ ++ ret = sysdb_invalidate_cache_entry(result->domain, name, is_user); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_invalidate_cache_entry failed.\n"); ++ return ret; ++ } ++ ++ return EOK; ++} ++ + static void nss_getby_done(struct tevent_req *subreq) + { + struct cache_req_result *result; +@@ -440,6 +555,16 @@ static void nss_getby_done(struct tevent_req *subreq) + goto done; + } + ++ if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ ret = invalidate_cache(cmd_ctx, result); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to invalidate cache for [%s].\n", ++ cmd_ctx->rawname); ++ nss_protocol_done(cmd_ctx->cli_ctx, ret); ++ goto done; ++ } ++ } ++ + nss_protocol_reply(cmd_ctx->cli_ctx, cmd_ctx->nss_ctx, cmd_ctx, + result, cmd_ctx->fill_fn); + +diff --git a/src/responder/nss/nss_protocol.c b/src/responder/nss/nss_protocol.c +index 17bfc4f4e71960a72e9e04622eac95b94a865ec7..2655386498754c46fbb363bdd1f976f9ded6a434 100644 +--- a/src/responder/nss/nss_protocol.c ++++ b/src/responder/nss/nss_protocol.c +@@ -233,6 +233,7 @@ nss_protocol_parse_id_ex(struct cli_ctx *cli_ctx, uint32_t *_id, + SAFEALIGN_COPY_UINT32(&flags, body + sizeof(uint32_t), NULL); + + *_id = id; ++ *_flags = flags; + + return EOK; + } +diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h +index ca5b040237dc18acdca9a7a3a7a7dbb64265aa95..76724d2b2db7b11c9147fa927e39abab731328b2 100644 +--- a/src/responder/nss/nss_protocol.h ++++ b/src/responder/nss/nss_protocol.h +@@ -50,6 +50,7 @@ struct nss_cmd_ctx { + struct nss_ctx *nss_ctx; + struct nss_state_ctx *state_ctx; + nss_protocol_fill_packet_fn fill_fn; ++ uint32_t flags; + + /* For initgroups- */ + const char *rawname; +diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c +index ee228c722a153a1ba7aa8a1b30a1e551108424bb..6f6ae57dd97b000ad3cf174b0f649d46981563e2 100644 +--- a/src/responder/nss/nss_protocol_grent.c ++++ b/src/responder/nss/nss_protocol_grent.c +@@ -274,8 +274,10 @@ nss_protocol_fill_grent(struct nss_ctx *nss_ctx, + + num_results++; + +- /* Do not store entry in memory cache during enumeration. */ +- if (!cmd_ctx->enumeration) { ++ /* Do not store entry in memory cache during enumeration or when ++ * requested. */ ++ if (!cmd_ctx->enumeration ++ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) { + members = (char *)&body[rp_members]; + members_size = body_len - rp_members; + ret = sss_mmap_cache_gr_store(&nss_ctx->grp_mc_ctx, name, &pwfield, +@@ -390,7 +392,8 @@ nss_protocol_fill_initgr(struct nss_ctx *nss_ctx, + num_results++; + } + +- if (nss_ctx->initgr_mc_ctx) { ++ if (nss_ctx->initgr_mc_ctx ++ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) { + to_sized_string(&rawname, cmd_ctx->rawname); + to_sized_string(&unique_name, result->lookup_name); + +diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c +index db5c071e2ff172a2267c08c9817fecfbcc7cabc3..f449ec69b6a86a6db2aaed368e217c1a791faaa2 100644 +--- a/src/responder/nss/nss_protocol_pwent.c ++++ b/src/responder/nss/nss_protocol_pwent.c +@@ -295,8 +295,10 @@ nss_protocol_fill_pwent(struct nss_ctx *nss_ctx, + + num_results++; + +- /* Do not store entry in memory cache during enumeration. */ +- if (!cmd_ctx->enumeration) { ++ /* Do not store entry in memory cache during enumeration or when ++ * requested. */ ++ if (!cmd_ctx->enumeration ++ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) { + ret = sss_mmap_cache_pw_store(&nss_ctx->pwd_mc_ctx, name, &pwfield, + uid, gid, &gecos, &homedir, &shell); + if (ret != EOK) { +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +index edb3ea652ef7032b76c8f815b9f83fe185a669ea..148eb7b35ec236b6272dd203a0035399cfdef73d 100644 +--- a/src/sss_client/idmap/sss_nss_ex.c ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -103,6 +103,18 @@ errno_t sss_nss_mc_get(struct nss_input *inp) + } + } + ++static int check_flags(uint32_t flags) ++{ ++ /* SSS_NSS_EX_FLAG_NO_CACHE and SSS_NSS_EX_FLAG_INVALIDATE_CACHE are ++ * mutually exclusive */ ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 ++ && (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ return EINVAL; ++ } ++ ++ return 0; ++} ++ + int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + { + uint8_t *repbuf = NULL; +@@ -117,7 +129,13 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + size_t idx; + bool skip_mc = false; + +- if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { ++ ret = check_flags(flags); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 ++ || (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { + skip_mc = true; + } + +diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h +index 1649830afbb80c617fd339f054aef8bc8e585fb9..3755643312f05a31d1cf1aa76dfc22848ef1e3ec 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.h ++++ b/src/sss_client/idmap/sss_nss_idmap.h +@@ -170,9 +170,15 @@ void sss_nss_free_kv(struct sss_nss_kv *kv_list); + #define SSS_NSS_EX_FLAG_NO_FLAGS 0 + + /** Always request data from the server side, client must be privileged to do +- * so, see nss_trusted_users option in man sssd.conf for details */ ++ * so, see nss_trusted_users option in man sssd.conf for details. ++ * This flag cannot be used together with SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ + #define SSS_NSS_EX_FLAG_NO_CACHE (1 << 0) + ++/** Invalidate the data in the caches, client must be privileged to do ++ * so, see nss_trusted_users option in man sssd.conf for details. ++ * This flag cannot be used together with SSS_NSS_EX_FLAG_NO_CACHE */ ++#define SSS_NSS_EX_FLAG_INVALIDATE_CACHE (1 << 1) ++ + #ifdef IPA_389DS_PLUGIN_HELPER_CALLS + + /** +-- +2.13.6 + diff --git a/SOURCES/0028-TESTS-Add-integration-tests-for-the-KCM-responder.patch b/SOURCES/0028-TESTS-Add-integration-tests-for-the-KCM-responder.patch deleted file mode 100644 index 776bf94..0000000 --- a/SOURCES/0028-TESTS-Add-integration-tests-for-the-KCM-responder.patch +++ /dev/null @@ -1,799 +0,0 @@ -From ad820beebae89c886f1ba4f0d2ddac4ca36857b7 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 13 Dec 2016 17:17:16 +0100 -Subject: [PATCH 28/36] TESTS: Add integration tests for the KCM responder -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce -Reviewed-by: Lukáš Slebodník ---- - contrib/ci/configure.sh | 7 + - contrib/ci/deps.sh | 6 + - src/tests/intg/Makefile.am | 4 + - src/tests/intg/kdc.py | 175 +++++++++++++++++++++ - src/tests/intg/krb5utils.py | 156 +++++++++++++++++++ - src/tests/intg/test_kcm.py | 361 ++++++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 709 insertions(+) - create mode 100644 src/tests/intg/kdc.py - create mode 100644 src/tests/intg/krb5utils.py - create mode 100644 src/tests/intg/test_kcm.py - -diff --git a/contrib/ci/configure.sh b/contrib/ci/configure.sh -index 8e779cfe634a7555e0e8e3b52f42c07e62980fbc..7590743c2aa5fe31bcdf1a3e92a3f482dbec699b 100644 ---- a/contrib/ci/configure.sh -+++ b/contrib/ci/configure.sh -@@ -38,6 +38,13 @@ if [[ "$DISTRO_BRANCH" == -redhat-redhatenterprise*-6.*- || - "--disable-cifs-idmap-plugin" - "--with-syslog=syslog" - "--without-python3-bindings" -+ "--without-kcm" -+ ) -+fi -+ -+if [[ "$DISTRO_BRANCH" == -redhat-fedora-2[0-2]* ]]; then -+ CONFIGURE_ARG_LIST+=( -+ "--without-kcm" - ) - fi - -diff --git a/contrib/ci/deps.sh b/contrib/ci/deps.sh -index c525e62e8c1d5b9fa042dee4ad03790dbceba242..4467e117c3a896a7f01ef7cb9e94fe28c2ea2838 100644 ---- a/contrib/ci/deps.sh -+++ b/contrib/ci/deps.sh -@@ -47,6 +47,8 @@ if [[ "$DISTRO_BRANCH" == -redhat-* ]]; then - uid_wrapper - python-requests - curl-devel -+ krb5-server -+ krb5-workstation - ) - _DEPS_LIST_SPEC=` - sed -e 's/@PACKAGE_VERSION@/0/g' \ -@@ -122,6 +124,10 @@ if [[ "$DISTRO_BRANCH" == -debian-* ]]; then - libhttp-parser-dev - libjansson-dev - libcurl4-openssl-dev -+ krb5-kdc -+ krb5-admin-server -+ krb5-user -+ uuid-dev - ) - DEPS_INTGCHECK_SATISFIED=true - fi -diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am -index 1d36fa0d2d50307fbc871f5b2a6f0cb1cc95db81..8526beace09b15c99aa27ac98d5038d1980f6a71 100644 ---- a/src/tests/intg/Makefile.am -+++ b/src/tests/intg/Makefile.am -@@ -26,6 +26,9 @@ dist_noinst_DATA = \ - files_ops.py \ - test_files_ops.py \ - test_files_provider.py \ -+ kdc.py \ -+ krb5utils.py \ -+ test_kcm.py \ - $(NULL) - - config.py: config.py.m4 -@@ -80,5 +83,6 @@ intgcheck-installed: config.py passwd group - NSS_WRAPPER_MODULE_FN_PREFIX="sss" \ - UID_WRAPPER=1 \ - UID_WRAPPER_ROOT=1 \ -+ NON_WRAPPED_UID=$$(echo $$UID) \ - fakeroot $(PYTHON2) $(PYTEST) -v --tb=native $(INTGCHECK_PYTEST_ARGS) . - rm -f $(DESTDIR)$(logpath)/* -diff --git a/src/tests/intg/kdc.py b/src/tests/intg/kdc.py -new file mode 100644 -index 0000000000000000000000000000000000000000..dec33a979916c0979561afb22dc39d6eb8894ff3 ---- /dev/null -+++ b/src/tests/intg/kdc.py -@@ -0,0 +1,175 @@ -+# -+# MIT Kerberos server class -+# -+# Copyright (c) 2016 Red Hat, Inc. -+# -+# This 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; version 2 only -+# -+# 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 . -+# -+import os -+import signal -+import shutil -+import subprocess -+ -+from util import * -+ -+ -+class KDC(object): -+ """ -+ MIT Kerberos KDC instance -+ """ -+ -+ def __init__(self, basedir, realm, -+ includedir=None, -+ kdc_port=10088, -+ kadmin_port=10749, -+ master_key='master'): -+ self.basedir = basedir -+ self.realm = realm -+ self.kdc_port = kdc_port -+ self.kadmin_port = kadmin_port -+ self.master_key = master_key -+ -+ self.kdc_basedir = self.basedir + "/var/krb5kdc" -+ self.includedir = includedir or (self.kdc_basedir + "/include") -+ self.kdc_logdir = self.kdc_basedir + "/log" -+ self.kdc_conf_path = self.kdc_basedir + "/kdc.conf" -+ self.krb5_conf_path = self.kdc_basedir + "/krb5.conf" -+ -+ self.kdc_pid_file = self.kdc_basedir + "/kdc.pid" -+ -+ self.acl_file = self.kdc_basedir + "/kadm5.acl" -+ -+ self.admin_princ = "admin/admin@" + self.realm -+ -+ def start_kdc(self, extra_args=[]): -+ args = ["krb5kdc", '-P', self.kdc_pid_file] + extra_args -+ return self._run_in_env(args, self.get_krb5_env()) -+ -+ def stop_kdc(self): -+ try: -+ with open(self.kdc_pid_file, "r") as pid_file: -+ os.kill(int(pid_file.read()), signal.SIGTERM) -+ except IOError as ioex: -+ if ioex.errno == 2: -+ pass -+ else: -+ raise ioex -+ -+ def teardown(self): -+ self.stop_kdc() -+ shutil.rmtree(self.kdc_basedir) -+ -+ def set_up(self): -+ self._create_config() -+ self._create_acl() -+ self._create_kdb() -+ -+ def get_krb5_env(self): -+ my_env = os.environ -+ my_env['KRB5_CONFIG'] = self.krb5_conf_path -+ my_env['KRB5_KDC_PROFILE'] = self.kdc_conf_path -+ return my_env -+ -+ def add_config(self, include_files): -+ for name, contents in include_files.items(): -+ include_fpath = os.path.join(self.includedir, name) -+ with open(include_fpath, 'w') as include_file: -+ include_file.write(contents) -+ -+ def add_principal(self, princ, password=None): -+ args = ["kadmin.local", "-q"] -+ if password is None: -+ args += ["addprinc -randkey %s" % (princ)] -+ else: -+ args += ["addprinc -pw %s %s" % (password, princ)] -+ return self._run_in_env(args, self.get_krb5_env()) -+ -+ def _run_in_env(self, args, env): -+ cmd = subprocess.Popen(args, env=env) -+ out, err = cmd.communicate() -+ return cmd.returncode, out, err -+ -+ def _create_config(self): -+ try: -+ os.makedirs(self.kdc_basedir) -+ os.makedirs(self.kdc_logdir) -+ os.makedirs(self.includedir) -+ except OSError as osex: -+ if osex.errno == 17: -+ pass -+ -+ kdc_conf = self._format_kdc_conf() -+ with open(self.kdc_conf_path, 'w') as kdc_conf_file: -+ kdc_conf_file.write(kdc_conf) -+ -+ krb5_conf = self._format_krb5_conf() -+ with open(self.krb5_conf_path, 'w') as krb5_conf_file: -+ krb5_conf_file.write(krb5_conf) -+ -+ def _create_acl(self): -+ with open(self.acl_file, 'w') as acl_fobject: -+ acl_fobject.write(self.admin_princ) -+ -+ def _create_kdb(self): -+ self._run_in_env( -+ ['kdb5_util', 'create', '-W', '-s', '-P', self.master_key], -+ self.get_krb5_env() -+ ) -+ -+ def _format_kdc_conf(self): -+ database_path = self.kdc_basedir + "/principal" -+ key_stash = self.kdc_basedir + "/stash." + self.realm -+ -+ kdc_logfile = "FILE:" + self.kdc_logdir + "/krb5kdc.log" -+ kadmin_logfile = "FILE:" + self.kdc_logdir + "/kadmin.log" -+ libkrb5_logfile = "FILE:" + self.kdc_logdir + "/libkrb5.log" -+ -+ kdc_conf = unindent(""" -+ [kdcdefaults] -+ kdc_ports = {self.kdc_port} -+ kdc_tcp_ports = {self.kdc_port} -+ -+ [realms] -+ {self.realm} = {{ -+ kadmind_port = {self.kadmin_port} -+ database_name = {database_path} -+ key_stash_file = {key_stash} -+ acl_file = {self.acl_file} -+ }} -+ -+ [logging] -+ kdc = {kdc_logfile} -+ admin_server = {kadmin_logfile} -+ default = {libkrb5_logfile} -+ """).format(**locals()) -+ return kdc_conf -+ -+ def _format_krb5_conf(self): -+ kdc_uri = "localhost:%d" % self.kdc_port -+ kadmin_uri = "localhost:%d" % self.kadmin_port -+ -+ krb5_conf = unindent(""" -+ includedir {self.includedir} -+ -+ [libdefaults] -+ default_realm = {self.realm} -+ dns_lookup_kdc = false -+ dns_lookup_realm = false -+ -+ [realms] -+ {self.realm} = {{ -+ kdc = {kdc_uri} -+ admin_server = {kadmin_uri} -+ }} -+ """).format(**locals()) -+ return krb5_conf -diff --git a/src/tests/intg/krb5utils.py b/src/tests/intg/krb5utils.py -new file mode 100644 -index 0000000000000000000000000000000000000000..775cffd0bbfa011f2d8ffc1169dccfef96d78fab ---- /dev/null -+++ b/src/tests/intg/krb5utils.py -@@ -0,0 +1,156 @@ -+# -+# MIT Kerberos server class -+# -+# Copyright (c) 2016 Red Hat, Inc. -+# -+# This 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; version 2 only -+# -+# 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 . -+# -+import os -+import subprocess -+ -+ -+class NoPrincipals(Exception): -+ def __init__(self): -+ Exception.__init__(self, 'No principals in the collection') -+ -+ -+class PrincNotFound(Exception): -+ def __init__(self, principal): -+ Exception.__init__(self, 'Principal %s not found' % principal) -+ -+ -+class Krb5Utils(object): -+ """ -+ Helper class to test Kerberos command line utilities -+ """ -+ def __init__(self, krb5_conf_path): -+ self.krb5_conf_path = krb5_conf_path -+ -+ def _run_in_env(self, args, stdin=None, extra_env=None): -+ my_env = os.environ -+ my_env['KRB5_CONFIG'] = self.krb5_conf_path -+ -+ if 'KRB5CCNAME' in my_env: -+ del my_env['KRB5CCNAME'] -+ if extra_env is not None: -+ my_env.update(extra_env) -+ -+ cmd = subprocess.Popen(args, -+ env=my_env, -+ stdin=subprocess.PIPE, -+ stdout=subprocess.PIPE, -+ stderr=subprocess.PIPE) -+ out, err = cmd.communicate(stdin) -+ return cmd.returncode, out.decode('utf-8'), err.decode('utf-8') -+ -+ def kinit(self, principal, password, env=None): -+ args = ["kinit", principal] -+ return self._run_in_env(args, password.encode('utf-8'), env) -+ -+ def kvno(self, principal, env=None): -+ args = ["kvno", principal] -+ return self._run_in_env(args, env) -+ -+ def kdestroy(self, all_ccaches=False, env=None): -+ args = ["kdestroy"] -+ if all_ccaches is True: -+ args += ["-A"] -+ retval, _, _ = self._run_in_env(args, env) -+ return retval -+ -+ def kswitch(self, principal, env=None): -+ args = ["kswitch", '-p', principal] -+ retval, _, _ = self._run_in_env(args, env) -+ return retval -+ -+ def _check_klist_l(self, line, exp_principal, exp_cache): -+ try: -+ princ, cache = line.split() -+ except ValueError: -+ return False -+ -+ if exp_cache is not None and cache != exp_cache: -+ return False -+ -+ if exp_principal != princ: -+ return False -+ -+ return True -+ -+ def num_princs(self, env=None): -+ args = ["klist", "-l"] -+ retval, out, err = self._run_in_env(args, extra_env=env) -+ if retval != 0: -+ return 0 -+ -+ outlines = [l for l in out.split('\n') if len(l) > 1] -+ return len(outlines) - 2 -+ -+ def list_princs(self, env=None): -+ args = ["klist", "-l"] -+ retval, out, err = self._run_in_env(args, extra_env=env) -+ if retval == 1: -+ raise NoPrincipals -+ elif retval != 0: -+ raise Exception("klist failed: %d: %s\n", retval, err) -+ -+ outlines = out.split('\n') -+ if len(outlines) < 2: -+ raise Exception("Not enough output from klist -l") -+ -+ return [l for l in outlines[2:] if len(l) > 0] -+ -+ def has_principal(self, exp_principal, exp_cache=None, env=None): -+ try: -+ princlist = self.list_princs(env) -+ except NoPrincipals: -+ return False -+ -+ for line in princlist: -+ matches = self._check_klist_l(line, exp_principal, exp_cache) -+ if matches is True: -+ return True -+ -+ return False -+ -+ def default_principal(self, env=None): -+ principals = self.list_princs(env) -+ return principals[0].split()[0] -+ -+ def _parse_klist_a(self, out): -+ dflprinc = None -+ thisrealm = None -+ ccache_dict = dict() -+ -+ for line in [l for l in out.split('\n') if len(l) > 0]: -+ if line.startswith("Default principal"): -+ dflprinc = line.split()[2] -+ thisrealm = '@' + dflprinc.split('@')[1] -+ elif thisrealm is not None and line.endswith(thisrealm): -+ svc = line.split()[-1] -+ if dflprinc in ccache_dict: -+ ccache_dict[dflprinc].append(svc) -+ else: -+ ccache_dict[dflprinc] = [svc] -+ -+ return ccache_dict -+ -+ def list_all_princs(self, env=None): -+ args = ["klist", "-A"] -+ retval, out, err = self._run_in_env(args, extra_env=env) -+ if retval == 1: -+ raise NoPrincipals -+ elif retval != 0: -+ raise Exception("klist -A failed: %d: %s\n", retval, err) -+ -+ return self._parse_klist_a(out) -diff --git a/src/tests/intg/test_kcm.py b/src/tests/intg/test_kcm.py -new file mode 100644 -index 0000000000000000000000000000000000000000..ad1e4923bfe339cb040464757431d2ef3bf57ce1 ---- /dev/null -+++ b/src/tests/intg/test_kcm.py -@@ -0,0 +1,361 @@ -+# -+# KCM responder integration tests -+# -+# Copyright (c) 2016 Red Hat, Inc. -+# -+# This 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; version 2 only -+# -+# 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 . -+# -+import os -+import os.path -+import stat -+import subprocess -+import pytest -+import socket -+import time -+import signal -+ -+import kdc -+import krb5utils -+import config -+from util import unindent, run_shell -+ -+class KcmTestEnv(object): -+ def __init__(self, k5kdc, k5util): -+ self.k5kdc = k5kdc -+ self.k5util = k5util -+ self.counter = 0 -+ -+ def my_uid(self): -+ s_myuid = os.environ['NON_WRAPPED_UID'] -+ return int(s_myuid) -+ -+ def ccname(self, my_uid=None): -+ if my_uid is None: -+ my_uid = self.my_uid() -+ -+ return "KCM:%d" % my_uid -+ -+ -+@pytest.fixture(scope="module") -+def kdc_instance(request): -+ """Kerberos server instance fixture""" -+ kdc_instance = kdc.KDC(config.PREFIX, "KCMTEST") -+ try: -+ kdc_instance.set_up() -+ kdc_instance.start_kdc() -+ except: -+ kdc_instance.teardown() -+ raise -+ request.addfinalizer(kdc_instance.teardown) -+ return kdc_instance -+ -+ -+def create_conf_fixture(request, contents): -+ """Generate sssd.conf and add teardown for removing it""" -+ with open(config.CONF_PATH, "w") as conf: -+ conf.write(contents) -+ os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR) -+ request.addfinalizer(lambda: os.unlink(config.CONF_PATH)) -+ -+ -+def create_sssd_kcm_fixture(sock_path, request): -+ if subprocess.call(['sssd', "--genconf"]) != 0: -+ raise Exception("failed to regenerate confdb") -+ -+ resp_path = os.path.join(config.LIBEXEC_PATH, "sssd", "sssd_kcm") -+ if not os.access(resp_path, os.X_OK): -+ # It would be cleaner to use pytest.mark.skipif on the package level -+ # but upstream insists on supporting RHEL-6.. -+ pytest.skip("No KCM responder, skipping") -+ -+ kcm_pid = os.fork() -+ assert kcm_pid >= 0 -+ -+ if kcm_pid == 0: -+ if subprocess.call([resp_path, "--uid=0", "--gid=0"]) != 0: -+ print("sssd_kcm failed to start") -+ sys.exit(99) -+ else: -+ abs_sock_path = os.path.join(config.RUNSTATEDIR, sock_path) -+ sck = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) -+ for _ in range(1, 10): -+ try: -+ sck.connect(abs_sock_path) -+ except: -+ time.sleep(0.1) -+ else: -+ break -+ sck.close() -+ assert os.path.exists(abs_sock_path) -+ -+ def kcm_teardown(): -+ if kcm_pid == 0: -+ return -+ os.kill(kcm_pid, signal.SIGTERM) -+ -+ request.addfinalizer(kcm_teardown) -+ return kcm_pid -+ -+ -+@pytest.fixture -+def setup_for_kcm(request, kdc_instance): -+ """ -+ Just set up the local provider for tests and enable the KCM -+ responder -+ """ -+ kcm_path = os.path.join(config.RUNSTATEDIR, "kcm.socket") -+ -+ sssd_conf = unindent("""\ -+ [sssd] -+ domains = local -+ services = nss -+ -+ [domain/local] -+ id_provider = local -+ -+ [kcm] -+ socket_path = {kcm_path} -+ """).format(**locals()) -+ -+ kcm_socket_include = unindent(""" -+ [libdefaults] -+ default_ccache_name = KCM: -+ kcm_socket = {kcm_path} -+ """).format(**locals()) -+ kdc_instance.add_config({'kcm_socket': kcm_socket_include}) -+ -+ create_conf_fixture(request, sssd_conf) -+ create_sssd_kcm_fixture(kcm_path, request) -+ -+ k5util = krb5utils.Krb5Utils(kdc_instance.krb5_conf_path) -+ -+ return KcmTestEnv(kdc_instance, k5util) -+ -+ -+def test_kcm_init_list_destroy(setup_for_kcm): -+ """ -+ Test that kinit, kdestroy and klist work with KCM -+ """ -+ testenv = setup_for_kcm -+ testenv.k5kdc.add_principal("kcmtest", "Secret123") -+ -+ ok = testenv.k5util.has_principal("kcmtest@KCMTEST") -+ assert ok is False -+ nprincs = testenv.k5util.num_princs() -+ assert nprincs == 0 -+ -+ out, _, _ = testenv.k5util.kinit("kcmtest", "Secret123") -+ assert out == 0 -+ nprincs = testenv.k5util.num_princs() -+ assert nprincs == 1 -+ -+ exp_ccname = testenv.ccname() -+ ok = testenv.k5util.has_principal("kcmtest@KCMTEST", exp_ccname) -+ assert ok is True -+ -+ out = testenv.k5util.kdestroy() -+ assert out == 0 -+ -+ ok = testenv.k5util.has_principal("kcmtest@KCMTEST") -+ assert ok is False -+ nprincs = testenv.k5util.num_princs() -+ assert nprincs == 0 -+ -+ -+def test_kcm_overwrite(setup_for_kcm): -+ """ -+ That that reusing a ccache reinitializes the cache and doesn't -+ add the same principal twice -+ """ -+ testenv = setup_for_kcm -+ testenv.k5kdc.add_principal("kcmtest", "Secret123") -+ exp_ccache = {'kcmtest@KCMTEST': ['krbtgt/KCMTEST@KCMTEST']} -+ -+ assert testenv.k5util.num_princs() == 0 -+ -+ out, _, _ = testenv.k5util.kinit("kcmtest", "Secret123") -+ assert out == 0 -+ assert exp_ccache == testenv.k5util.list_all_princs() -+ -+ out, _, _ = testenv.k5util.kinit("kcmtest", "Secret123") -+ assert out == 0 -+ assert exp_ccache == testenv.k5util.list_all_princs() -+ -+ -+def test_collection_init_list_destroy(setup_for_kcm): -+ """ -+ Test that multiple principals and service tickets can be stored -+ in a collection. -+ """ -+ testenv = setup_for_kcm -+ testenv.k5kdc.add_principal("alice", "alicepw") -+ testenv.k5kdc.add_principal("bob", "bobpw") -+ testenv.k5kdc.add_principal("carol", "carolpw") -+ testenv.k5kdc.add_principal("host/somehostname") -+ -+ assert testenv.k5util.num_princs() == 0 -+ -+ out, _, _ = testenv.k5util.kinit("alice", "alicepw") -+ assert out == 0 -+ assert testenv.k5util.default_principal() == 'alice@KCMTEST' -+ cc_coll = testenv.k5util.list_all_princs() -+ assert len(cc_coll) == 1 -+ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -+ assert 'bob@KCMTEST' not in cc_coll -+ assert 'carol@KCMTEST' not in cc_coll -+ -+ out, _, _ = testenv.k5util.kinit("bob", "bobpw") -+ assert out == 0 -+ assert testenv.k5util.default_principal() == 'bob@KCMTEST' -+ cc_coll = testenv.k5util.list_all_princs() -+ assert len(cc_coll) == 2 -+ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -+ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -+ assert 'carol@KCMTEST' not in cc_coll -+ -+ out, _, _ = testenv.k5util.kinit("carol", "carolpw") -+ assert out == 0 -+ assert testenv.k5util.default_principal() == 'carol@KCMTEST' -+ cc_coll = testenv.k5util.list_all_princs() -+ assert len(cc_coll) == 3 -+ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -+ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -+ assert cc_coll['carol@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -+ -+ out, _, _ = testenv.k5util.kvno('host/somehostname') -+ assert out == 0 -+ cc_coll = testenv.k5util.list_all_princs() -+ assert len(cc_coll) == 3 -+ assert set(cc_coll['carol@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST', -+ 'host/somehostname@KCMTEST']) -+ -+ out = testenv.k5util.kdestroy() -+ assert out == 0 -+ assert testenv.k5util.default_principal() == 'bob@KCMTEST' -+ cc_coll = testenv.k5util.list_all_princs() -+ assert len(cc_coll) == 2 -+ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -+ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -+ assert 'carol@KCMTEST' not in cc_coll -+ -+ # FIXME - a bug in libkrb5? -+ #out = testenv.k5util.kdestroy(all_ccaches=True) -+ #assert out == 0 -+ #cc_coll = testenv.k5util.list_all_princs() -+ #assert len(cc_coll) == 0 -+ -+ -+def test_kswitch(setup_for_kcm): -+ """ -+ Test switching between principals -+ """ -+ testenv = setup_for_kcm -+ testenv.k5kdc.add_principal("alice", "alicepw") -+ testenv.k5kdc.add_principal("bob", "bobpw") -+ testenv.k5kdc.add_principal("host/somehostname") -+ testenv.k5kdc.add_principal("host/differenthostname") -+ -+ out, _, _ = testenv.k5util.kinit("alice", "alicepw") -+ assert out == 0 -+ assert testenv.k5util.default_principal() == 'alice@KCMTEST' -+ -+ out, _, _ = testenv.k5util.kinit("bob", "bobpw") -+ assert out == 0 -+ assert testenv.k5util.default_principal() == 'bob@KCMTEST' -+ -+ cc_coll = testenv.k5util.list_all_princs() -+ assert len(cc_coll) == 2 -+ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -+ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -+ -+ out = testenv.k5util.kswitch("alice@KCMTEST") -+ assert testenv.k5util.default_principal() == 'alice@KCMTEST' -+ out, _, _ = testenv.k5util.kvno('host/somehostname') -+ assert out == 0 -+ cc_coll = testenv.k5util.list_all_princs() -+ assert len(cc_coll) == 2 -+ assert set(cc_coll['alice@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST', -+ 'host/somehostname@KCMTEST']) -+ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -+ -+ out = testenv.k5util.kswitch("bob@KCMTEST") -+ assert testenv.k5util.default_principal() == 'bob@KCMTEST' -+ out, _, _ = testenv.k5util.kvno('host/differenthostname') -+ assert out == 0 -+ cc_coll = testenv.k5util.list_all_princs() -+ assert len(cc_coll) == 2 -+ assert set(cc_coll['alice@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST', -+ 'host/somehostname@KCMTEST']) -+ assert set(cc_coll['bob@KCMTEST']) == set([ -+ 'krbtgt/KCMTEST@KCMTEST', -+ 'host/differenthostname@KCMTEST']) -+ -+ -+def test_subsidiaries(setup_for_kcm): -+ """ -+ Test that subsidiary caches are usable and KCM: without specifying UID -+ can be used to identify the collection -+ """ -+ testenv = setup_for_kcm -+ testenv.k5kdc.add_principal("alice", "alicepw") -+ testenv.k5kdc.add_principal("bob", "bobpw") -+ testenv.k5kdc.add_principal("host/somehostname") -+ testenv.k5kdc.add_principal("host/differenthostname") -+ -+ out, _, _ = testenv.k5util.kinit("alice", "alicepw") -+ assert out == 0 -+ out, _, _ = testenv.k5util.kvno('host/somehostname') -+ -+ out, _, _ = testenv.k5util.kinit("bob", "bobpw") -+ assert out == 0 -+ out, _, _ = testenv.k5util.kvno('host/differenthostname') -+ -+ exp_cc_coll = dict() -+ exp_cc_coll['alice@KCMTEST'] = 'host/somehostname@KCMTEST' -+ exp_cc_coll['bob@KCMTEST'] = 'host/differenthostname@KCMTEST' -+ -+ klist_l = testenv.k5util.list_princs() -+ princ_ccache = dict() -+ for line in klist_l: -+ princ, subsidiary = line.split() -+ princ_ccache[princ] = subsidiary -+ -+ for princ, subsidiary in princ_ccache.items(): -+ env = {'KRB5CCNAME': subsidiary} -+ cc_coll = testenv.k5util.list_all_princs(env=env) -+ assert len(cc_coll) == 1 -+ assert princ in cc_coll -+ assert exp_cc_coll[princ] in cc_coll[princ] -+ -+ cc_coll = testenv.k5util.list_all_princs(env={'KRB5CCNAME': 'KCM:'}) -+ assert len(cc_coll) == 2 -+ assert set(cc_coll['alice@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST', -+ 'host/somehostname@KCMTEST']) -+ assert set(cc_coll['bob@KCMTEST']) == set([ -+ 'krbtgt/KCMTEST@KCMTEST', -+ 'host/differenthostname@KCMTEST']) -+ -+ -+def test_kdestroy_nocache(setup_for_kcm): -+ """ -+ Destroying a non-existing ccache should not throw an error -+ """ -+ testenv = setup_for_kcm -+ testenv.k5kdc.add_principal("alice", "alicepw") -+ out, _, _ = testenv.k5util.kinit("alice", "alicepw") -+ assert out == 0 -+ -+ testenv.k5util.kdestroy() -+ assert out == 0 -+ out = testenv.k5util.kdestroy() -+ assert out == 0 --- -2.9.3 - diff --git a/SOURCES/0029-NSS-TESTS-add-unit-tests-for-_EX-requests.patch b/SOURCES/0029-NSS-TESTS-add-unit-tests-for-_EX-requests.patch new file mode 100644 index 0000000..384ca17 --- /dev/null +++ b/SOURCES/0029-NSS-TESTS-add-unit-tests-for-_EX-requests.patch @@ -0,0 +1,590 @@ +From e0f1d81bc24416da1d6d646a0cd3a14bd7e3e02d Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 25 Oct 2017 21:31:54 +0200 +Subject: [PATCH 29/31] NSS/TESTS: add unit tests for *_EX requests + +The patch adds unit tests for the new *_EX requests with different input +types and flags. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 85da8a5e90bffc8b0fef5e0ea364a8d3cb50de86) +--- + src/tests/cmocka/test_nss_srv.c | 539 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 539 insertions(+) + +diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c +index ccedf96beaecfaa4232bbe456d5e5a8394098483..6aa726153183b5a871a75d398727ea7132358ca6 100644 +--- a/src/tests/cmocka/test_nss_srv.c ++++ b/src/tests/cmocka/test_nss_srv.c +@@ -255,6 +255,45 @@ static void mock_input_user_or_group(const char *input) + mock_parse_inp(shortname, domname, EOK); + } + ++static void mock_input_user_or_group_ex(bool do_parse_inp, const char *input, ++ uint32_t flags) ++{ ++ const char *copy; ++ const char *shortname; ++ const char *domname; ++ char *separator; ++ uint8_t *data; ++ size_t len; ++ ++ len = strlen(input); ++ len++; ++ data = talloc_size(nss_test_ctx, len + sizeof(uint32_t)); ++ assert_non_null(data); ++ memcpy(data, input, len); ++ SAFEALIGN_COPY_UINT32(data + len, &flags, NULL); ++ ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); ++ will_return(__wrap_sss_packet_get_body, data); ++ will_return(__wrap_sss_packet_get_body, len + sizeof(uint32_t)); ++ ++ if (do_parse_inp) { ++ copy = talloc_strdup(nss_test_ctx, input); ++ assert_non_null(copy); ++ ++ separator = strrchr(copy, '@'); ++ if (separator == NULL) { ++ shortname = input; ++ domname = NULL; ++ } else { ++ *separator = '\0'; ++ shortname = copy; ++ domname = separator + 1; ++ } ++ ++ mock_parse_inp(shortname, domname, EOK); ++ } ++} ++ + static void mock_input_upn(const char *upn) + { + will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); +@@ -291,6 +330,20 @@ static void mock_input_id(TALLOC_CTX *mem_ctx, uint32_t id) + will_return(__wrap_sss_packet_get_body, sizeof(uint32_t)); + } + ++static void mock_input_id_ex(TALLOC_CTX *mem_ctx, uint32_t id, uint32_t flags) ++{ ++ uint8_t *body; ++ ++ body = talloc_zero_array(mem_ctx, uint8_t, 8); ++ if (body == NULL) return; ++ ++ SAFEALIGN_SETMEM_UINT32(body, id, NULL); ++ SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), flags, NULL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); ++ will_return(__wrap_sss_packet_get_body, body); ++ will_return(__wrap_sss_packet_get_body, 2 * sizeof(uint32_t)); ++} ++ + static void mock_fill_user(void) + { + /* One packet for the entry and one for num entries */ +@@ -4143,6 +4196,482 @@ void test_nss_getsidbyname_neg(void **state) + assert_int_equal(ret, ENOENT); + } + ++static int test_nss_EINVAL_check(uint32_t status, uint8_t *body, size_t blen) ++{ ++ assert_int_equal(status, EINVAL); ++ assert_int_equal(blen, 0); ++ ++ return EOK; ++} ++ ++#define RESET_TCTX do { \ ++ nss_test_ctx->tctx->done = false; \ ++ nss_test_ctx->tctx->error = EIO; \ ++} while (0) ++ ++void test_nss_getpwnam_ex(void **state) ++{ ++ errno_t ret; ++ ++ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, ++ &getpwnam_usr, NULL, 0); ++ assert_int_equal(ret, EOK); ++ ++ mock_input_user_or_group_ex(true, "testuser", 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX); ++ mock_fill_user(); ++ ++ /* Query for that user, call a callback when command finishes */ ++ set_cmd_cb(test_nss_getpwnam_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use old input format, expect EINVAL */ ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); ++ will_return(__wrap_sss_packet_get_body, "testuser"); ++ will_return(__wrap_sss_packet_get_body, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use unsupported flag combination, expect EINVAL */ ++ mock_input_user_or_group_ex(false, "testuser", ++ SSS_NSS_EX_FLAG_NO_CACHE ++ |SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_NO_CACHE, ++ * will cause a backend lookup -> mock_account_recv_simple() */ ++ mock_input_user_or_group_ex(true, "testuser", SSS_NSS_EX_FLAG_NO_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX); ++ mock_fill_user(); ++ mock_account_recv_simple(); ++ ++ set_cmd_cb(test_nss_getpwnam_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ mock_input_user_or_group_ex(true, "testuser", ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX); ++ mock_fill_user(); ++ ++ set_cmd_cb(test_nss_getpwnam_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_nss_getpwuid_ex(void **state) ++{ ++ errno_t ret; ++ uint32_t id = 101; ++ ++ /* Prime the cache with a valid user */ ++ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, ++ &getpwuid_usr, NULL, 0); ++ assert_int_equal(ret, EOK); ++ ++ mock_input_id_ex(nss_test_ctx, id, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX); ++ mock_fill_user(); ++ ++ /* Query for that id, call a callback when command finishes */ ++ set_cmd_cb(test_nss_getpwuid_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use old input format, expect failure */ ++ mock_input_id(nss_test_ctx, id); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use unsupported flag combination, expect EINVAL */ ++ mock_input_id_ex(nss_test_ctx, id, SSS_NSS_EX_FLAG_NO_CACHE ++ |SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_NO_CACHE, ++ * will cause a backend lookup -> mock_account_recv_simple() */ ++ mock_input_id_ex(nss_test_ctx, id, SSS_NSS_EX_FLAG_NO_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX); ++ mock_fill_user(); ++ mock_account_recv_simple(); ++ ++ set_cmd_cb(test_nss_getpwuid_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ mock_input_id_ex(nss_test_ctx, id, SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX); ++ mock_fill_user(); ++ ++ set_cmd_cb(test_nss_getpwuid_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_nss_getgrnam_ex_no_members(void **state) ++{ ++ errno_t ret; ++ ++ /* Test group is still in the cache */ ++ ++ mock_input_user_or_group_ex(true, getgrnam_no_members.gr_name, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ /* Query for that group, call a callback when command finishes */ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use old input format, expect failure */ ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); ++ will_return(__wrap_sss_packet_get_body, "testgroup"); ++ will_return(__wrap_sss_packet_get_body, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use unsupported flag combination, expect EINVAL */ ++ mock_input_user_or_group_ex(false, getgrnam_no_members.gr_name, ++ SSS_NSS_EX_FLAG_NO_CACHE ++ |SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_NO_CACHE, ++ * will cause a backend lookup -> mock_account_recv_simple() */ ++ mock_input_user_or_group_ex(true, getgrnam_no_members.gr_name, ++ SSS_NSS_EX_FLAG_NO_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ mock_account_recv_simple(); ++ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ mock_input_user_or_group_ex(true, getgrnam_no_members.gr_name, ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_nss_getgrgid_ex_no_members(void **state) ++{ ++ errno_t ret; ++ ++ /* Test group is still in the cache */ ++ ++ mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ mock_account_recv_simple(); ++ ++ /* Query for that group, call a callback when command finishes */ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use old input format, expect failure */ ++ mock_input_id(nss_test_ctx, getgrnam_no_members.gr_gid); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use unsupported flag combination, expect EINVAL */ ++ mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid, ++ SSS_NSS_EX_FLAG_NO_CACHE ++ |SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_NO_CACHE, ++ * will cause a backend lookup -> mock_account_recv_simple() */ ++ mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid, ++ SSS_NSS_EX_FLAG_NO_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ mock_account_recv_simple(); ++ mock_account_recv_simple(); ++ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid, ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_nss_initgroups_ex(void **state) ++{ ++ errno_t ret; ++ struct sysdb_attrs *attrs; ++ ++ attrs = sysdb_new_attrs(nss_test_ctx); ++ assert_non_null(attrs); ++ ++ ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, ++ time(NULL) + 300); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, "upninitgr@upndomain.test"); ++ assert_int_equal(ret, EOK); ++ ++ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, ++ &testinitgr_usr, attrs, 0); ++ assert_int_equal(ret, EOK); ++ ++ mock_input_user_or_group_ex(true, "testinitgr", 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX); ++ mock_fill_user(); ++ ++ /* Query for that user, call a callback when command finishes */ ++ set_cmd_cb(test_nss_initgr_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use old input format, expect failure */ ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); ++ will_return(__wrap_sss_packet_get_body, "testinitgr"); ++ will_return(__wrap_sss_packet_get_body, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use unsupported flag combination, expect EINVAL */ ++ mock_input_user_or_group_ex(false, "testinitgr", ++ SSS_NSS_EX_FLAG_NO_CACHE ++ |SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_NO_CACHE, ++ * will cause a backend lookup -> mock_account_recv_simple() */ ++ mock_input_user_or_group_ex(true, "testinitgr", ++ SSS_NSS_EX_FLAG_NO_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX); ++ mock_fill_user(); ++ mock_account_recv_simple(); ++ ++ set_cmd_cb(test_nss_initgr_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ mock_input_user_or_group_ex(true, "testinitgr", ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX); ++ mock_fill_user(); ++ ++ set_cmd_cb(test_nss_initgr_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ + int main(int argc, const char *argv[]) + { + int rv; +@@ -4288,6 +4817,16 @@ int main(int argc, const char *argv[]) + nss_test_setup, nss_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getsidbyname_neg, + nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_getpwnam_ex, ++ nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_getpwuid_ex, ++ nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_getgrnam_ex_no_members, ++ nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_getgrgid_ex_no_members, ++ nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_initgroups_ex, ++ nss_test_setup, nss_test_teardown), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +-- +2.13.6 + diff --git a/SOURCES/0029-SECRETS-Create-DB-path-before-the-operation-itself.patch b/SOURCES/0029-SECRETS-Create-DB-path-before-the-operation-itself.patch deleted file mode 100644 index 3b1bee7..0000000 --- a/SOURCES/0029-SECRETS-Create-DB-path-before-the-operation-itself.patch +++ /dev/null @@ -1,405 +0,0 @@ -From 27e11e8f03e1bad5d1be276efaf1406b16b11625 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 3 Jan 2017 16:00:38 +0100 -Subject: [PATCH 29/36] SECRETS: Create DB path before the operation itself -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This is a refactoring where instead of creating the ldb path in the -operation itself, we create the ldb path when creating the local db request -and pass the path to the operation. - -This would allow us to store different kind of objects in the secrets -storage later. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/responder/secrets/local.c | 170 +++++++++++++++++++++--------------------- - 1 file changed, 84 insertions(+), 86 deletions(-) - -diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c -index ed70193bcb27d84eaf449f6f7571c94f466c9896..9dcdd9925e542499d3a962b4998103b07c26a5ab 100644 ---- a/src/responder/secrets/local.c -+++ b/src/responder/secrets/local.c -@@ -199,39 +199,36 @@ static char *local_dn_to_path(TALLOC_CTX *mem_ctx, - return path; - } - -+struct local_db_req { -+ char *path; -+ struct ldb_dn *basedn; -+}; -+ - #define LOCAL_SIMPLE_FILTER "(type=simple)" - #define LOCAL_CONTAINER_FILTER "(type=container)" - - static int local_db_get_simple(TALLOC_CTX *mem_ctx, - struct local_context *lctx, -- const char *req_path, -+ struct local_db_req *lc_req, - char **secret) - { - TALLOC_CTX *tmp_ctx; - static const char *attrs[] = { "secret", "enctype", NULL }; - struct ldb_result *res; -- struct ldb_dn *dn; - const char *attr_secret; - const char *attr_enctype; - int ret; - -- DEBUG(SSSDBG_TRACE_FUNC, "Retrieving a secret from [%s]\n", req_path); -+ DEBUG(SSSDBG_TRACE_FUNC, "Retrieving a secret from [%s]\n", lc_req->path); - - tmp_ctx = talloc_new(mem_ctx); - if (!tmp_ctx) return ENOMEM; - -- ret = local_db_dn(tmp_ctx, lctx->ldb, req_path, &dn); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret)); -- goto done; -- } -- - DEBUG(SSSDBG_TRACE_INTERNAL, - "Searching for [%s] at [%s] with scope=base\n", -- LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(dn)); -+ LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(lc_req->basedn)); - -- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, -+ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_BASE, - attrs, "%s", LOCAL_SIMPLE_FILTER); - if (ret != EOK) { - DEBUG(SSSDBG_TRACE_LIBS, -@@ -278,34 +275,26 @@ done: - - static int local_db_list_keys(TALLOC_CTX *mem_ctx, - struct local_context *lctx, -- const char *req_path, -+ struct local_db_req *lc_req, - char ***_keys, - int *num_keys) - { - TALLOC_CTX *tmp_ctx; - static const char *attrs[] = { "secret", NULL }; - struct ldb_result *res; -- struct ldb_dn *dn; - char **keys; - int ret; - - tmp_ctx = talloc_new(mem_ctx); - if (!tmp_ctx) return ENOMEM; - -- DEBUG(SSSDBG_TRACE_FUNC, "Listing keys at [%s]\n", req_path); -- -- ret = local_db_dn(tmp_ctx, lctx->ldb, req_path, &dn); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret)); -- goto done; -- } -+ DEBUG(SSSDBG_TRACE_FUNC, "Listing keys at [%s]\n", lc_req->path); - - DEBUG(SSSDBG_TRACE_INTERNAL, - "Searching for [%s] at [%s] with scope=subtree\n", -- LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(dn)); -+ LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(lc_req->basedn)); - -- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE, -+ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_SUBTREE, - attrs, "%s", LOCAL_SIMPLE_FILTER); - if (ret != EOK) { - DEBUG(SSSDBG_TRACE_LIBS, -@@ -327,7 +316,7 @@ static int local_db_list_keys(TALLOC_CTX *mem_ctx, - } - - for (unsigned i = 0; i < res->count; i++) { -- keys[i] = local_dn_to_path(keys, dn, res->msgs[i]->dn); -+ keys[i] = local_dn_to_path(keys, lc_req->basedn, res->msgs[i]->dn); - if (!keys[i]) { - ret = ENOMEM; - goto done; -@@ -474,7 +463,7 @@ static int local_check_max_payload_size(struct local_context *lctx, - - static int local_db_put_simple(TALLOC_CTX *mem_ctx, - struct local_context *lctx, -- const char *req_path, -+ struct local_db_req *lc_req, - const char *secret) - { - struct ldb_message *msg; -@@ -482,20 +471,14 @@ static int local_db_put_simple(TALLOC_CTX *mem_ctx, - char *enc_secret; - int ret; - -+ DEBUG(SSSDBG_TRACE_FUNC, "Adding a secret to [%s]\n", lc_req->path); -+ - msg = ldb_msg_new(mem_ctx); - if (!msg) { - ret = ENOMEM; - goto done; - } -- -- DEBUG(SSSDBG_TRACE_FUNC, "Adding a secret to [%s]\n", req_path); -- -- ret = local_db_dn(msg, lctx->ldb, req_path, &msg->dn); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret)); -- goto done; -- } -+ msg->dn = lc_req->basedn; - - /* make sure containers exist */ - ret = local_db_check_containers(msg, lctx, msg->dn); -@@ -585,32 +568,24 @@ done: - - static int local_db_delete(TALLOC_CTX *mem_ctx, - struct local_context *lctx, -- const char *req_path) -+ struct local_db_req *lc_req) - { - TALLOC_CTX *tmp_ctx; -- struct ldb_dn *dn; - static const char *attrs[] = { NULL }; - struct ldb_result *res; - int ret; - -- DEBUG(SSSDBG_TRACE_FUNC, "Removing a secret from [%s]\n", req_path); -+ DEBUG(SSSDBG_TRACE_FUNC, "Removing a secret from [%s]\n", lc_req->path); - - tmp_ctx = talloc_new(mem_ctx); - if (!tmp_ctx) return ENOMEM; - -- ret = local_db_dn(mem_ctx, lctx->ldb, req_path, &dn); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret)); -- goto done; -- } -- - DEBUG(SSSDBG_TRACE_INTERNAL, - "Searching for [%s] at [%s] with scope=base\n", -- LOCAL_CONTAINER_FILTER, ldb_dn_get_linearized(dn)); -+ LOCAL_CONTAINER_FILTER, ldb_dn_get_linearized(lc_req->basedn)); - -- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, -- attrs, LOCAL_CONTAINER_FILTER); -+ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_BASE, -+ attrs, LOCAL_CONTAINER_FILTER); - if (ret != EOK) { - DEBUG(SSSDBG_TRACE_LIBS, - "ldb_search returned %d: %s\n", ret, ldb_strerror(ret)); -@@ -619,8 +594,8 @@ static int local_db_delete(TALLOC_CTX *mem_ctx, - - if (res->count == 1) { - DEBUG(SSSDBG_TRACE_INTERNAL, -- "Searching for children of [%s]\n", ldb_dn_get_linearized(dn)); -- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_ONELEVEL, -+ "Searching for children of [%s]\n", ldb_dn_get_linearized(lc_req->basedn)); -+ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_ONELEVEL, - attrs, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_TRACE_LIBS, -@@ -632,13 +607,13 @@ static int local_db_delete(TALLOC_CTX *mem_ctx, - ret = EEXIST; - DEBUG(SSSDBG_OP_FAILURE, - "Failed to remove '%s': Container is not empty\n", -- ldb_dn_get_linearized(dn)); -+ ldb_dn_get_linearized(lc_req->basedn)); - - goto done; - } - } - -- ret = ldb_delete(lctx->ldb, dn); -+ ret = ldb_delete(lctx->ldb, lc_req->basedn); - if (ret != EOK) { - DEBUG(SSSDBG_TRACE_LIBS, - "ldb_delete returned %d: %s\n", ret, ldb_strerror(ret)); -@@ -653,25 +628,19 @@ done: - - static int local_db_create(TALLOC_CTX *mem_ctx, - struct local_context *lctx, -- const char *req_path) -+ struct local_db_req *lc_req) - { - struct ldb_message *msg; - int ret; - -+ DEBUG(SSSDBG_TRACE_FUNC, "Creating a container at [%s]\n", lc_req->path); -+ - msg = ldb_msg_new(mem_ctx); - if (!msg) { - ret = ENOMEM; - goto done; - } -- -- DEBUG(SSSDBG_TRACE_FUNC, "Creating a container at [%s]\n", req_path); -- -- ret = local_db_dn(msg, lctx->ldb, req_path, &msg->dn); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret)); -- goto done; -- } -+ msg->dn = lc_req->basedn; - - /* make sure containers exist */ - ret = local_db_check_containers(msg, lctx, msg->dn); -@@ -724,10 +693,13 @@ done: - } - - static int local_secrets_map_path(TALLOC_CTX *mem_ctx, -+ struct ldb_context *ldb, - struct sec_req_ctx *secreq, -- char **local_db_path) -+ struct local_db_req **_lc_req) - { - int ret; -+ struct local_db_req *lc_req; -+ const char *basedn; - - /* be strict for now */ - if (secreq->parsed_url.fragment != NULL) { -@@ -755,20 +727,46 @@ static int local_secrets_map_path(TALLOC_CTX *mem_ctx, - } - } - -- /* drop SEC_BASEPATH prefix */ -- *local_db_path = -- talloc_strdup(mem_ctx, &secreq->mapped_path[sizeof(SEC_BASEPATH) - 1]); -- if (!*local_db_path) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Failed to map request to local db path\n"); -+ lc_req = talloc(mem_ctx, struct local_db_req); -+ if (lc_req == NULL) { - return ENOMEM; - } - -- DEBUG(SSSDBG_TRACE_LIBS, "Local DB path is %s\n", *local_db_path); -- return EOK; -+ /* drop the prefix and select a basedn instead */ -+ if (strncmp(secreq->mapped_path, -+ SEC_BASEPATH, sizeof(SEC_BASEPATH) - 1) == 0) { -+ lc_req->path = talloc_strdup(lc_req, -+ secreq->mapped_path + (sizeof(SEC_BASEPATH) - 1)); -+ basedn = SECRETS_BASEDN; -+ } else { -+ ret = EINVAL; -+ goto done; -+ } -+ -+ if (lc_req->path == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to map request to local db path\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = local_db_dn(mem_ctx, ldb, basedn, lc_req->path, &lc_req->basedn); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to map request to local db DN\n"); -+ goto done; -+ } -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "Local DB path is %s\n", lc_req->path); -+ ret = EOK; -+ *_lc_req = lc_req; -+done: -+ if (ret != EOK) { -+ talloc_free(lc_req); -+ } -+ return ret; - } - -- - struct local_secret_state { - struct tevent_context *ev; - struct sec_req_ctx *secreq; -@@ -785,7 +783,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, - struct sec_data body = { 0 }; - const char *content_type; - bool body_is_json; -- char *req_path; -+ struct local_db_req *lc_req; - char *secret; - char **keys; - int nkeys; -@@ -821,14 +819,14 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, - } - DEBUG(SSSDBG_TRACE_LIBS, "Content-Type: %s\n", content_type); - -- ret = local_secrets_map_path(state, secreq, &req_path); -+ ret = local_secrets_map_path(state, lctx->ldb, secreq, &lc_req); - if (ret) goto done; - - switch (secreq->method) { - case HTTP_GET: -- DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP GET at [%s]\n", req_path); -- if (req_path[strlen(req_path) - 1] == '/') { -- ret = local_db_list_keys(state, lctx, req_path, &keys, &nkeys); -+ DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP GET at [%s]\n", lc_req->path); -+ if (lc_req->path[strlen(lc_req->path) - 1] == '/') { -+ ret = local_db_list_keys(state, lctx, lc_req, &keys, &nkeys); - if (ret) goto done; - - ret = sec_array_to_json(state, keys, nkeys, &body.data); -@@ -838,7 +836,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, - break; - } - -- ret = local_db_get_simple(state, lctx, req_path, &secret); -+ ret = local_db_get_simple(state, lctx, lc_req, &secret); - if (ret) goto done; - - if (body_is_json) { -@@ -855,7 +853,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, - break; - - case HTTP_PUT: -- DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP PUT at [%s]\n", req_path); -+ DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP PUT at [%s]\n", lc_req->path); - if (body_is_json) { - ret = sec_json_to_simple_secret(state, secreq->body.data, - &secret); -@@ -866,27 +864,27 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, - } - if (ret) goto done; - -- ret = local_db_put_simple(state, lctx, req_path, secret); -+ ret = local_db_put_simple(state, lctx, lc_req, secret); - if (ret) goto done; - break; - - case HTTP_DELETE: -- ret = local_db_delete(state, lctx, req_path); -+ ret = local_db_delete(state, lctx, lc_req); - if (ret) goto done; - break; - - case HTTP_POST: -- DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP POST at [%s]\n", req_path); -- plen = strlen(req_path); -+ DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP POST at [%s]\n", lc_req->path); -+ plen = strlen(lc_req->path); - -- if (req_path[plen - 1] != '/') { -+ if (lc_req->path[plen - 1] != '/') { - ret = EINVAL; - goto done; - } - -- req_path[plen - 1] = '\0'; -+ lc_req->path[plen - 1] = '\0'; - -- ret = local_db_create(state, lctx, req_path); -+ ret = local_db_create(state, lctx, lc_req); - if (ret) goto done; - break; - --- -2.9.3 - diff --git a/SOURCES/0030-SECRETS-Return-a-nicer-error-message-on-request-with.patch b/SOURCES/0030-SECRETS-Return-a-nicer-error-message-on-request-with.patch deleted file mode 100644 index 2c596dc..0000000 --- a/SOURCES/0030-SECRETS-Return-a-nicer-error-message-on-request-with.patch +++ /dev/null @@ -1,40 +0,0 @@ -From ddda18a37ac4b732ad109dbb129255dc3edd8fbb Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 3 Feb 2017 14:33:47 +0100 -Subject: [PATCH 30/36] SECRETS: Return a nicer error message on request with - no PUT data -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -I managed to create this pathological situation with the tcurl tool -which didn't send any PUT data. The error in sssd-secrets was quite -strange (ENOMEM). This patch just adds a safeguard sooner so that we -return a graceful error. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/responder/secrets/local.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c -index 9dcdd9925e542499d3a962b4998103b07c26a5ab..26c97a2849febbf0ac482d526cf927bfc103b4f2 100644 ---- a/src/responder/secrets/local.c -+++ b/src/responder/secrets/local.c -@@ -853,6 +853,12 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, - break; - - case HTTP_PUT: -+ if (secreq->body.length == 0) { -+ DEBUG(SSSDBG_OP_FAILURE, "PUT with no data\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ - DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP PUT at [%s]\n", lc_req->path); - if (body_is_json) { - ret = sec_json_to_simple_secret(state, secreq->body.data, --- -2.9.3 - diff --git a/SOURCES/0030-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch b/SOURCES/0030-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch new file mode 100644 index 0000000..caf0dc0 --- /dev/null +++ b/SOURCES/0030-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch @@ -0,0 +1,494 @@ +From a12e6ac8001025174cf201bcaa2143edb1b0c017 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 2 Nov 2017 10:32:41 +0100 +Subject: [PATCH 30/31] nss-idmap: add timeout version of old sss_nss_* calls + +Reviewed-by: Jakub Hrozek +(cherry picked from commit e54db68cbb9c12d8a6867f2c7766fb2115ab0997) +--- + Makefile.am | 2 +- + src/sss_client/idmap/sss_nss_idmap.c | 126 ++++++++++++++++++-------- + src/sss_client/idmap/sss_nss_idmap.exports | 7 ++ + src/sss_client/idmap/sss_nss_idmap.h | 124 +++++++++++++++++++++++++ + src/sss_client/idmap/sss_nss_idmap.unit_tests | 2 +- + src/tests/cmocka/sss_nss_idmap-tests.c | 13 +-- + 6 files changed, 229 insertions(+), 45 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index dd25d1f7ea1be66388aa1b393bac290c4d7501a2..286ba47e3c421864362717be5258de960efca9f2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2974,7 +2974,6 @@ test_sysdb_domain_resolution_order_LDADD = \ + + test_wbc_calls_SOURCES = \ + src/tests/cmocka/test_wbc_calls.c \ +- src/sss_client/idmap/sss_nss_idmap.c \ + src/sss_client/libwbclient/wbc_sid_sssd.c \ + src/sss_client/libwbclient/wbclient_common.c \ + src/sss_client/libwbclient/wbc_sid_common.c \ +@@ -2993,6 +2992,7 @@ test_wbc_calls_LDADD = \ + $(TALLOC_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ + libsss_test_common.la \ ++ libsss_nss_idmap.la \ + $(NULL) + + test_be_ptask_SOURCES = \ +diff --git a/src/sss_client/idmap/sss_nss_idmap.c b/src/sss_client/idmap/sss_nss_idmap.c +index 6f3af267a1e763e7dce77e3862be377ae2bfe984..6e7685d2b1d80956b6a6668e9bbb146abd9e86ed 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.c ++++ b/src/sss_client/idmap/sss_nss_idmap.c +@@ -28,10 +28,13 @@ + + #include "sss_client/sss_cli.h" + #include "sss_client/idmap/sss_nss_idmap.h" ++#include "sss_client/idmap/sss_nss_idmap_private.h" + #include "util/strtonum.h" + + #define DATA_START (3 * sizeof(uint32_t)) + #define LIST_START (2 * sizeof(uint32_t)) ++#define NO_TIMEOUT ((unsigned int) -1) ++ + union input { + const char *str; + uint32_t id; +@@ -198,8 +201,8 @@ done: + return ret; + } + +-static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , +- struct output *out) ++static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd, ++ unsigned int timeout, struct output *out) + { + int ret; + size_t inp_len; +@@ -215,6 +218,7 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , + struct sss_nss_kv *kv_list; + char **names; + enum sss_id_type *types; ++ int time_left = SSS_CLI_SOCKET_TIMEOUT; + + switch (cmd) { + case SSS_NSS_GETSIDBYNAME: +@@ -250,9 +254,14 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , + return EINVAL; + } + +- sss_nss_lock(); ++ if (timeout == NO_TIMEOUT) { ++ sss_nss_lock(); ++ } else { ++ sss_nss_timedlock(timeout, &time_left); ++ } + +- nret = sss_nss_make_request(cmd, &rd, &repbuf, &replen, &errnop); ++ nret = sss_nss_make_request_timeout(cmd, &rd, time_left, &repbuf, &replen, ++ &errnop); + if (nret != NSS_STATUS_SUCCESS) { + ret = nss_status_to_errno(nret); + goto done; +@@ -347,8 +356,8 @@ done: + return ret; + } + +-int sss_nss_getsidbyname(const char *fq_name, char **sid, +- enum sss_id_type *type) ++int sss_nss_getsidbyname_timeout(const char *fq_name, unsigned int timeout, ++ char **sid, enum sss_id_type *type) + { + int ret; + union input inp; +@@ -360,7 +369,7 @@ int sss_nss_getsidbyname(const char *fq_name, char **sid, + + inp.str = fq_name; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYNAME, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYNAME, timeout, &out); + if (ret == EOK) { + *sid = out.d.str; + *type = out.type; +@@ -369,7 +378,14 @@ int sss_nss_getsidbyname(const char *fq_name, char **sid, + return ret; + } + +-int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type) ++int sss_nss_getsidbyname(const char *fq_name, char **sid, ++ enum sss_id_type *type) ++{ ++ return sss_nss_getsidbyname_timeout(fq_name, NO_TIMEOUT, sid, type); ++} ++ ++int sss_nss_getsidbyid_timeout(uint32_t id, unsigned int timeout, ++ char **sid, enum sss_id_type *type) + { + int ret; + union input inp; +@@ -381,7 +397,7 @@ int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type) + + inp.id = id; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYID, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYID, timeout, &out); + if (ret == EOK) { + *sid = out.d.str; + *type = out.type; +@@ -390,8 +406,13 @@ int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type) + return ret; + } + +-int sss_nss_getnamebysid(const char *sid, char **fq_name, +- enum sss_id_type *type) ++int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type) ++{ ++ return sss_nss_getsidbyid_timeout(id, NO_TIMEOUT, sid, type); ++} ++ ++int sss_nss_getnamebysid_timeout(const char *sid, unsigned int timeout, ++ char **fq_name, enum sss_id_type *type) + { + int ret; + union input inp; +@@ -403,7 +424,7 @@ int sss_nss_getnamebysid(const char *sid, char **fq_name, + + inp.str = sid; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYSID, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYSID, timeout, &out); + if (ret == EOK) { + *fq_name = out.d.str; + *type = out.type; +@@ -412,7 +433,14 @@ int sss_nss_getnamebysid(const char *sid, char **fq_name, + return ret; + } + +-int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type) ++int sss_nss_getnamebysid(const char *sid, char **fq_name, ++ enum sss_id_type *type) ++{ ++ return sss_nss_getnamebysid_timeout(sid, NO_TIMEOUT, fq_name, type); ++} ++ ++int sss_nss_getidbysid_timeout(const char *sid, unsigned int timeout, ++ uint32_t *id, enum sss_id_type *id_type) + { + int ret; + union input inp; +@@ -424,7 +452,7 @@ int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type) + + inp.str = sid; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETIDBYSID, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETIDBYSID, timeout, &out); + if (ret == EOK) { + *id = out.d.id; + *id_type = out.type; +@@ -433,8 +461,14 @@ int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type) + return ret; + } + +-int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list, +- enum sss_id_type *type) ++int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type) ++{ ++ return sss_nss_getidbysid_timeout(sid, NO_TIMEOUT, id, id_type); ++} ++ ++int sss_nss_getorigbyname_timeout(const char *fq_name, unsigned int timeout, ++ struct sss_nss_kv **kv_list, ++ enum sss_id_type *type) + { + int ret; + union input inp; +@@ -446,7 +480,7 @@ int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list, + + inp.str = fq_name; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETORIGBYNAME, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETORIGBYNAME, timeout, &out); + if (ret == EOK) { + *kv_list = out.d.kv_list; + *type = out.type; +@@ -455,30 +489,42 @@ int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list, + return ret; + } + ++int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list, ++ enum sss_id_type *type) ++{ ++ return sss_nss_getorigbyname_timeout(fq_name, NO_TIMEOUT, kv_list, type); ++} ++ ++int sss_nss_getnamebycert_timeout(const char *cert, unsigned int timeout, ++ char **fq_name, enum sss_id_type *type) ++{ ++ int ret; ++ union input inp; ++ struct output out; ++ ++ if (fq_name == NULL || cert == NULL || *cert == '\0') { ++ return EINVAL; ++ } ++ ++ inp.str = cert; ++ ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYCERT, timeout, &out); ++ if (ret == EOK) { ++ *fq_name = out.d.str; ++ *type = out.type; ++ } ++ ++ return ret; ++} ++ + int sss_nss_getnamebycert(const char *cert, char **fq_name, + enum sss_id_type *type) + { +- int ret; +- union input inp; +- struct output out; +- +- if (fq_name == NULL || cert == NULL || *cert == '\0') { +- return EINVAL; +- } +- +- inp.str = cert; +- +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYCERT, &out); +- if (ret == EOK) { +- *fq_name = out.d.str; +- *type = out.type; +- } +- +- return ret; ++ return sss_nss_getnamebycert_timeout(cert, NO_TIMEOUT, fq_name, type); + } + +-int sss_nss_getlistbycert(const char *cert, char ***fq_name, +- enum sss_id_type **type) ++int sss_nss_getlistbycert_timeout(const char *cert, unsigned int timeout, ++ char ***fq_name, enum sss_id_type **type) + { + int ret; + union input inp; +@@ -490,7 +536,7 @@ int sss_nss_getlistbycert(const char *cert, char ***fq_name, + + inp.str = cert; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETLISTBYCERT, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETLISTBYCERT, timeout, &out); + if (ret == EOK) { + *fq_name = out.d.names; + *type = out.types; +@@ -498,3 +544,9 @@ int sss_nss_getlistbycert(const char *cert, char ***fq_name, + + return ret; + } ++ ++int sss_nss_getlistbycert(const char *cert, char ***fq_name, ++ enum sss_id_type **type) ++{ ++ return sss_nss_getlistbycert_timeout(cert, NO_TIMEOUT, fq_name, type); ++} +diff --git a/src/sss_client/idmap/sss_nss_idmap.exports b/src/sss_client/idmap/sss_nss_idmap.exports +index 788d05ecc3bd56fa88e68a98b9c8096cf7140a09..8d0a24f42aa3fb3dd9c2ed125bf79e2c7792993f 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.exports ++++ b/src/sss_client/idmap/sss_nss_idmap.exports +@@ -40,4 +40,11 @@ SSS_NSS_IDMAP_0.4.0 { + sss_nss_getgrnam_timeout; + sss_nss_getgrgid_timeout; + sss_nss_getgrouplist_timeout; ++ sss_nss_getsidbyname_timeout; ++ sss_nss_getsidbyid_timeout; ++ sss_nss_getnamebysid_timeout; ++ sss_nss_getidbysid_timeout; ++ sss_nss_getorigbyname_timeout; ++ sss_nss_getnamebycert_timeout; ++ sss_nss_getlistbycert_timeout; + } SSS_NSS_IDMAP_0.3.0; +diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h +index 3755643312f05a31d1cf1aa76dfc22848ef1e3ec..125e72a6486f5916f90d37f27e1743d181bfa3e5 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.h ++++ b/src/sss_client/idmap/sss_nss_idmap.h +@@ -303,5 +303,129 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, + int sss_nss_getgrouplist_timeout(const char *name, gid_t group, + gid_t *groups, int *ngroups, + uint32_t flags, unsigned int timeout); ++/** ++ * @brief Find SID by fully qualified name with timeout ++ * ++ * @param[in] fq_name Fully qualified name of a user or a group ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] sid String representation of the SID of the requested user ++ * or group, must be freed by the caller ++ * @param[out] type Type of the object related to the given name ++ * ++ * @return ++ * - 0 (EOK): success, sid contains the requested SID ++ * - ENOENT: requested object was not found in the domain extracted from the given name ++ * - ENETUNREACH: SSSD does not know how to handle the domain extracted from the given name ++ * - ENOSYS: this call is not supported by the configured provider ++ * - EINVAL: input cannot be parsed ++ * - EIO: remote servers cannot be reached ++ * - EFAULT: any other error ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getsidbyname_timeout(const char *fq_name, unsigned int timeout, ++ char **sid, enum sss_id_type *type); ++ ++/** ++ * @brief Find SID by a POSIX UID or GID with timeout ++ * ++ * @param[in] id POSIX UID or GID ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] sid String representation of the SID of the requested user ++ * or group, must be freed by the caller ++ * @param[out] type Type of the object related to the given ID ++ * ++ * @return ++ * - see #sss_nss_getsidbyname_timeout ++ */ ++int sss_nss_getsidbyid_timeout(uint32_t id, unsigned int timeout, ++ char **sid, enum sss_id_type *type); ++ ++/** ++ * @brief Return the fully qualified name for the given SID with timeout ++ * ++ * @param[in] sid String representation of the SID ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] fq_name Fully qualified name of a user or a group, ++ * must be freed by the caller ++ * @param[out] type Type of the object related to the SID ++ * ++ * @return ++ * - see #sss_nss_getsidbyname_timeout ++ */ ++int sss_nss_getnamebysid_timeout(const char *sid, unsigned int timeout, ++ char **fq_name, enum sss_id_type *type); ++ ++/** ++ * @brief Return the POSIX ID for the given SID with timeout ++ * ++ * @param[in] sid String representation of the SID ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] id POSIX ID related to the SID ++ * @param[out] id_type Type of the object related to the SID ++ * ++ * @return ++ * - see #sss_nss_getsidbyname_timeout ++ */ ++int sss_nss_getidbysid_timeout(const char *sid, unsigned int timeout, ++ uint32_t *id, enum sss_id_type *id_type); ++ ++/** ++ * @brief Find original data by fully qualified name with timeout ++ * ++ * @param[in] fq_name Fully qualified name of a user or a group ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] kv_list A NULL terminate list of key-value pairs where the key ++ * is the attribute name in the cache of SSSD, ++ * must be freed by the caller with sss_nss_free_kv() ++ * @param[out] type Type of the object related to the given name ++ * ++ * @return ++ * - 0 (EOK): success, sid contains the requested SID ++ * - ENOENT: requested object was not found in the domain extracted from the given name ++ * - ENETUNREACH: SSSD does not know how to handle the domain extracted from the given name ++ * - ENOSYS: this call is not supported by the configured provider ++ * - EINVAL: input cannot be parsed ++ * - EIO: remote servers cannot be reached ++ * - EFAULT: any other error ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getorigbyname_timeout(const char *fq_name, unsigned int timeout, ++ struct sss_nss_kv **kv_list, ++ enum sss_id_type *type); ++ ++/** ++ * @brief Return the fully qualified name for the given base64 encoded ++ * X.509 certificate in DER format with timeout ++ * ++ * @param[in] cert base64 encoded certificate ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] fq_name Fully qualified name of a user or a group, ++ * must be freed by the caller ++ * @param[out] type Type of the object related to the cert ++ * ++ * @return ++ * - see #sss_nss_getsidbyname_timeout ++ */ ++int sss_nss_getnamebycert_timeout(const char *cert, unsigned int timeout, ++ char **fq_name, enum sss_id_type *type); ++ ++/** ++ * @brief Return a list of fully qualified names for the given base64 encoded ++ * X.509 certificate in DER format with timeout ++ * ++ * @param[in] cert base64 encoded certificate ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] fq_name List of fully qualified name of users or groups, ++ * must be freed by the caller ++ * @param[out] type List of types of the objects related to the cert ++ * ++ * @return ++ * - see #sss_nss_getsidbyname_timeout ++ */ ++int sss_nss_getlistbycert_timeout(const char *cert, unsigned int timeout, ++ char ***fq_name, enum sss_id_type **type); ++ + #endif /* IPA_389DS_PLUGIN_HELPER_CALLS */ + #endif /* SSS_NSS_IDMAP_H_ */ +diff --git a/src/sss_client/idmap/sss_nss_idmap.unit_tests b/src/sss_client/idmap/sss_nss_idmap.unit_tests +index 361cc3b134ead52cf458afe27c055739d6728441..05c474f008e1d59aae5976acfd81613c3c3e6540 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.unit_tests ++++ b/src/sss_client/idmap/sss_nss_idmap.unit_tests +@@ -2,5 +2,5 @@ + UNIT_TEST_ONLY { + # should not be part of installed library + global: +- sss_nss_make_request; ++ sss_nss_make_request_timeout; + }; +diff --git a/src/tests/cmocka/sss_nss_idmap-tests.c b/src/tests/cmocka/sss_nss_idmap-tests.c +index 8807eca619d7b07d919168e5629042cf38f654ac..2e37040d2d3523bea157804706685fa0b36df16a 100644 +--- a/src/tests/cmocka/sss_nss_idmap-tests.c ++++ b/src/tests/cmocka/sss_nss_idmap-tests.c +@@ -61,10 +61,11 @@ uint8_t buf_orig1[] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0 + #error "unknow endianess" + #endif + +-enum nss_status sss_nss_make_request(enum sss_cli_command cmd, +- struct sss_cli_req_data *rd, +- uint8_t **repbuf, size_t *replen, +- int *errnop) ++enum nss_status sss_nss_make_request_timeout(enum sss_cli_command cmd, ++ struct sss_cli_req_data *rd, ++ int timeout, ++ uint8_t **repbuf, size_t *replen, ++ int *errnop) + { + struct sss_nss_make_request_test_data *d; + +@@ -114,7 +115,7 @@ void test_getsidbyname(void **state) + sid = NULL; + + for (c = 0; d[c].d.repbuf != NULL; c++) { +- will_return(sss_nss_make_request, &d[0].d); ++ will_return(sss_nss_make_request_timeout, &d[0].d); + + ret = sss_nss_getsidbyname("test", &sid, &type); + assert_int_equal(ret, d[0].ret); +@@ -134,7 +135,7 @@ void test_getorigbyname(void **state) + enum sss_id_type type; + struct sss_nss_make_request_test_data d = {buf_orig1, sizeof(buf_orig1), 0, NSS_STATUS_SUCCESS}; + +- will_return(sss_nss_make_request, &d); ++ will_return(sss_nss_make_request_timeout, &d); + ret = sss_nss_getorigbyname("test", &kv_list, &type); + assert_int_equal(ret, EOK); + assert_int_equal(type, SSS_ID_TYPE_UID); +-- +2.13.6 + diff --git a/SOURCES/0031-SECRETS-Store-ccaches-in-secrets-for-the-KCM-respond.patch b/SOURCES/0031-SECRETS-Store-ccaches-in-secrets-for-the-KCM-respond.patch deleted file mode 100644 index 09d388a..0000000 --- a/SOURCES/0031-SECRETS-Store-ccaches-in-secrets-for-the-KCM-respond.patch +++ /dev/null @@ -1,206 +0,0 @@ -From 91c099a993252680f103084431b1d0f5798d8a24 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 21 Mar 2017 14:14:42 +0100 -Subject: [PATCH 31/36] SECRETS: Store ccaches in secrets for the KCM responder -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Adds a new "hive" to the secrets responder whose base path is /kcm. Only -root can contact the /kcm hive, because the KCM responder only runs as -root and it must impersonate other users and store ccaches on their behalf. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/responder/secrets/local.c | 16 +++++++- - src/responder/secrets/providers.c | 71 ++++++++++++++++++++++++++++++---- - src/responder/secrets/secsrv_private.h | 10 ++++- - 3 files changed, 86 insertions(+), 11 deletions(-) - -diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c -index 26c97a2849febbf0ac482d526cf927bfc103b4f2..02007ada8b673071ecba033df0eb3f81af93fcbd 100644 ---- a/src/responder/secrets/local.c -+++ b/src/responder/secrets/local.c -@@ -26,6 +26,9 @@ - - #define MKEY_SIZE (256 / 8) - -+#define SECRETS_BASEDN "cn=secrets" -+#define KCM_BASEDN "cn=kcm" -+ - struct local_context { - struct ldb_context *ldb; - struct sec_data master_key; -@@ -119,6 +122,7 @@ static int local_encrypt(struct local_context *lctx, TALLOC_CTX *mem_ctx, - - static int local_db_dn(TALLOC_CTX *mem_ctx, - struct ldb_context *ldb, -+ const char *basedn, - const char *req_path, - struct ldb_dn **req_dn) - { -@@ -126,7 +130,7 @@ static int local_db_dn(TALLOC_CTX *mem_ctx, - const char *s, *e; - int ret; - -- dn = ldb_dn_new(mem_ctx, ldb, "cn=secrets"); -+ dn = ldb_dn_new(mem_ctx, ldb, basedn); - if (!dn) { - ret = ENOMEM; - goto done; -@@ -738,6 +742,11 @@ static int local_secrets_map_path(TALLOC_CTX *mem_ctx, - lc_req->path = talloc_strdup(lc_req, - secreq->mapped_path + (sizeof(SEC_BASEPATH) - 1)); - basedn = SECRETS_BASEDN; -+ } else if (strncmp(secreq->mapped_path, -+ SEC_KCM_BASEPATH, sizeof(SEC_KCM_BASEPATH) - 1) == 0) { -+ lc_req->path = talloc_strdup(lc_req, -+ secreq->mapped_path + (sizeof(SEC_KCM_BASEPATH) - 1)); -+ basedn = KCM_BASEDN; - } else { - ret = EINVAL; - goto done; -@@ -820,7 +829,10 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, - DEBUG(SSSDBG_TRACE_LIBS, "Content-Type: %s\n", content_type); - - ret = local_secrets_map_path(state, lctx->ldb, secreq, &lc_req); -- if (ret) goto done; -+ if (ret) { -+ DEBUG(SSSDBG_OP_FAILURE, "Cannot map request path to local path\n"); -+ goto done; -+ } - - switch (secreq->method) { - case HTTP_GET: -diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c -index eba555d2e422d08db211979422a2957e48b51589..94831c73036d269addca45c0117811a2c68873fd 100644 ---- a/src/responder/secrets/providers.c -+++ b/src/responder/secrets/providers.c -@@ -24,6 +24,14 @@ - #include "responder/secrets/secsrv_proxy.h" - #include - -+typedef int (*url_mapper_fn)(struct sec_req_ctx *secreq, -+ char **mapped_path); -+ -+struct url_pfx_router { -+ const char *prefix; -+ url_mapper_fn mapper_fn; -+}; -+ - static int sec_map_url_to_user_path(struct sec_req_ctx *secreq, - char **mapped_path) - { -@@ -42,10 +50,43 @@ static int sec_map_url_to_user_path(struct sec_req_ctx *secreq, - return ENOMEM; - } - -- DEBUG(SSSDBG_TRACE_LIBS, "User-specific path is [%s]\n", *mapped_path); -+ DEBUG(SSSDBG_TRACE_LIBS, -+ "User-specific secrets path is [%s]\n", *mapped_path); - return EOK; - } - -+static int kcm_map_url_to_path(struct sec_req_ctx *secreq, -+ char **mapped_path) -+{ -+ uid_t c_euid; -+ -+ c_euid = client_euid(secreq->cctx->creds); -+ if (c_euid != KCM_PEER_UID) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "UID %"SPRIuid" is not allowed to access " -+ "the "SEC_KCM_BASEPATH" hive\n", -+ c_euid); -+ return EPERM; -+ } -+ -+ *mapped_path = talloc_strdup(secreq, secreq->parsed_url.path ); -+ if (!*mapped_path) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to map request to user specific url\n"); -+ return ENOMEM; -+ } -+ -+ DEBUG(SSSDBG_TRACE_LIBS, -+ "User-specific KCM path is [%s]\n", *mapped_path); -+ return EOK; -+} -+ -+static struct url_pfx_router secrets_url_mapping[] = { -+ { SEC_BASEPATH, sec_map_url_to_user_path }, -+ { SEC_KCM_BASEPATH, kcm_map_url_to_path }, -+ { NULL, NULL }, -+}; -+ - int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, - struct provider_handle **handle) - { -@@ -55,21 +96,35 @@ int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, - char *provider; - int num_sections; - int ret; -+ url_mapper_fn mapper_fn = NULL; - - sctx = talloc_get_type(secreq->cctx->rctx->pvt_ctx, struct sec_ctx); - -- /* patch must start with /secrets/ for now */ -- ret = strncasecmp(secreq->parsed_url.path, -- SEC_BASEPATH, sizeof(SEC_BASEPATH) - 1); -- if (ret != 0) { -+ for (int i = 0; secrets_url_mapping[i].prefix != NULL; i++) { -+ if (strncasecmp(secreq->parsed_url.path, -+ secrets_url_mapping[i].prefix, -+ strlen(secrets_url_mapping[i].prefix)) == 0) { -+ DEBUG(SSSDBG_TRACE_LIBS, -+ "Mapping prefix %s\n", secrets_url_mapping[i].prefix); -+ mapper_fn = secrets_url_mapping[i].mapper_fn; -+ break; -+ } -+ } -+ -+ if (mapper_fn == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, -- "Path [%s] does not start with "SEC_BASEPATH"\n", -+ "Path [%s] does not start with any allowed prefix\n", - secreq->parsed_url.path); - return EPERM; - } - -- ret = sec_map_url_to_user_path(secreq, &secreq->mapped_path); -- if (ret) return ret; -+ ret = mapper_fn(secreq, &secreq->mapped_path); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to map the user path [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return ret; -+ } - - /* source default provider */ - ret = confdb_get_string(secreq->cctx->rctx->cdb, mem_ctx, -diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h -index 1c3fbd8eadb237551233f048503ddc01b4ba00ae..a8544f656517a17fe4576247779bff4850beaf97 100644 ---- a/src/responder/secrets/secsrv_private.h -+++ b/src/responder/secrets/secsrv_private.h -@@ -101,7 +101,15 @@ int sec_get_provider(struct sec_ctx *sctx, const char *name, - struct provider_handle **out_handle); - int sec_add_provider(struct sec_ctx *sctx, struct provider_handle *handle); - --#define SEC_BASEPATH "/secrets/" -+#define SEC_BASEPATH "/secrets/" -+#define SEC_KCM_BASEPATH "/kcm/" -+ -+/* The KCM responder must "impersonate" the owner of the credentials. -+ * Only a trusted UID can do that -- root by default, but unit -+ * tests might choose otherwise */ -+#ifndef KCM_PEER_UID -+#define KCM_PEER_UID 0 -+#endif /* KCM_PEER_UID */ - - /* providers.c */ - int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, --- -2.9.3 - diff --git a/SOURCES/0031-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch b/SOURCES/0031-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch new file mode 100644 index 0000000..7724a87 --- /dev/null +++ b/SOURCES/0031-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch @@ -0,0 +1,184 @@ +From 464a19ecef7c4a0aad22cd9d2c7b2364e3680351 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 2 Nov 2017 11:09:20 +0100 +Subject: [PATCH 31/31] nss-idmap: allow empty buffer with + SSS_NSS_EX_FLAG_INVALIDATE_CACHE + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 859bddc2bf51dc426a3dc56bd9f365e9c5722b65) +--- + src/sss_client/idmap/sss_nss_ex.c | 89 ++++++++++++++++++++++++++------------- + 1 file changed, 60 insertions(+), 29 deletions(-) + +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +index 148eb7b35ec236b6272dd203a0035399cfdef73d..dcd9619a8b07ced7498f61b7e809fa46ebffe09e 100644 +--- a/src/sss_client/idmap/sss_nss_ex.c ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -103,8 +103,11 @@ errno_t sss_nss_mc_get(struct nss_input *inp) + } + } + +-static int check_flags(uint32_t flags) ++static int check_flags(struct nss_input *inp, uint32_t flags, ++ bool *skip_mc, bool *skip_data) + { ++ bool no_data = false; ++ + /* SSS_NSS_EX_FLAG_NO_CACHE and SSS_NSS_EX_FLAG_INVALIDATE_CACHE are + * mutually exclusive */ + if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 +@@ -112,6 +115,52 @@ static int check_flags(uint32_t flags) + return EINVAL; + } + ++ *skip_mc = false; ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 ++ || (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ *skip_mc = true; ++ } ++ ++ switch(inp->cmd) { ++ case SSS_NSS_GETPWNAM: ++ case SSS_NSS_GETPWNAM_EX: ++ case SSS_NSS_GETPWUID: ++ case SSS_NSS_GETPWUID_EX: ++ if (inp->result.pwrep.buffer == NULL ++ || inp->result.pwrep.buflen == 0) { ++ no_data = true; ++ } ++ break; ++ case SSS_NSS_GETGRNAM: ++ case SSS_NSS_GETGRNAM_EX: ++ case SSS_NSS_GETGRGID: ++ case SSS_NSS_GETGRGID_EX: ++ if (inp->result.grrep.buffer == NULL ++ || inp->result.grrep.buflen == 0) { ++ no_data = true; ++ } ++ break; ++ case SSS_NSS_INITGR: ++ case SSS_NSS_INITGR_EX: ++ if (inp->result.initgrrep.ngroups == 0 ++ || inp->result.initgrrep.groups == NULL) { ++ return EINVAL; ++ } ++ break; ++ default: ++ return EINVAL; ++ } ++ ++ *skip_data = false; ++ /* Allow empty buffer with SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ if (no_data) { ++ if ((flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ *skip_data = true; ++ } else { ++ return ERANGE; ++ } ++ } ++ + return 0; + } + +@@ -128,18 +177,14 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + gid_t *new_groups; + size_t idx; + bool skip_mc = false; ++ bool skip_data = false; + +- ret = check_flags(flags); ++ ret = check_flags(inp, flags, &skip_mc, &skip_data); + if (ret != 0) { + return ret; + } + +- if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 +- || (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { +- skip_mc = true; +- } +- +- if (!skip_mc) { ++ if (!skip_mc && !skip_data) { + ret = sss_nss_mc_get(inp); + switch (ret) { + case 0: +@@ -159,7 +204,7 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + + sss_nss_timedlock(timeout, &time_left); + +- if (!skip_mc) { ++ if (!skip_mc && !skip_data) { + /* previous thread might already initialize entry in mmap cache */ + ret = sss_nss_mc_get(inp); + switch (ret) { +@@ -196,6 +241,12 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + goto out; + } + ++ if (skip_data) { ++ /* No data requested, just return the return code */ ++ ret = 0; ++ goto out; ++ } ++ + if (inp->cmd == SSS_NSS_INITGR || inp->cmd == SSS_NSS_INITGR_EX) { + if ((*(inp->result.initgrrep.ngroups) - *(inp->result.initgrrep.start)) + < num_results) { +@@ -311,10 +362,6 @@ int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, + .result.pwrep.buffer = buffer, + .result.pwrep.buflen = buflen}; + +- if (buffer == NULL || buflen == 0) { +- return ERANGE; +- } +- + ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { + return ret; +@@ -346,10 +393,6 @@ int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd, + .result.pwrep.buffer = buffer, + .result.pwrep.buflen = buflen}; + +- if (buffer == NULL || buflen == 0) { +- return ERANGE; +- } +- + SAFEALIGN_COPY_UINT32(&req_data[0], &uid, NULL); + SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL); + *result = NULL; +@@ -373,10 +416,6 @@ int sss_nss_getgrnam_timeout(const char *name, struct group *grp, + .result.grrep.buffer = buffer, + .result.grrep.buflen = buflen}; + +- if (buffer == NULL || buflen == 0) { +- return ERANGE; +- } +- + ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { + return ret; +@@ -407,10 +446,6 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, + .result.grrep.buffer = buffer, + .result.grrep.buflen = buflen}; + +- if (buffer == NULL || buflen == 0) { +- return ERANGE; +- } +- + SAFEALIGN_COPY_UINT32(&req_data[0], &gid, NULL); + SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL); + *result = NULL; +@@ -434,10 +469,6 @@ int sss_nss_getgrouplist_timeout(const char *name, gid_t group, + .input.name = name, + .cmd = SSS_NSS_INITGR_EX}; + +- if (groups == NULL || ngroups == NULL || *ngroups == 0) { +- return EINVAL; +- } +- + ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { + return ret; +-- +2.13.6 + diff --git a/SOURCES/0032-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch b/SOURCES/0032-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch new file mode 100644 index 0000000..be96f01 --- /dev/null +++ b/SOURCES/0032-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch @@ -0,0 +1,51 @@ +From 1925a1bb1e0ea210bd40ec3374726948fb6e4760 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 7 Nov 2017 17:11:52 +0100 +Subject: [PATCH 32/35] BUILD: Properly expand variables in sssd-ifp.service +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +systemd[1]: [/usr/lib/systemd/system/sssd-ifp.service:9] + Path '-@environment_file@' is not absolute, ignoring. + +sh-4.2# systemctl cat sssd-ifp.service + # /usr/lib/systemd/system/sssd-ifp.service +[Unit] +Description=SSSD IFP Service responder +Documentation=man:sssd-ifp(5) +After=sssd.service +BindsTo=sssd.service + +[Service] +Environment=DEBUG_LOGGER=--logger=files +EnvironmentFile=-@environment_file@ +Type=dbus +BusName=org.freedesktop.sssd.infopipe +ExecStart=/usr/libexec/sssd/sssd_ifp --uid 0 --gid 0 --dbus-activated ${DEBUG_LOGGER} + +Resolves: +https://pagure.io/SSSD/sssd/issue/3433 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit b495522f3eadde9ad4bb8d125fd70b0d5f07596a) +--- + Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index 286ba47e3c421864362717be5258de960efca9f2..bbc90d9bad4d22ca0284ea95281a487d42399c05 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1491,7 +1491,7 @@ EXTRA_DIST += \ + src/responder/ifp/org.freedesktop.sssd.infopipe.service.in \ + $(NULL) + +-ifp_edit_cmd = $(SED) \ ++ifp_edit_cmd = $(edit_cmd) \ + -e 's|@ifp_exec_cmd[@]|$(ifp_exec_cmd)|g' \ + -e 's|@ifp_systemdservice[@]|$(ifp_systemdservice)|g' \ + -e 's|@ifp_restart[@]|$(ifp_restart)|g' +-- +2.13.6 + diff --git a/SOURCES/0032-TCURL-Support-HTTP-POST-for-creating-containers.patch b/SOURCES/0032-TCURL-Support-HTTP-POST-for-creating-containers.patch deleted file mode 100644 index c94fe07..0000000 --- a/SOURCES/0032-TCURL-Support-HTTP-POST-for-creating-containers.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 2777ccdcc9038d8f62be81a24ae885639fe6ea9a Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 14 Mar 2017 15:34:57 +0100 -Subject: [PATCH 32/36] TCURL: Support HTTP POST for creating containers -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The curl integration must allow us to create containers, therefore we -also add support of the POST HTTP request type. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/tests/intg/test_secrets.py | 28 ++++++++++++++++++++++++++++ - src/tests/tcurl_test_tool.c | 5 +++++ - src/util/tev_curl.c | 7 +++++++ - src/util/tev_curl.h | 1 + - 4 files changed, 41 insertions(+) - -diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py -index cbc1a1f06d2abb826bc0a880cb5a842f577657ea..d71c1904558cc6f8a6eee36c4049582705bc30ac 100644 ---- a/src/tests/intg/test_secrets.py -+++ b/src/tests/intg/test_secrets.py -@@ -271,6 +271,34 @@ def test_curlwrap_crd_ops(setup_for_secrets, - 'http://localhost/secrets/foo'], - 404) - -+ # Create a container -+ run_curlwrap_tool([curlwrap_tool, '-o', -+ '-v', '-s', sock_path, -+ 'http://localhost/secrets/cont/'], -+ 200) -+ -+ # set a secret foo:bar -+ run_curlwrap_tool([curlwrap_tool, '-p', -+ '-v', '-s', sock_path, -+ 'http://localhost/secrets/cont/cfoo', -+ 'foo_under_cont'], -+ 200) -+ -+ # list secrets -+ output = run_curlwrap_tool([curlwrap_tool, -+ '-v', '-s', sock_path, -+ 'http://localhost/secrets/cont/'], -+ 200) -+ assert "cfoo" in output -+ -+ # get the foo secret -+ output = run_curlwrap_tool([curlwrap_tool, -+ '-v', '-s', sock_path, -+ 'http://localhost/secrets/cont/cfoo'], -+ 200) -+ assert "foo_under_cont" in output -+ -+ - - def test_curlwrap_parallel(setup_for_secrets, - curlwrap_tool): -diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c -index 38cea432885c97ca3827c8f158bf7e3ebfc67b31..2af950ebb76a22bdf4a6dfd58442b10486e64293 100644 ---- a/src/tests/tcurl_test_tool.c -+++ b/src/tests/tcurl_test_tool.c -@@ -88,6 +88,7 @@ int main(int argc, const char *argv[]) - { "get", 'g', POPT_ARG_NONE, NULL, 'g', "Perform a HTTP GET (default)", NULL }, - { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, - { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, -+ { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, - { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Print response code and body", NULL }, - POPT_TABLEEND - }; -@@ -118,6 +119,9 @@ int main(int argc, const char *argv[]) - case 'd': - req_type = TCURL_HTTP_DELETE; - break; -+ case 'o': -+ req_type = TCURL_HTTP_POST; -+ break; - case 'v': - pc_verbose = 1; - break; -@@ -145,6 +149,7 @@ int main(int argc, const char *argv[]) - switch (req_type) { - case TCURL_HTTP_GET: - case TCURL_HTTP_DELETE: -+ case TCURL_HTTP_POST: - urls[n_reqs++] = extra_arg_ptr; - break; - case TCURL_HTTP_PUT: -diff --git a/src/util/tev_curl.c b/src/util/tev_curl.c -index fd436653b5aeb611a9648a8b81a330fd3fcfe875..645d1182d10f825f209f48e0ba7e6804dde1971c 100644 ---- a/src/util/tev_curl.c -+++ b/src/util/tev_curl.c -@@ -154,6 +154,8 @@ static const char *http_req2str(enum tcurl_http_request req) - return "PUT"; - case TCURL_HTTP_DELETE: - return "DELETE"; -+ case TCURL_HTTP_POST: -+ return "POST"; - } - - return "Uknown request type"; -@@ -815,6 +817,11 @@ static errno_t tcurl_set_options(struct tcurl_http_state *state, - } - - switch (req_type) { -+ case TCURL_HTTP_POST: -+ crv = curl_easy_setopt(state->http_handle, -+ CURLOPT_CUSTOMREQUEST, -+ "POST"); -+ break; - case TCURL_HTTP_PUT: - /* CURLOPT_UPLOAD enables HTTP_PUT */ - crv = curl_easy_setopt(state->http_handle, -diff --git a/src/util/tev_curl.h b/src/util/tev_curl.h -index de0601df4327d97001a8a825cd4709936f6c8466..444eb286e09d189b4588e2b2152b5202df3914d8 100644 ---- a/src/util/tev_curl.h -+++ b/src/util/tev_curl.h -@@ -34,6 +34,7 @@ enum tcurl_http_request { - TCURL_HTTP_GET, - TCURL_HTTP_PUT, - TCURL_HTTP_DELETE, -+ TCURL_HTTP_POST, - }; - - /** --- -2.9.3 - diff --git a/SOURCES/0033-KCM-Store-ccaches-in-secrets.patch b/SOURCES/0033-KCM-Store-ccaches-in-secrets.patch deleted file mode 100644 index d08a786..0000000 --- a/SOURCES/0033-KCM-Store-ccaches-in-secrets.patch +++ /dev/null @@ -1,3787 +0,0 @@ -From 8c30024303436d98818977288e28511ed74c018a Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 20 Mar 2017 11:49:43 +0100 -Subject: [PATCH 33/36] KCM: Store ccaches in secrets -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Adds a new KCM responder ccache back end that forwards all requests to -sssd-secrets. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - Makefile.am | 40 +- - contrib/sssd.spec.in | 1 + - src/responder/kcm/kcmsrv_ccache.h | 49 + - src/responder/kcm/kcmsrv_ccache_json.c | 921 +++++++++++ - src/responder/kcm/kcmsrv_ccache_secrets.c | 2169 ++++++++++++++++++++++++++ - src/tests/cmocka/test_kcm_json_marshalling.c | 234 +++ - src/tests/intg/test_kcm.py | 132 +- - src/util/util_errors.c | 2 + - src/util/util_errors.h | 2 + - 9 files changed, 3525 insertions(+), 25 deletions(-) - create mode 100644 src/responder/kcm/kcmsrv_ccache_json.c - create mode 100644 src/responder/kcm/kcmsrv_ccache_secrets.c - create mode 100644 src/tests/cmocka/test_kcm_json_marshalling.c - -diff --git a/Makefile.am b/Makefile.am -index 49b4cabf9ee3ce1417f955c972376894f3709b33..e9eaa312c91e3aee40bcf13c90a0ad8c683045d5 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -303,6 +303,10 @@ if HAVE_INOTIFY - non_interactive_cmocka_based_tests += test_inotify - endif # HAVE_INOTIFY - -+if BUILD_KCM -+non_interactive_cmocka_based_tests += test_kcm_json -+endif # BUILD_KCM -+ - if BUILD_SAMBA - non_interactive_cmocka_based_tests += \ - ad_access_filter_tests \ -@@ -1494,19 +1498,26 @@ sssd_kcm_SOURCES = \ - src/responder/kcm/kcmsrv_cmd.c \ - src/responder/kcm/kcmsrv_ccache.c \ - src/responder/kcm/kcmsrv_ccache_mem.c \ -+ src/responder/kcm/kcmsrv_ccache_json.c \ -+ src/responder/kcm/kcmsrv_ccache_secrets.c \ - src/responder/kcm/kcmsrv_ops.c \ - src/util/sss_sockets.c \ - src/util/sss_krb5.c \ - src/util/sss_iobuf.c \ -+ src/util/tev_curl.c \ - $(SSSD_RESPONDER_OBJ) \ - $(NULL) - sssd_kcm_CFLAGS = \ - $(AM_CFLAGS) \ - $(KRB5_CFLAGS) \ - $(UUID_CFLAGS) \ -+ $(CURL_CFLAGS) \ -+ $(JANSSON_CFLAGS) \ - $(NULL) - sssd_kcm_LDADD = \ - $(KRB5_LIBS) \ -+ $(CURL_LIBS) \ -+ $(JANSSON_LIBS) \ - $(SSSD_LIBS) \ - $(UUID_LIBS) \ - $(SYSTEMD_DAEMON_LIBS) \ -@@ -3369,6 +3380,30 @@ sss_certmap_test_LDADD = \ - libsss_certmap.la \ - $(NULL) - endif -+ -+if BUILD_KCM -+test_kcm_json_SOURCES = \ -+ src/tests/cmocka/test_kcm_json_marshalling.c \ -+ src/responder/kcm/kcmsrv_ccache_json.c \ -+ src/responder/kcm/kcmsrv_ccache.c \ -+ src/util/sss_krb5.c \ -+ src/util/sss_iobuf.c \ -+ $(NULL) -+test_kcm_json_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(UUID_CFLAGS) \ -+ $(NULL) -+test_kcm_json_LDADD = \ -+ $(JANSSON_LIBS) \ -+ $(UUID_LIBS) \ -+ $(KRB5_LIBS) \ -+ $(CMOCKA_LIBS) \ -+ $(SSSD_LIBS) \ -+ $(SSSD_INTERNAL_LTLIBS) \ -+ libsss_test_common.la \ -+ $(NULL) -+endif # BUILD_KCM -+ - endif # HAVE_CMOCKA - - noinst_PROGRAMS = pam_test_client -@@ -3431,8 +3466,9 @@ intgcheck-prepare: - --enable-intgcheck-reqs \ - --without-semanage \ - --enable-files-domain \ -- $(INTGCHECK_CONFIGURE_FLAGS); \ -- $(MAKE) $(AM_MAKEFLAGS); \ -+ $(INTGCHECK_CONFIGURE_FLAGS) \ -+ CFLAGS="$$CFLAGS $(AM_CFLAGS) -DKCM_PEER_UID=$$(id -u)"; \ -+ $(MAKE) $(AM_MAKEFLAGS) ; \ - : Force single-thread install to workaround concurrency issues; \ - $(MAKE) $(AM_MAKEFLAGS) -j1 install; \ - : Remove .la files from LDB module directory to avoid loader warnings; \ -diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in -index 1d4d020415ee28292bb4d88c78de205465d812f1..af14d4e3d6b9ffeb4696f1517113b8daa575cb99 100644 ---- a/contrib/sssd.spec.in -+++ b/contrib/sssd.spec.in -@@ -223,6 +223,7 @@ BuildRequires: systemtap-sdt-devel - BuildRequires: http-parser-devel - BuildRequires: jansson-devel - BuildRequires: libuuid-devel -+BuildRequires: libcurl-devel - - %description - Provides a set of daemons to manage access to remote directories and -diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h -index 130ae48ae30d5e1e2ab238a647a9b9dc76cc4945..18c8c47ad4ecb24521a85a1833b239c7a2a8bb45 100644 ---- a/src/responder/kcm/kcmsrv_ccache.h -+++ b/src/responder/kcm/kcmsrv_ccache.h -@@ -303,4 +303,53 @@ void kcm_debug_uuid(uuid_t uuid); - */ - errno_t kcm_check_name(const char *name, struct cli_creds *client); - -+/* -+ * ccahe marshalling to and from JSON. This is used when the ccaches -+ * are stored in the secrets store -+ */ -+ -+/* -+ * The secrets store is a key-value store at heart. We store the UUID -+ * and the name in the key to allow easy lookups be either key -+ */ -+bool sec_key_match_name(const char *sec_key, -+ const char *name); -+ -+bool sec_key_match_uuid(const char *sec_key, -+ uuid_t uuid); -+ -+const char *sec_key_get_name(const char *sec_key); -+ -+errno_t sec_key_get_uuid(const char *sec_key, -+ uuid_t uuid); -+ -+/* Create a URL for the default client's ccache */ -+const char *sec_dfl_url_create(TALLOC_CTX *mem_ctx, -+ struct cli_creds *client); -+ -+/* Create a URL for the client's ccache container */ -+const char *sec_container_url_create(TALLOC_CTX *mem_ctx, -+ struct cli_creds *client); -+ -+const char *sec_cc_url_create(TALLOC_CTX *mem_ctx, -+ struct cli_creds *client, -+ const char *sec_key); -+ -+/* -+ * sec_key is a concatenation of the ccache's UUID and name -+ * sec_value is the JSON dump of the ccache contents -+ */ -+errno_t sec_kv_to_ccache(TALLOC_CTX *mem_ctx, -+ const char *sec_key, -+ const char *sec_value, -+ struct cli_creds *client, -+ struct kcm_ccache **_cc); -+ -+/* Convert a kcm_ccache to a key-value pair to be stored in secrets */ -+errno_t kcm_ccache_to_sec_input(TALLOC_CTX *mem_ctx, -+ struct kcm_ccache *cc, -+ struct cli_creds *client, -+ const char **_url, -+ struct sss_iobuf **_payload); -+ - #endif /* _KCMSRV_CCACHE_H_ */ -diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c -new file mode 100644 -index 0000000000000000000000000000000000000000..40b64861c209206d6f60ccd0843857edee24a844 ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_ccache_json.c -@@ -0,0 +1,921 @@ -+/* -+ SSSD -+ -+ KCM Server - ccache JSON (un)marshalling for storing ccaches in -+ sssd-secrets -+ -+ Copyright (C) Red Hat, 2017 -+ -+ 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 "config.h" -+ -+#include -+#include -+#include -+ -+#include "util/util.h" -+#include "util/util_creds.h" -+#include "util/crypto/sss_crypto.h" -+#include "responder/kcm/kcmsrv_ccache_pvt.h" -+ -+/* The base for storing secrets is: -+ * http://localhost/kcm/persistent/$uid -+ * -+ * Under $base, there are two containers: -+ * /ccache - stores the ccaches -+ * /ntlm - stores NTLM creds [Not implement yet] -+ * -+ * There is also a special entry that contains the UUID of the default -+ * cache for this UID: -+ * /default - stores the UUID of the default ccache for this UID -+ * -+ * Each ccache has a name and an UUID. On the secrets level, the 'secret' -+ * is a concatenation of the stringified UUID and the name separated -+ * by a plus-sign. -+ */ -+#define KCM_SEC_URL "http://localhost/kcm/persistent" -+#define KCM_SEC_BASE_FMT KCM_SEC_URL"/%"SPRIuid"/" -+#define KCM_SEC_CCACHE_FMT KCM_SEC_BASE_FMT"ccache/" -+#define KCM_SEC_DFL_FMT KCM_SEC_BASE_FMT"default" -+ -+ -+/* -+ * We keep the JSON representation of the ccache versioned to allow -+ * us to modify the format in a future version -+ */ -+#define KS_JSON_VERSION 1 -+ -+/* -+ * The secrets store is a key-value store at heart. We store the UUID -+ * and the name in the key to allow easy lookups be either key -+ */ -+#define SEC_KEY_SEPARATOR '-' -+ -+/* Compat definition of json_array_foreach for older systems */ -+#ifndef json_array_foreach -+#define json_array_foreach(array, idx, value) \ -+ for(idx = 0; \ -+ idx < json_array_size(array) && (value = json_array_get(array, idx)); \ -+ idx++) -+#endif -+ -+const char *sec_container_url_create(TALLOC_CTX *mem_ctx, -+ struct cli_creds *client) -+{ -+ return talloc_asprintf(mem_ctx, -+ KCM_SEC_CCACHE_FMT, -+ cli_creds_get_uid(client)); -+} -+ -+const char *sec_cc_url_create(TALLOC_CTX *mem_ctx, -+ struct cli_creds *client, -+ const char *sec_key) -+{ -+ return talloc_asprintf(mem_ctx, -+ KCM_SEC_CCACHE_FMT"%s", -+ cli_creds_get_uid(client), -+ sec_key); -+} -+ -+const char *sec_dfl_url_create(TALLOC_CTX *mem_ctx, -+ struct cli_creds *client) -+{ -+ return talloc_asprintf(mem_ctx, -+ KCM_SEC_DFL_FMT, -+ cli_creds_get_uid(client)); -+} -+ -+static const char *sec_key_create(TALLOC_CTX *mem_ctx, -+ const char *name, -+ uuid_t uuid) -+{ -+ char uuid_str[UUID_STR_SIZE]; -+ -+ uuid_unparse(uuid, uuid_str); -+ return talloc_asprintf(mem_ctx, -+ "%s%c%s", uuid_str, SEC_KEY_SEPARATOR, name); -+} -+ -+static errno_t sec_key_parse(TALLOC_CTX *mem_ctx, -+ const char *sec_key, -+ const char **_name, -+ uuid_t uuid) -+{ -+ char uuid_str[UUID_STR_SIZE]; -+ -+ if (strlen(sec_key) < UUID_STR_SIZE + 2) { -+ /* One char for separator and at least one for the name */ -+ DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); -+ return EINVAL; -+ } -+ -+ strncpy(uuid_str, sec_key, sizeof(uuid_str)-1); -+ if (sec_key[UUID_STR_SIZE - 1] != SEC_KEY_SEPARATOR) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n"); -+ return EINVAL; -+ } -+ uuid_str[UUID_STR_SIZE-1] = '\0'; -+ -+ *_name = talloc_strdup(mem_ctx, sec_key + UUID_STR_SIZE); -+ if (*_name == NULL) { -+ return ENOMEM; -+ } -+ uuid_parse(uuid_str, uuid); -+ -+ return EOK; -+} -+ -+errno_t sec_key_get_uuid(const char *sec_key, -+ uuid_t uuid) -+{ -+ char uuid_str[UUID_STR_SIZE]; -+ -+ if (strlen(sec_key) < UUID_STR_SIZE + 2) { -+ /* One char for separator and at least one for the name */ -+ DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); -+ return EINVAL; -+ } -+ -+ if (sec_key[UUID_STR_SIZE-1] != SEC_KEY_SEPARATOR) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n"); -+ return EINVAL; -+ } -+ -+ strncpy(uuid_str, sec_key, UUID_STR_SIZE-1); -+ uuid_str[UUID_STR_SIZE-1] = '\0'; -+ uuid_parse(uuid_str, uuid); -+ return EOK; -+} -+ -+const char *sec_key_get_name(const char *sec_key) -+{ -+ if (strlen(sec_key) < UUID_STR_SIZE + 2) { -+ /* One char for separator and at least one for the name */ -+ DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); -+ return NULL; -+ } -+ -+ return sec_key + UUID_STR_SIZE; -+} -+ -+bool sec_key_match_name(const char *sec_key, -+ const char *name) -+{ -+ if (strlen(sec_key) < UUID_STR_SIZE + 2) { -+ /* One char for separator and at least one for the name */ -+ DEBUG(SSSDBG_MINOR_FAILURE, "Key %s is too short\n", sec_key); -+ return false; -+ } -+ -+ return strcmp(sec_key + UUID_STR_SIZE, name) == 0; -+} -+ -+bool sec_key_match_uuid(const char *sec_key, -+ uuid_t uuid) -+{ -+ errno_t ret; -+ uuid_t key_uuid; -+ -+ ret = sec_key_get_uuid(sec_key, key_uuid); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot convert key to UUID\n"); -+ return false; -+ } -+ -+ return uuid_compare(key_uuid, uuid) == 0; -+} -+ -+/* -+ * Creates an array of principal elements that will be used later -+ * in the form of: -+ * "componenets": [ "elem1", "elem2", ...] -+ */ -+static json_t *princ_data_to_json(TALLOC_CTX *mem_ctx, -+ krb5_principal princ) -+{ -+ json_t *jdata = NULL; -+ json_t *data_array = NULL; -+ int ret; -+ char *str_princ_data; -+ -+ data_array = json_array(); -+ if (data_array == NULL) { -+ return NULL; -+ } -+ -+ for (ssize_t i = 0; i < princ->length; i++) { -+ /* FIXME - it might be cleaner to use stringn here, but the libjansson -+ * version on RHEL-7 doesn't support that -+ */ -+ str_princ_data = talloc_zero_array(mem_ctx, -+ char, -+ princ->data[i].length + 1); -+ if (str_princ_data == NULL) { -+ return NULL; -+ } -+ memcpy(str_princ_data, princ->data[i].data, princ->data[i].length); -+ str_princ_data[princ->data[i].length] = '\0'; -+ -+ jdata = json_string(str_princ_data); -+ talloc_free(str_princ_data); -+ if (jdata == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert principal data to string\n"); -+ json_decref(data_array); -+ return NULL; -+ } -+ -+ ret = json_array_append_new(data_array, jdata); -+ if (ret != 0) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot append principal data to array\n"); -+ json_decref(jdata); -+ json_decref(data_array); -+ return NULL; -+ } -+ /* data_array now owns the reference to jdata */ -+ } -+ -+ return data_array; -+} -+ -+/* Creates: -+ * { -+ * "type": "number", -+ * "realm": "string", -+ * "componenents": [ "elem1", "elem2", ...] -+ * } -+ */ -+static json_t *princ_to_json(TALLOC_CTX *mem_ctx, -+ krb5_principal princ) -+{ -+ json_t *jprinc = NULL; -+ json_t *components = NULL; -+ json_error_t error; -+ char *str_realm_data; -+ -+ components = princ_data_to_json(mem_ctx, princ); -+ if (components == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert principal data to JSON\n"); -+ return NULL; -+ } -+ -+ /* FIXME - it might be cleaner to use the s% specifier here, but the libjansson -+ * version on RHEL-7 doesn't support that -+ */ -+ str_realm_data = talloc_zero_array(mem_ctx, -+ char, -+ princ->realm.length + 1); -+ if (str_realm_data == NULL) { -+ return NULL; -+ } -+ memcpy(str_realm_data, princ->realm.data, princ->realm.length); -+ str_realm_data[princ->realm.length] = '\0'; -+ -+ jprinc = json_pack_ex(&error, -+ JSON_STRICT, -+ "{s:i, s:s, s:o}", -+ "type", princ->type, -+ "realm", str_realm_data, -+ "components", components); -+ talloc_free(str_realm_data); -+ if (jprinc == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to pack JSON princ structure on line %d: %s\n", -+ error.line, error.text); -+ json_decref(components); -+ return NULL; -+ } -+ -+ return jprinc; -+} -+ -+/* Creates: -+ * { -+ * "uuid": , -+ * "payload": , -+ * }, -+ */ -+static json_t *cred_to_json(struct kcm_cred *crd) -+{ -+ char uuid_str[UUID_STR_SIZE]; -+ uint8_t *cred_blob_data; -+ size_t cred_blob_size; -+ json_t *jcred; -+ json_error_t error; -+ char *base64_cred_blob; -+ -+ uuid_unparse(crd->uuid, uuid_str); -+ cred_blob_data = sss_iobuf_get_data(crd->cred_blob); -+ cred_blob_size = sss_iobuf_get_size(crd->cred_blob); -+ -+ base64_cred_blob = sss_base64_encode(crd, cred_blob_data, cred_blob_size); -+ if (base64_cred_blob == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot base64 encode the certificate blob\n"); -+ return NULL; -+ } -+ -+ jcred = json_pack_ex(&error, -+ JSON_STRICT, -+ "{s:s, s:s}", -+ "uuid", uuid_str, -+ "payload", base64_cred_blob); -+ talloc_free(base64_cred_blob); -+ if (jcred == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to pack JSON cred structure on line %d: %s\n", -+ error.line, error.text); -+ return NULL; -+ } -+ return jcred; -+} -+ -+/* -+ * Creates: -+ * [ -+ * { -+ * "uuid": , -+ * "payload": , -+ * }, -+ * ... -+ * ] -+ */ -+static json_t *creds_to_json_array(struct kcm_cred *creds) -+{ -+ struct kcm_cred *crd; -+ json_t *array; -+ json_t *jcred; -+ -+ array = json_array(); -+ if (array == NULL) { -+ return NULL; -+ } -+ -+ DLIST_FOR_EACH(crd, creds) { -+ jcred = cred_to_json(crd); -+ if (jcred == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert credentials to JSON\n"); -+ json_decref(array); -+ return NULL; -+ } -+ -+ json_array_append_new(array, jcred); -+ /* array now owns jcred */ -+ jcred = NULL; -+ } -+ -+ return array; -+} -+ -+/* -+ * The ccache is formatted in JSON as: -+ * { -+ * version: number -+ * kdc_offset: number -+ * principal : { -+ * "type": "number", -+ * "realm": "string", -+ * "componenents": [ "elem1", "elem2", ...] -+ * } -+ * creds : [ -+ * { -+ * "uuid": , -+ * "payload": , -+ * }, -+ * { -+ * ... -+ * } -+ * ] -+ * } -+ * } -+ */ -+static json_t *ccache_to_json(struct kcm_ccache *cc) -+{ -+ json_t *princ = NULL; -+ json_t *creds = NULL; -+ json_t *jcc = NULL; -+ json_error_t error; -+ -+ princ = princ_to_json(cc, cc->client); -+ if (princ == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert princ to JSON\n"); -+ return NULL; -+ } -+ -+ creds = creds_to_json_array(cc->creds); -+ if (creds == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert creds to JSON array\n"); -+ json_decref(princ); -+ return NULL; -+ } -+ -+ jcc = json_pack_ex(&error, -+ JSON_STRICT, -+ "{s:i, s:i, s:o, s:o}", -+ "version", KS_JSON_VERSION, -+ "kdc_offset", cc->kdc_offset, -+ "principal", princ, -+ "creds", creds); -+ if (jcc == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to pack JSON ccache structure on line %d: %s\n", -+ error.line, error.text); -+ json_decref(creds); -+ json_decref(princ); -+ return NULL; -+ } -+ -+ return jcc; -+} -+ -+static errno_t ccache_to_sec_kv(TALLOC_CTX *mem_ctx, -+ struct kcm_ccache *cc, -+ const char **_sec_key, -+ const char **_sec_value) -+{ -+ json_t *jcc = NULL; -+ char *jdump; -+ -+ jcc = ccache_to_json(cc); -+ if (jcc == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert ccache to JSON\n"); -+ return ERR_JSON_ENCODING; -+ } -+ -+ /* it would be more efficient to learn the size with json_dumpb and -+ * a NULL buffer, but that's only available since 2.10 -+ */ -+ jdump = json_dumps(jcc, JSON_INDENT(4) | JSON_ENSURE_ASCII); -+ if (jdump == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot dump JSON\n"); -+ return ERR_JSON_ENCODING; -+ } -+ -+ *_sec_key = sec_key_create(mem_ctx, cc->name, cc->uuid); -+ *_sec_value = talloc_strdup(mem_ctx, jdump); -+ free(jdump); -+ json_decref(jcc); -+ if (*_sec_key == NULL || *_sec_value == NULL) { -+ return ENOMEM; -+ } -+ -+ return EOK; -+} -+ -+errno_t kcm_ccache_to_sec_input(TALLOC_CTX *mem_ctx, -+ struct kcm_ccache *cc, -+ struct cli_creds *client, -+ const char **_url, -+ struct sss_iobuf **_payload) -+{ -+ errno_t ret; -+ const char *key; -+ const char *value; -+ const char *url; -+ struct sss_iobuf *payload; -+ TALLOC_CTX *tmp_ctx; -+ -+ tmp_ctx = talloc_new(mem_ctx); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = ccache_to_sec_kv(mem_ctx, cc, &key, &value); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert cache %s to JSON [%d]: %s\n", -+ cc->name, ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ url = sec_cc_url_create(tmp_ctx, client, key); -+ if (url == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ payload = sss_iobuf_init_readonly(tmp_ctx, -+ (const uint8_t *) value, -+ strlen(value)+1); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot create payload buffer\n"); -+ goto done; -+ } -+ -+ ret = EOK; -+ *_url = talloc_steal(mem_ctx, url); -+ *_payload = talloc_steal(mem_ctx, payload); -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ -+static errno_t sec_value_to_json(const char *input, -+ json_t **_root) -+{ -+ json_t *root = NULL; -+ json_error_t error; -+ int ok; -+ -+ root = json_loads(input, 0, &error); -+ if (root == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to parse JSON payload on line %d: %s\n", -+ error.line, error.text); -+ return ERR_JSON_DECODING; -+ } -+ -+ ok = json_is_object(root); -+ if (!ok) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Json data is not an object.\n"); -+ json_decref(root); -+ return ERR_JSON_DECODING; -+ } -+ -+ *_root = root; -+ return EOK; -+} -+ -+/* -+ * ccache unmarshalling from JSON -+ */ -+static errno_t json_element_to_krb5_data(TALLOC_CTX *mem_ctx, -+ json_t *element, -+ krb5_data *data) -+{ -+ const char *str_value; -+ size_t str_len; -+ -+ /* FIXME - it might be cleaner to use stringn here, but the libjansson -+ * version on RHEL-7 doesn't support that -+ */ -+ str_value = json_string_value(element); -+ if (str_value == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "JSON element not a string\n"); -+ return EINVAL; -+ } -+ str_len = strlen(str_value); -+ -+ data->data = talloc_strndup(mem_ctx, str_value, str_len); -+ if (data->data == NULL) { -+ return ENOMEM; -+ } -+ data->length = str_len; -+ -+ return EOK; -+} -+ -+static errno_t json_array_to_krb5_data(TALLOC_CTX *mem_ctx, -+ json_t *array, -+ krb5_data **_data, -+ size_t *_len) -+{ -+ errno_t ret; -+ int ok; -+ size_t len; -+ size_t idx; -+ json_t *element; -+ krb5_data *data; -+ -+ ok = json_is_array(array); -+ if (!ok) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Json object is not an array.\n"); -+ return ERR_JSON_DECODING; -+ } -+ -+ len = json_array_size(array); -+ if (len == 0) { -+ *_data = NULL; -+ *_len = 0; -+ return EOK; -+ } -+ -+ data = talloc_zero_array(mem_ctx, krb5_data, len); -+ if (data == NULL) { -+ return ENOMEM; -+ } -+ -+ json_array_foreach(array, idx, element) { -+ ret = json_element_to_krb5_data(data, element, &data[idx]); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert krb5 data element from JSON"); -+ talloc_free(data); -+ return ret; -+ } -+ } -+ -+ *_data = data; -+ *_len = len; -+ return EOK; -+} -+ -+static errno_t json_to_princ(TALLOC_CTX *mem_ctx, -+ json_t *js_princ, -+ krb5_principal *_princ) -+{ -+ errno_t ret; -+ json_t *components = NULL; -+ int ok; -+ krb5_principal princ = NULL; -+ TALLOC_CTX *tmp_ctx = NULL; -+ char *realm_str; -+ size_t realm_size; -+ json_error_t error; -+ -+ ok = json_is_object(js_princ); -+ if (!ok) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Json principal is not an object.\n"); -+ ret = ERR_JSON_DECODING; -+ goto done; -+ } -+ -+ tmp_ctx = talloc_new(mem_ctx); -+ if (tmp_ctx == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ princ = talloc_zero(tmp_ctx, struct krb5_principal_data); -+ if (princ == NULL) { -+ return ENOMEM; -+ } -+ princ->magic = KV5M_PRINCIPAL; -+ -+ /* FIXME - it might be cleaner to use the s% specifier here, but the libjansson -+ * version on RHEL-7 doesn't support that -+ */ -+ ret = json_unpack_ex(js_princ, -+ &error, -+ JSON_STRICT, -+ "{s:i, s:s, s:o}", -+ "type", &princ->type, -+ "realm", &realm_str, -+ "components", &components); -+ if (ret != 0) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to unpack JSON princ structure on line %d: %s\n", -+ error.line, error.text); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ realm_size = strlen(realm_str); -+ -+ princ->realm.data = talloc_strndup(mem_ctx, realm_str, realm_size); -+ if (princ->realm.data == NULL) { -+ return ENOMEM; -+ } -+ princ->realm.length = realm_size; -+ princ->realm.magic = 0; -+ -+ ret = json_array_to_krb5_data(princ, components, -+ &princ->data, -+ (size_t *) &princ->length); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert principal from JSON"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ *_princ = talloc_steal(mem_ctx, princ); -+ ret = EOK; -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ -+static errno_t json_elem_to_cred(TALLOC_CTX *mem_ctx, -+ json_t *element, -+ struct kcm_cred **_crd) -+{ -+ errno_t ret; -+ char *uuid_str; -+ json_error_t error; -+ uuid_t uuid; -+ struct sss_iobuf *cred_blob; -+ const char *base64_cred_blob; -+ struct kcm_cred *crd; -+ uint8_t *outbuf; -+ size_t outbuf_size; -+ TALLOC_CTX *tmp_ctx = NULL; -+ -+ ret = json_unpack_ex(element, -+ &error, -+ JSON_STRICT, -+ "{s:s, s:s}", -+ "uuid", &uuid_str, -+ "payload", &base64_cred_blob); -+ if (ret != 0) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to unpack JSON cred structure on line %d: %s\n", -+ error.line, error.text); -+ return EINVAL; -+ } -+ -+ uuid_parse(uuid_str, uuid); -+ -+ tmp_ctx = talloc_new(mem_ctx); -+ if (tmp_ctx == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ outbuf = sss_base64_decode(tmp_ctx, base64_cred_blob, &outbuf_size); -+ if (outbuf == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot decode cred blob\n"); -+ ret = EIO; -+ goto done; -+ } -+ -+ cred_blob = sss_iobuf_init_readonly(tmp_ctx, outbuf, outbuf_size); -+ if (cred_blob == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ crd = kcm_cred_new(tmp_ctx, uuid, cred_blob); -+ if (crd == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = EOK; -+ *_crd = talloc_steal(mem_ctx, crd); -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ -+static errno_t json_to_creds(struct kcm_ccache *cc, -+ json_t *jcreds) -+{ -+ errno_t ret; -+ int ok; -+ size_t idx; -+ json_t *value; -+ struct kcm_cred *crd; -+ -+ ok = json_is_array(jcreds); -+ if (!ok) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Json creds object is not an array.\n"); -+ return ERR_JSON_DECODING; -+ } -+ -+ json_array_foreach(jcreds, idx, value) { -+ ret = json_elem_to_cred(cc, value, &crd); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert JSON cred element [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return ret; -+ } -+ -+ ret = kcm_cc_store_creds(cc, crd); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot store creds in ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return ret; -+ } -+ } -+ -+ return EOK; -+} -+ -+static errno_t sec_json_value_to_ccache(struct kcm_ccache *cc, -+ json_t *root) -+{ -+ errno_t ret; -+ json_t *princ = NULL; -+ json_t *creds = NULL; -+ json_error_t error; -+ int version; -+ -+ ret = json_unpack_ex(root, -+ &error, -+ JSON_STRICT, -+ "{s:i, s:i, s:o, s:o}", -+ "version", &version, -+ "kdc_offset", &cc->kdc_offset, -+ "principal", &princ, -+ "creds", &creds); -+ if (ret != 0) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to unpack JSON creds structure on line %d: %s\n", -+ error.line, error.text); -+ return EINVAL; -+ } -+ -+ if (version != KS_JSON_VERSION) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Expected version %d, received version %d\n", -+ KS_JSON_VERSION, version); -+ return EINVAL; -+ } -+ -+ ret = json_to_princ(cc, princ, &cc->client); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot store JSON to principal [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return ret; -+ } -+ -+ ret = json_to_creds(cc, creds); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot store JSON to creds [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return EOK; -+ } -+ -+ return EOK; -+} -+ -+/* -+ * sec_key is a concatenation of the ccache's UUID and name -+ * sec_value is the JSON dump of the ccache contents -+ */ -+errno_t sec_kv_to_ccache(TALLOC_CTX *mem_ctx, -+ const char *sec_key, -+ const char *sec_value, -+ struct cli_creds *client, -+ struct kcm_ccache **_cc) -+{ -+ errno_t ret; -+ json_t *root = NULL; -+ struct kcm_ccache *cc = NULL; -+ TALLOC_CTX *tmp_ctx = NULL; -+ -+ ret = sec_value_to_json(sec_value, &root); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot store secret to JSN [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ tmp_ctx = talloc_new(mem_ctx); -+ if (tmp_ctx == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ cc = talloc_zero(tmp_ctx, struct kcm_ccache); -+ if (cc == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ /* We rely on sssd-secrets only searching the user's subtree so we -+ * set the ownership to the client -+ */ -+ cc->owner.uid = cli_creds_get_uid(client); -+ cc->owner.gid = cli_creds_get_gid(client); -+ -+ ret = sec_key_parse(cc, sec_key, &cc->name, cc->uuid); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannt parse secret key [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ ret = sec_json_value_to_ccache(cc, root); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannt parse secret value [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ ret = EOK; -+ *_cc = talloc_steal(mem_ctx, cc); -+done: -+ talloc_free(tmp_ctx); -+ json_decref(root); -+ return ret; -+} -diff --git a/src/responder/kcm/kcmsrv_ccache_secrets.c b/src/responder/kcm/kcmsrv_ccache_secrets.c -new file mode 100644 -index 0000000000000000000000000000000000000000..8be7daea59bd6e04ab8393aae9f8adc29df11c21 ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_ccache_secrets.c -@@ -0,0 +1,2169 @@ -+/* -+ SSSD -+ -+ KCM Server - ccache storage in sssd-secrets -+ -+ Copyright (C) Red Hat, 2016 -+ -+ 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 "config.h" -+ -+#include -+#include -+#include -+ -+#include "util/util.h" -+#include "util/crypto/sss_crypto.h" -+#include "util/tev_curl.h" -+#include "responder/kcm/kcmsrv_ccache_pvt.h" -+#include "responder/kcm/kcmsrv_ccache_be.h" -+ -+#ifndef SSSD_SECRETS_SOCKET -+#define SSSD_SECRETS_SOCKET VARDIR"/run/secrets.socket" -+#endif /* SSSD_SECRETS_SOCKET */ -+ -+#ifndef SEC_TIMEOUT -+#define SEC_TIMEOUT 5 -+#endif /* SEC_TIMEOUT */ -+ -+/* Just to keep the name of the ccache readable */ -+#define MAX_CC_NUM 99999 -+ -+/* Compat definition of json_array_foreach for older systems */ -+#ifndef json_array_foreach -+#define json_array_foreach(array, idx, value) \ -+ for(idx = 0; \ -+ idx < json_array_size(array) && (value = json_array_get(array, idx)); \ -+ idx++) -+#endif -+ -+static const char *find_by_name(const char **sec_key_list, -+ const char *name) -+{ -+ const char *sec_name = NULL; -+ -+ if (sec_key_list == NULL) { -+ return NULL; -+ } -+ -+ for (int i = 0; sec_key_list[i]; i++) { -+ if (sec_key_match_name(sec_key_list[i], name)) { -+ sec_name = sec_key_list[i]; -+ break; -+ } -+ } -+ -+ return sec_name; -+} -+ -+static const char *find_by_uuid(const char **sec_key_list, -+ uuid_t uuid) -+{ -+ const char *sec_name = NULL; -+ -+ if (sec_key_list == NULL) { -+ return NULL; -+ } -+ -+ for (int i = 0; sec_key_list[i]; i++) { -+ if (sec_key_match_uuid(sec_key_list[i], uuid)) { -+ sec_name = sec_key_list[i]; -+ break; -+ } -+ } -+ -+ return sec_name; -+} -+ -+static const char *sec_headers[] = { -+ "Content-type: application/octet-stream", -+ NULL, -+}; -+ -+struct ccdb_sec { -+ struct tcurl_ctx *tctx; -+}; -+ -+static errno_t http2errno(int http_code) -+{ -+ if (http_code != 200) { -+ DEBUG(SSSDBG_OP_FAILURE, "HTTP request returned %d\n", http_code); -+ } -+ -+ switch (http_code) { -+ case 200: -+ return EOK; -+ case 404: -+ return ERR_NO_CREDS; -+ case 400: -+ return ERR_INPUT_PARSE; -+ case 403: -+ return EACCES; -+ case 409: -+ return EEXIST; -+ case 413: -+ return E2BIG; -+ case 507: -+ return ENOSPC; -+ } -+ -+ return EIO; -+} -+ -+/* -+ * Helper request to list all UUID+name pairs -+ */ -+struct sec_list_state { -+ const char **sec_key_list; -+ size_t sec_key_list_len; -+}; -+ -+static void sec_list_done(struct tevent_req *subreq); -+static errno_t sec_list_parse(struct sss_iobuf *outbuf, -+ TALLOC_CTX *mem_ctx, -+ const char ***_list, -+ size_t *_list_len); -+ -+static struct tevent_req *sec_list_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct ccdb_sec *secdb, -+ struct cli_creds *client) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct sec_list_state *state = NULL; -+ errno_t ret; -+ const char *container_url; -+ -+ req = tevent_req_create(mem_ctx, &state, struct sec_list_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Listing all ccaches in the secrets store\n"); -+ container_url = sec_container_url_create(state, client); -+ if (container_url == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ subreq = tcurl_http_send(state, ev, secdb->tctx, -+ TCURL_HTTP_GET, -+ SSSD_SECRETS_SOCKET, -+ container_url, -+ sec_headers, -+ NULL, -+ SEC_TIMEOUT); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, sec_list_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void sec_list_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ struct sec_list_state *state = tevent_req_data(req, -+ struct sec_list_state); -+ struct sss_iobuf *outbuf; -+ int http_code; -+ -+ ret = tcurl_http_recv(state, subreq, &http_code, &outbuf); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "list HTTP request failed [%d]: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (http_code == 404) { -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Nothing to list\n"); -+ /* If no ccaches are found, return an empty list */ -+ state->sec_key_list = talloc_zero_array(state, const char *, 1); -+ if (state->sec_key_list == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ } else if (http_code == 200) { -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Found %zu items\n", state->sec_key_list_len); -+ ret = sec_list_parse(outbuf, state, -+ &state->sec_key_list, -+ &state->sec_key_list_len); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ } else { -+ tevent_req_error(req, http2errno(http_code)); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "list done\n"); -+ tevent_req_done(req); -+} -+ -+static errno_t sec_list_parse(struct sss_iobuf *outbuf, -+ TALLOC_CTX *mem_ctx, -+ const char ***_list, -+ size_t *_list_len) -+{ -+ json_t *root; -+ uint8_t *sec_http_list; -+ json_error_t error; -+ json_t *element; -+ errno_t ret; -+ int ok; -+ size_t idx; -+ const char **list = NULL; -+ size_t list_len; -+ -+ sec_http_list = sss_iobuf_get_data(outbuf); -+ if (sec_http_list == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "No data in output buffer?\n"); -+ return EINVAL; -+ } -+ -+ root = json_loads((const char *) sec_http_list, 0, &error); -+ if (root == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to parse JSON payload on line %d: %s\n", -+ error.line, error.text); -+ return ERR_JSON_DECODING; -+ } -+ -+ ok = json_is_array(root); -+ if (!ok) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "list reply is not an object.\n"); -+ ret = ERR_JSON_DECODING; -+ goto done; -+ } -+ -+ list_len = json_array_size(root); -+ list = talloc_zero_array(mem_ctx, const char *, list_len + 1); -+ if (list == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ json_array_foreach(root, idx, element) { -+ list[idx] = talloc_strdup(list, json_string_value(element)); -+ if (list[idx] == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ ret = EOK; -+ *_list = list; -+ *_list_len = list_len; -+done: -+ if (ret != EOK) { -+ talloc_free(list); -+ } -+ json_decref(root); -+ return ret; -+} -+ -+static errno_t sec_list_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ const char ***_sec_key_list, -+ size_t *_sec_key_list_len) -+ -+{ -+ struct sec_list_state *state = tevent_req_data(req, -+ struct sec_list_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ -+ if (_sec_key_list != NULL) { -+ *_sec_key_list = talloc_steal(mem_ctx, state->sec_key_list); -+ } -+ if (_sec_key_list_len != NULL) { -+ *_sec_key_list_len = state->sec_key_list_len; -+ } -+ return EOK; -+} -+ -+/* -+ * Helper request to get a ccache by key -+ */ -+struct sec_get_state { -+ const char *sec_key; -+ struct cli_creds *client; -+ -+ struct kcm_ccache *cc; -+}; -+ -+static void sec_get_done(struct tevent_req *subreq); -+ -+static struct tevent_req *sec_get_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct ccdb_sec *secdb, -+ struct cli_creds *client, -+ const char *sec_key) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct sec_get_state *state = NULL; -+ errno_t ret; -+ const char *cc_url; -+ -+ req = tevent_req_create(mem_ctx, &state, struct sec_get_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->sec_key = sec_key; -+ state->client = client; -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Retrieving ccache %s\n", sec_key); -+ -+ cc_url = sec_cc_url_create(state, state->client, state->sec_key); -+ if (cc_url == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ subreq = tcurl_http_send(state, -+ ev, -+ secdb->tctx, -+ TCURL_HTTP_GET, -+ SSSD_SECRETS_SOCKET, -+ cc_url, -+ sec_headers, -+ NULL, -+ SEC_TIMEOUT); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, sec_get_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void sec_get_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ struct sec_get_state *state = tevent_req_data(req, -+ struct sec_get_state); -+ struct sss_iobuf *outbuf; -+ const char *sec_value; -+ int http_code; -+ -+ ret = tcurl_http_recv(state, subreq, &http_code, &outbuf); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "GET HTTP request failed [%d]: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (http_code != 200) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "GET operation returned HTTP error %d\n", http_code); -+ ret = http2errno(http_code); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ sec_value = (const char *) sss_iobuf_get_data(outbuf); -+ if (sec_value == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "No data in output buffer\n"); -+ tevent_req_error(req, EINVAL); -+ return; -+ } -+ -+ ret = sec_kv_to_ccache(state, -+ state->sec_key, -+ sec_value, -+ state->client, -+ &state->cc); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot convert JSON keyval to ccache blob [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "GET done\n"); -+ tevent_req_done(req); -+} -+ -+static errno_t sec_get_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc) -+{ -+ struct sec_get_state *state = tevent_req_data(req, struct sec_get_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_cc = talloc_steal(mem_ctx, state->cc); -+ return EOK; -+} -+ -+/* -+ * Helper request to get a ccache name or ID -+ */ -+struct sec_get_ccache_state { -+ struct tevent_context *ev; -+ struct ccdb_sec *secdb; -+ struct cli_creds *client; -+ const char *name; -+ uuid_t uuid; -+ -+ const char *sec_key; -+ -+ struct kcm_ccache *cc; -+}; -+ -+static void sec_get_ccache_list_done(struct tevent_req *subreq); -+static void sec_get_ccache_done(struct tevent_req *subreq); -+ -+static struct tevent_req *sec_get_ccache_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct ccdb_sec *secdb, -+ struct cli_creds *client, -+ const char *name, -+ uuid_t uuid) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct sec_get_ccache_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct sec_get_ccache_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->ev = ev; -+ state->secdb = secdb; -+ state->client = client; -+ state->name = name; -+ uuid_copy(state->uuid, uuid); -+ -+ if ((name == NULL && uuid_is_null(uuid)) -+ || (name != NULL && !uuid_is_null(uuid))) { -+ DEBUG(SSSDBG_OP_FAILURE, "Expected one of name, uuid to be set\n"); -+ ret = EINVAL; -+ goto immediate; -+ } -+ -+ subreq = sec_list_send(state, ev, secdb, client); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, sec_get_ccache_list_done, req); -+ return req; -+ -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void sec_get_ccache_list_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ struct sec_get_ccache_state *state = tevent_req_data(req, -+ struct sec_get_ccache_state); -+ const char **sec_key_list; -+ -+ ret = sec_list_recv(subreq, state, &sec_key_list, NULL); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot list keys [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (state->name != NULL) { -+ state->sec_key = find_by_name(sec_key_list, state->name); -+ } else { -+ state->sec_key = find_by_uuid(sec_key_list, state->uuid); -+ } -+ -+ if (state->sec_key == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Cannot find item in the ccache list\n"); -+ /* Don't error out, just return an empty list */ -+ tevent_req_done(req); -+ return; -+ } -+ -+ subreq = sec_get_send(state, -+ state->ev, -+ state->secdb, -+ state->client, -+ state->sec_key); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, sec_get_ccache_done, req); -+} -+ -+static void sec_get_ccache_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct sec_get_ccache_state *state = tevent_req_data(req, -+ struct sec_get_ccache_state); -+ -+ ret = sec_get_recv(subreq, state, &state->cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot resolve key to ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+static errno_t sec_get_ccache_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc) -+{ -+ struct sec_get_ccache_state *state = tevent_req_data(req, -+ struct sec_get_ccache_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_cc = talloc_steal(mem_ctx, state->cc); -+ return EOK; -+} -+ -+/* -+ * The actual sssd-secrets back end -+ */ -+static errno_t ccdb_sec_init(struct kcm_ccdb *db) -+{ -+ struct ccdb_sec *secdb = NULL; -+ -+ secdb = talloc_zero(db, struct ccdb_sec); -+ if (secdb == NULL) { -+ return ENOMEM; -+ } -+ -+ secdb->tctx = tcurl_init(secdb, db->ev); -+ if (secdb->tctx == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Cannot initialize tcurl\n"); -+ talloc_zfree(secdb); -+ return ENOMEM; -+ } -+ -+ /* We just need the random numbers to generate pseudo-random ccache names -+ * and avoid conflicts */ -+ srand(time(NULL)); -+ -+ db->db_handle = secdb; -+ return EOK; -+} -+ -+/* -+ * Helper request to get a ccache by key -+ */ -+struct sec_patch_state { -+ struct tevent_context *ev; -+ struct ccdb_sec *secdb; -+ struct cli_creds *client; -+ -+ const char *sec_key_url; -+ struct sss_iobuf *sec_value; -+}; -+ -+static void sec_patch_del_done(struct tevent_req *subreq); -+static void sec_patch_put_done(struct tevent_req *subreq); -+ -+static struct tevent_req *sec_patch_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct ccdb_sec *secdb, -+ struct cli_creds *client, -+ const char *sec_key_url, -+ struct sss_iobuf *sec_value) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct sec_patch_state *state = NULL; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct sec_patch_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->ev = ev; -+ state->secdb = secdb; -+ state->client = client; -+ state->sec_key_url = sec_key_url; -+ state->sec_value = sec_value; -+ -+ subreq = tcurl_http_send(state, state->ev, -+ state->secdb->tctx, -+ TCURL_HTTP_DELETE, -+ SSSD_SECRETS_SOCKET, -+ state->sec_key_url, -+ sec_headers, -+ NULL, -+ SEC_TIMEOUT); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, sec_patch_del_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void sec_patch_del_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct sec_patch_state *state = tevent_req_data(req, -+ struct sec_patch_state); -+ int http_code; -+ -+ ret = tcurl_http_recv(state, subreq, &http_code, NULL); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot delete key [%d]: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (http_code == 404) { -+ DEBUG(SSSDBG_TRACE_LIBS, -+ "Key %s does not exist, moving on\n", state->sec_key_url); -+ } else if (http_code != 200) { -+ ret = http2errno(http_code); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Adding new payload\n"); -+ -+ subreq = tcurl_http_send(state, -+ state->ev, -+ state->secdb->tctx, -+ TCURL_HTTP_PUT, -+ SSSD_SECRETS_SOCKET, -+ state->sec_key_url, -+ sec_headers, -+ state->sec_value, -+ SEC_TIMEOUT); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, sec_patch_put_done, req); -+} -+ -+static void sec_patch_put_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct sec_patch_state *state = tevent_req_data(req, -+ struct sec_patch_state); -+ int http_code; -+ -+ ret = tcurl_http_recv(state, subreq, &http_code, NULL); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot put new value [%d]: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (http_code != 200) { -+ DEBUG(SSSDBG_OP_FAILURE, "Failed to add the payload\n"); -+ ret = http2errno(http_code); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "payload created\n"); -+ tevent_req_done(req); -+} -+ -+ -+static errno_t sec_patch_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+/* The operations between the KCM and sssd-secrets */ -+ -+struct ccdb_sec_nextid_state { -+ struct tevent_context *ev; -+ struct ccdb_sec *secdb; -+ struct cli_creds *client; -+ -+ unsigned int nextid; -+ char *nextid_name; -+ -+ int maxtries; -+ int numtry; -+}; -+ -+static errno_t ccdb_sec_nextid_generate(struct tevent_req *req); -+static void ccdb_sec_nextid_list_done(struct tevent_req *subreq); -+ -+/* Generate a unique ID */ -+/* GET the name from secrets, if doesn't exist, OK, if exists, try again */ -+static struct tevent_req *ccdb_sec_nextid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client) -+{ -+ struct tevent_req *req = NULL; -+ struct ccdb_sec_nextid_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_nextid_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->ev = ev; -+ state->secdb = secdb; -+ state->client = client; -+ -+ state->maxtries = 3; -+ state->numtry = 0; -+ -+ ret = ccdb_sec_nextid_generate(req); -+ if (ret != EOK) { -+ goto immediate; -+ } -+ -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static errno_t ccdb_sec_nextid_generate(struct tevent_req *req) -+{ -+ struct tevent_req *subreq = NULL; -+ struct ccdb_sec_nextid_state *state = tevent_req_data(req, -+ struct ccdb_sec_nextid_state); -+ -+ if (state->numtry >= state->maxtries) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to find a random ccache in %d tries\n", state->numtry); -+ return EBUSY; -+ } -+ -+ state->nextid = rand() % MAX_CC_NUM; -+ state->nextid_name = talloc_asprintf(state, "%"SPRIuid":%u", -+ cli_creds_get_uid(state->client), -+ state->nextid); -+ if (state->nextid_name == NULL) { -+ return ENOMEM; -+ } -+ -+ subreq = sec_list_send(state, state->ev, state->secdb, state->client); -+ if (subreq == NULL) { -+ return ENOMEM; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_nextid_list_done, req); -+ -+ state->numtry++; -+ return EOK; -+} -+ -+static void ccdb_sec_nextid_list_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct ccdb_sec_nextid_state *state = tevent_req_data(req, -+ struct ccdb_sec_nextid_state); -+ const char **sec_key_list; -+ size_t sec_key_list_len; -+ size_t i; -+ -+ ret = sec_list_recv(subreq, state, &sec_key_list, &sec_key_list_len); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot list keys [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ for (i = 0; i < sec_key_list_len; i++) { -+ if (sec_key_match_name(sec_key_list[i], state->nextid_name) == true) { -+ break; -+ } -+ } -+ -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Failed to find a random key, trying again..\n"); -+ if (i < sec_key_list_len) { -+ /* Try again */ -+ ret = ccdb_sec_nextid_generate(req); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, -+ "Generated new ccache name %u\n", state->nextid); -+ tevent_req_done(req); -+} -+ -+static errno_t ccdb_sec_nextid_recv(struct tevent_req *req, -+ unsigned int *_nextid) -+{ -+ struct ccdb_sec_nextid_state *state = tevent_req_data(req, -+ struct ccdb_sec_nextid_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_nextid = state->nextid; -+ return EOK; -+} -+ -+/* IN: HTTP PUT $base/default -d 'uuid' */ -+/* We chose only UUID here to avoid issues later with renaming */ -+struct ccdb_sec_set_default_state { -+}; -+ -+static void ccdb_sec_set_default_done(struct tevent_req *subreq); -+ -+static struct tevent_req *ccdb_sec_set_default_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct ccdb_sec_set_default_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ struct sss_iobuf *uuid_iobuf; -+ errno_t ret; -+ const char *url; -+ char uuid_str[UUID_STR_SIZE]; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_set_default_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ uuid_unparse(uuid, uuid_str); -+ DEBUG(SSSDBG_TRACE_INTERNAL, -+ "Setting the default ccache to %s\n", uuid_str); -+ -+ url = sec_dfl_url_create(state, client); -+ if (url == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ uuid_iobuf = sss_iobuf_init_readonly(state, -+ (uint8_t *) uuid_str, -+ UUID_STR_SIZE); -+ if (uuid_iobuf == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ subreq = sec_patch_send(state, ev, secdb, client, url, uuid_iobuf); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_set_default_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void ccdb_sec_set_default_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ -+ ret = sec_patch_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sec_patch request failed [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Set the default ccache\n"); -+ tevent_req_done(req); -+} -+ -+static errno_t ccdb_sec_set_default_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+/* IN: HTTP GET $base/default */ -+/* OUT: uuid */ -+struct ccdb_sec_get_default_state { -+ uuid_t uuid; -+}; -+ -+static void ccdb_sec_get_default_done(struct tevent_req *subreq); -+ -+static struct tevent_req *ccdb_sec_get_default_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct ccdb_sec_get_default_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ const char *url; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_get_default_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Getting the default ccache\n"); -+ url = sec_dfl_url_create(state, client); -+ if (url == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ subreq = tcurl_http_send(state, ev, secdb->tctx, -+ TCURL_HTTP_GET, -+ SSSD_SECRETS_SOCKET, -+ url, -+ sec_headers, -+ NULL, -+ SEC_TIMEOUT); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_get_default_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void ccdb_sec_get_default_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ int http_code; -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ struct ccdb_sec_get_default_state *state = tevent_req_data(req, -+ struct ccdb_sec_get_default_state); -+ struct sss_iobuf *outbuf; -+ size_t uuid_size; -+ -+ ret = tcurl_http_recv(state, subreq, &http_code, &outbuf); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Communication with the secrets responder failed [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (http_code == 404) { -+ /* Return a NULL uuid */ -+ uuid_clear(state->uuid); -+ tevent_req_done(req); -+ return; -+ } else if (http_code != 200) { -+ ret = http2errno(http_code); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ uuid_size = sss_iobuf_get_len(outbuf); -+ if (uuid_size != UUID_STR_SIZE) { -+ DEBUG(SSSDBG_OP_FAILURE, "Unexpected UUID size %zu\n", uuid_size); -+ tevent_req_error(req, EIO); -+ return; -+ } -+ -+ uuid_parse((const char *) sss_iobuf_get_data(outbuf), state->uuid); -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Got the default ccache\n"); -+ tevent_req_done(req); -+} -+ -+static errno_t ccdb_sec_get_default_recv(struct tevent_req *req, -+ uuid_t uuid) -+{ -+ struct ccdb_sec_get_default_state *state = tevent_req_data(req, -+ struct ccdb_sec_get_default_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ -+ uuid_copy(uuid, state->uuid); -+ return EOK; -+} -+ -+/* HTTP GET $base/ccache/ */ -+/* OUT: a list of */ -+struct ccdb_sec_list_state { -+ uuid_t *uuid_list; -+}; -+ -+static void ccdb_sec_list_done(struct tevent_req *subreq); -+ -+static struct tevent_req *ccdb_sec_list_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct ccdb_sec_list_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_list_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Listing all ccaches\n"); -+ -+ subreq = sec_list_send(state, ev, secdb, client); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_list_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void ccdb_sec_list_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct ccdb_sec_list_state *state = tevent_req_data(req, -+ struct ccdb_sec_list_state); -+ const char **sec_key_list; -+ size_t sec_key_list_len; -+ -+ ret = sec_list_recv(subreq, state, &sec_key_list, &sec_key_list_len); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Communication with the secrets responder failed [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Found %zu ccaches\n", sec_key_list_len); -+ -+ state->uuid_list = talloc_array(state, uuid_t, sec_key_list_len + 1); -+ if (state->uuid_list == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ -+ for (size_t i = 0; i < sec_key_list_len; i++) { -+ ret = sec_key_get_uuid(sec_key_list[i], -+ state->uuid_list[i]); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ } -+ /* Sentinel */ -+ uuid_clear(state->uuid_list[sec_key_list_len]); -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Listing all caches done\n"); -+ tevent_req_done(req); -+} -+ -+static errno_t ccdb_sec_list_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ uuid_t **_uuid_list) -+{ -+ struct ccdb_sec_list_state *state = tevent_req_data(req, -+ struct ccdb_sec_list_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_uuid_list = talloc_steal(mem_ctx, state->uuid_list); -+ return EOK; -+} -+ -+struct ccdb_sec_getbyuuid_state { -+ struct kcm_ccache *cc; -+}; -+ -+ -+/* HTTP GET $base/ccache/ */ -+/* OUT: a list of */ -+/* for each item in list, compare with the uuid: portion */ -+/* HTTP GET $base/ccache/uuid:name */ -+/* return result */ -+static void ccdb_sec_getbyuuid_done(struct tevent_req *subreq); -+ -+static struct tevent_req *ccdb_sec_getbyuuid_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ errno_t ret; -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct ccdb_sec_getbyuuid_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_getbyuuid_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Getting ccache by UUID\n"); -+ -+ subreq = sec_get_ccache_send(state, ev, secdb, client, NULL, uuid); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_getbyuuid_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void ccdb_sec_getbyuuid_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct ccdb_sec_getbyuuid_state *state = tevent_req_data(req, -+ struct ccdb_sec_getbyuuid_state); -+ -+ ret = sec_get_ccache_recv(subreq, state, &state->cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot retrieve the ccache [%d]: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by UUID\n"); -+ tevent_req_done(req); -+} -+ -+static errno_t ccdb_sec_getbyuuid_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc) -+{ -+ struct ccdb_sec_getbyuuid_state *state = tevent_req_data(req, -+ struct ccdb_sec_getbyuuid_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_cc = talloc_steal(mem_ctx, state->cc); -+ return EOK; -+} -+ -+/* HTTP GET $base/ccache/ */ -+/* OUT: a list of */ -+/* for each item in list, compare with the :name portion */ -+/* HTTP GET $base/ccache/uuid:name */ -+/* return result */ -+struct ccdb_sec_getbyname_state { -+ struct kcm_ccache *cc; -+}; -+ -+static void ccdb_sec_getbyname_done(struct tevent_req *subreq); -+ -+static struct tevent_req *ccdb_sec_getbyname_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ const char *name) -+{ -+ errno_t ret; -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct ccdb_sec_getbyname_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ uuid_t null_uuid; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_getbyname_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ uuid_clear(null_uuid); -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Getting ccache by name\n"); -+ -+ subreq = sec_get_ccache_send(state, ev, secdb, client, name, null_uuid); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_getbyname_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void ccdb_sec_getbyname_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct ccdb_sec_getbyname_state *state = tevent_req_data(req, -+ struct ccdb_sec_getbyname_state); -+ -+ ret = sec_get_ccache_recv(subreq, state, &state->cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot retrieve the ccache [%d]: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by UUID\n"); -+ tevent_req_done(req); -+} -+ -+static errno_t ccdb_sec_getbyname_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ccache **_cc) -+{ -+ struct ccdb_sec_getbyname_state *state = tevent_req_data(req, -+ struct ccdb_sec_getbyname_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_cc = talloc_steal(mem_ctx, state->cc); -+ return EOK; -+} -+ -+struct ccdb_sec_name_by_uuid_state { -+ struct tevent_context *ev; -+ struct ccdb_sec *secdb; -+ struct cli_creds *client; -+ -+ uuid_t uuid; -+ -+ const char *name; -+}; -+ -+static void ccdb_sec_name_by_uuid_done(struct tevent_req *subreq); -+ -+struct tevent_req *ccdb_sec_name_by_uuid_send(TALLOC_CTX *sec_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct ccdb_sec_name_by_uuid_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ errno_t ret; -+ -+ req = tevent_req_create(sec_ctx, &state, struct ccdb_sec_name_by_uuid_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->ev = ev; -+ state->secdb = secdb; -+ state->client = client; -+ uuid_copy(state->uuid, uuid); -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Translating UUID to name\n"); -+ -+ subreq = sec_list_send(state, state->ev, state->secdb, state->client); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_name_by_uuid_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void ccdb_sec_name_by_uuid_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct ccdb_sec_name_by_uuid_state *state = tevent_req_data(req, -+ struct ccdb_sec_name_by_uuid_state); -+ const char **sec_key_list; -+ const char *name; -+ size_t sec_key_list_len; -+ size_t i; -+ -+ ret = sec_list_recv(subreq, state, &sec_key_list, &sec_key_list_len); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ for (i = 0; i < sec_key_list_len; i++) { -+ if (sec_key_match_uuid(sec_key_list[i], state->uuid) == true) { -+ /* Match, copy name */ -+ name = sec_key_get_name(sec_key_list[i]); -+ if (name == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Malformed key, cannot get name\n"); -+ tevent_req_error(req, EINVAL); -+ return; -+ } -+ -+ state->name = talloc_strdup(state, name); -+ if (state->name == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by UUID\n"); -+ tevent_req_done(req); -+ return; -+ } -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "No such UUID\n"); -+ tevent_req_error(req, ERR_NO_CREDS); -+ return; -+} -+ -+errno_t ccdb_sec_name_by_uuid_recv(struct tevent_req *req, -+ TALLOC_CTX *sec_ctx, -+ const char **_name) -+{ -+ struct ccdb_sec_name_by_uuid_state *state = tevent_req_data(req, -+ struct ccdb_sec_name_by_uuid_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_name = talloc_steal(sec_ctx, state->name); -+ return EOK; -+} -+ -+struct ccdb_sec_uuid_by_name_state { -+ struct tevent_context *ev; -+ struct ccdb_sec *secdb; -+ struct cli_creds *client; -+ -+ const char *name; -+ -+ uuid_t uuid; -+}; -+ -+static void ccdb_sec_uuid_by_name_done(struct tevent_req *subreq); -+ -+struct tevent_req *ccdb_sec_uuid_by_name_send(TALLOC_CTX *sec_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ const char *name) -+{ -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct ccdb_sec_uuid_by_name_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ errno_t ret; -+ -+ req = tevent_req_create(sec_ctx, &state, struct ccdb_sec_uuid_by_name_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->ev = ev; -+ state->secdb = secdb; -+ state->client = client; -+ state->name = name; -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Translating name to UUID\n"); -+ -+ subreq = sec_list_send(state, state->ev, state->secdb, state->client); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_uuid_by_name_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void ccdb_sec_uuid_by_name_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct ccdb_sec_uuid_by_name_state *state = tevent_req_data(req, -+ struct ccdb_sec_uuid_by_name_state); -+ const char **sec_key_list; -+ size_t sec_key_list_len; -+ size_t i; -+ -+ ret = sec_list_recv(subreq, state, &sec_key_list, &sec_key_list_len); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ for (i = 0; i < sec_key_list_len; i++) { -+ if (sec_key_match_name(sec_key_list[i], state->name) == true) { -+ /* Match, copy UUID */ -+ ret = sec_key_get_uuid(sec_key_list[i], state->uuid); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Malformed key, cannot get UUID\n"); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by name\n"); -+ tevent_req_done(req); -+ return; -+ } -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "No such name\n"); -+ tevent_req_error(req, ERR_NO_CREDS); -+ return; -+} -+ -+errno_t ccdb_sec_uuid_by_name_recv(struct tevent_req *req, -+ TALLOC_CTX *sec_ctx, -+ uuid_t _uuid) -+{ -+ struct ccdb_sec_uuid_by_name_state *state = tevent_req_data(req, -+ struct ccdb_sec_uuid_by_name_state); -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ uuid_copy(_uuid, state->uuid); -+ return EOK; -+} -+ -+/* HTTP POST $base to create the container */ -+/* HTTP PUT $base to create the container. Since PUT errors out on duplicates, at least -+ * we fail consistently here and don't overwrite the ccache on concurrent requests -+ */ -+struct ccdb_sec_create_state { -+ struct tevent_context *ev; -+ struct ccdb_sec *secdb; -+ -+ const char *key_url; -+ struct sss_iobuf *ccache_payload; -+}; -+ -+static void ccdb_sec_container_done(struct tevent_req *subreq); -+static void ccdb_sec_ccache_done(struct tevent_req *subreq); -+ -+static struct tevent_req *ccdb_sec_create_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ struct kcm_ccache *cc) -+{ -+ struct tevent_req *subreq = NULL; -+ struct tevent_req *req = NULL; -+ struct ccdb_sec_create_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ errno_t ret; -+ const char *container_url; -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_create_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->ev = ev; -+ state->secdb = secdb; -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Creating ccache storage for %s\n", cc->name); -+ -+ /* Do the encoding asap so that if we fail, we don't even attempt any -+ * writes */ -+ ret = kcm_ccache_to_sec_input(state, cc, client, &state->key_url, &state->ccache_payload); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert cache %s to JSON [%d]: %s\n", -+ cc->name, ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ -+ container_url = sec_container_url_create(state, client); -+ if (container_url == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Creating the ccache container\n"); -+ subreq = tcurl_http_send(state, ev, secdb->tctx, -+ TCURL_HTTP_POST, -+ SSSD_SECRETS_SOCKET, -+ container_url, -+ sec_headers, -+ NULL, -+ SEC_TIMEOUT); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_container_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void ccdb_sec_container_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ int http_code; -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ struct ccdb_sec_create_state *state = tevent_req_data(req, -+ struct ccdb_sec_create_state); -+ -+ ret = tcurl_http_recv(state, subreq, &http_code, NULL); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Communication with the secrets responder failed [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ /* Conflict is not an error as multiple ccaches are under the same -+ * container */ -+ if (http_code == 409) { -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Container already exists, ignoring\n"); -+ } else if (http_code != 200) { -+ DEBUG(SSSDBG_OP_FAILURE, "Failed to create the ccache container\n"); -+ ret = http2errno(http_code); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "ccache container created\n"); -+ DEBUG(SSSDBG_TRACE_INTERNAL, "creating empty ccache payload\n"); -+ -+ subreq = tcurl_http_send(state, -+ state->ev, -+ state->secdb->tctx, -+ TCURL_HTTP_PUT, -+ SSSD_SECRETS_SOCKET, -+ state->key_url, -+ sec_headers, -+ state->ccache_payload, -+ SEC_TIMEOUT); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_ccache_done, req); -+} -+ -+static void ccdb_sec_ccache_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ int http_code; -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ struct ccdb_sec_create_state *state = tevent_req_data(req, -+ struct ccdb_sec_create_state); -+ -+ ret = tcurl_http_recv(state, subreq, &http_code, NULL); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Communication with the secrets responder failed [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (http_code != 200) { -+ DEBUG(SSSDBG_OP_FAILURE, "Failed to add the payload\n"); -+ ret = http2errno(http_code); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "payload created\n"); -+ tevent_req_done(req); -+} -+ -+static errno_t ccdb_sec_create_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+struct ccdb_sec_mod_cred_state { -+ struct tevent_context *ev; -+ struct kcm_ccdb *db; -+ struct cli_creds *client; -+ struct kcm_mod_ctx *mod_cc; -+ -+ struct ccdb_sec *secdb; -+}; -+ -+static void ccdb_sec_mod_cred_get_done(struct tevent_req *subreq); -+static void ccdb_sec_mod_cred_patch_done(struct tevent_req *subreq); -+ -+static struct tevent_req *ccdb_sec_mod_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid, -+ struct kcm_mod_ctx *mod_cc) -+{ -+ errno_t ret; -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct ccdb_sec_mod_cred_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_mod_cred_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->ev = ev; -+ state->db =db; -+ state->client = client; -+ state->secdb = secdb; -+ state->mod_cc = mod_cc; -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Modifying ccache\n"); -+ -+ subreq = sec_get_ccache_send(state, ev, secdb, client, NULL, uuid); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, *ccdb_sec_mod_cred_get_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void ccdb_sec_mod_cred_get_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct ccdb_sec_mod_cred_state *state = tevent_req_data(req, -+ struct ccdb_sec_mod_cred_state); -+ struct kcm_ccache *cc; -+ const char *url; -+ struct sss_iobuf *payload; -+ -+ ret = sec_get_ccache_recv(subreq, state, &cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot retrieve the ccache [%d]: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (cc == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "No such ccache\n"); -+ tevent_req_error(req, ERR_NO_CREDS); -+ return; -+ } -+ -+ kcm_mod_cc(cc, state->mod_cc); -+ -+ ret = kcm_ccache_to_sec_input(state, cc, state->client, &url, &payload); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to marshall modified ccache to payload [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ subreq = sec_patch_send(state, -+ state->ev, -+ state->secdb, -+ state->client, -+ url, -+ payload); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_mod_cred_patch_done, req); -+} -+ -+static void ccdb_sec_mod_cred_patch_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ -+ ret = sec_patch_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sec_patch request failed [%d]: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "ccache modified\n"); -+ tevent_req_done(req); -+} -+ -+static errno_t ccdb_sec_mod_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+struct ccdb_sec_store_cred_state { -+ struct tevent_context *ev; -+ struct kcm_ccdb *db; -+ struct cli_creds *client; -+ struct sss_iobuf *cred_blob; -+ -+ struct ccdb_sec *secdb; -+}; -+ -+static void ccdb_sec_store_cred_get_done(struct tevent_req *subreq); -+static void ccdb_sec_store_cred_patch_done(struct tevent_req *subreq); -+ -+/* HTTP DEL/PUT $base/ccache/uuid:name */ -+static struct tevent_req *ccdb_sec_store_cred_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid, -+ struct sss_iobuf *cred_blob) -+{ -+ errno_t ret; -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct ccdb_sec_store_cred_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_store_cred_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->ev = ev; -+ state->db =db; -+ state->client = client; -+ state->cred_blob = cred_blob; -+ state->secdb = secdb; -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Storing creds in ccache\n"); -+ -+ subreq = sec_get_ccache_send(state, ev, secdb, client, NULL, uuid); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, *ccdb_sec_store_cred_get_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void ccdb_sec_store_cred_get_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct ccdb_sec_store_cred_state *state = tevent_req_data(req, -+ struct ccdb_sec_store_cred_state); -+ struct kcm_ccache *cc; -+ const char *url; -+ struct sss_iobuf *payload; -+ -+ ret = sec_get_ccache_recv(subreq, state, &cc); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ ret = kcm_cc_store_cred_blob(cc, state->cred_blob); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot store credentials to ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ ret = kcm_ccache_to_sec_input(state, cc, state->client, &url, &payload); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to marshall modified ccache to payload [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ subreq = sec_patch_send(state, -+ state->ev, -+ state->secdb, -+ state->client, -+ url, -+ payload); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_store_cred_patch_done, req); -+} -+ -+static void ccdb_sec_store_cred_patch_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ -+ ret = sec_patch_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sec_patch request failed [%d]: %s\n", ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "ccache creds stored\n"); -+ tevent_req_done(req); -+} -+ -+static errno_t ccdb_sec_store_cred_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+/* HTTP DELETE $base/ccache/uuid:name */ -+struct ccdb_sec_delete_state { -+ struct tevent_context *ev; -+ struct ccdb_sec *secdb; -+ struct cli_creds *client; -+ uuid_t uuid; -+ -+ size_t sec_key_list_len; -+}; -+ -+static void ccdb_sec_delete_list_done(struct tevent_req *subreq); -+static void ccdb_sec_delete_cc_done(struct tevent_req *subreq); -+static void ccdb_sec_delete_container_done(struct tevent_req *subreq); -+ -+static struct tevent_req *ccdb_sec_delete_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ccdb *db, -+ struct cli_creds *client, -+ uuid_t uuid) -+{ -+ errno_t ret; -+ struct tevent_req *req = NULL; -+ struct tevent_req *subreq = NULL; -+ struct ccdb_sec_delete_state *state = NULL; -+ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); -+ -+ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_delete_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->ev = ev; -+ state->secdb = secdb; -+ state->client = client; -+ uuid_copy(state->uuid, uuid); -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Deleting ccache\n"); -+ -+ subreq = sec_list_send(state, ev, secdb, client); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_delete_list_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void ccdb_sec_delete_list_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct ccdb_sec_delete_state *state = tevent_req_data(req, -+ struct ccdb_sec_delete_state); -+ const char **sec_key_list; -+ const char *sec_key; -+ const char *cc_url; -+ -+ ret = sec_list_recv(subreq, -+ state, -+ &sec_key_list, -+ &state->sec_key_list_len); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (sec_key_list == 0) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "No ccaches to delete\n"); -+ tevent_req_done(req); -+ return; -+ } -+ -+ sec_key = find_by_uuid(sec_key_list, state->uuid); -+ if (sec_key == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot find ccache by UUID\n"); -+ tevent_req_done(req); -+ return; -+ } -+ -+ cc_url = sec_cc_url_create(state, state->client, sec_key); -+ if (cc_url == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ -+ subreq = tcurl_http_send(state, state->ev, -+ state->secdb->tctx, -+ TCURL_HTTP_DELETE, -+ SSSD_SECRETS_SOCKET, -+ cc_url, -+ sec_headers, -+ NULL, -+ SEC_TIMEOUT); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_delete_cc_done, req); -+} -+ -+static void ccdb_sec_delete_cc_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct ccdb_sec_delete_state *state = tevent_req_data(req, -+ struct ccdb_sec_delete_state); -+ int http_code; -+ const char *container_url; -+ -+ ret = tcurl_http_recv(state, subreq, &http_code, NULL); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot delete ccache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (http_code != 200) { -+ ret = http2errno(http_code); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (state->sec_key_list_len != 1) { -+ DEBUG(SSSDBG_TRACE_INTERNAL, "There are other ccaches, done\n"); -+ tevent_req_done(req); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Removing ccache container\n"); -+ -+ container_url = sec_container_url_create(state, state->client); -+ if (container_url == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ -+ subreq = tcurl_http_send(state, state->ev, -+ state->secdb->tctx, -+ TCURL_HTTP_DELETE, -+ SSSD_SECRETS_SOCKET, -+ container_url, -+ sec_headers, -+ NULL, -+ SEC_TIMEOUT); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ tevent_req_set_callback(subreq, ccdb_sec_delete_container_done, req); -+} -+ -+static void ccdb_sec_delete_container_done(struct tevent_req *subreq) -+{ -+ errno_t ret; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct ccdb_sec_delete_state *state = tevent_req_data(req, -+ struct ccdb_sec_delete_state); -+ int http_code; -+ -+ ret = tcurl_http_recv(state, subreq, &http_code, NULL); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot delete ccache container [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ if (http_code != 200) { -+ ret = http2errno(http_code); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Removed ccache container\n"); -+ tevent_req_done(req); -+} -+ -+static errno_t ccdb_sec_delete_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ -+const struct kcm_ccdb_ops ccdb_sec_ops = { -+ .init = ccdb_sec_init, -+ -+ .nextid_send = ccdb_sec_nextid_send, -+ .nextid_recv = ccdb_sec_nextid_recv, -+ -+ .set_default_send = ccdb_sec_set_default_send, -+ .set_default_recv = ccdb_sec_set_default_recv, -+ -+ .get_default_send = ccdb_sec_get_default_send, -+ .get_default_recv = ccdb_sec_get_default_recv, -+ -+ .list_send = ccdb_sec_list_send, -+ .list_recv = ccdb_sec_list_recv, -+ -+ .getbyname_send = ccdb_sec_getbyname_send, -+ .getbyname_recv = ccdb_sec_getbyname_recv, -+ -+ .getbyuuid_send = ccdb_sec_getbyuuid_send, -+ .getbyuuid_recv = ccdb_sec_getbyuuid_recv, -+ -+ .name_by_uuid_send = ccdb_sec_name_by_uuid_send, -+ .name_by_uuid_recv = ccdb_sec_name_by_uuid_recv, -+ -+ .uuid_by_name_send = ccdb_sec_uuid_by_name_send, -+ .uuid_by_name_recv = ccdb_sec_uuid_by_name_recv, -+ -+ .create_send = ccdb_sec_create_send, -+ .create_recv = ccdb_sec_create_recv, -+ -+ .mod_send = ccdb_sec_mod_send, -+ .mod_recv = ccdb_sec_mod_recv, -+ -+ .store_cred_send = ccdb_sec_store_cred_send, -+ .store_cred_recv = ccdb_sec_store_cred_recv, -+ -+ .delete_send = ccdb_sec_delete_send, -+ .delete_recv = ccdb_sec_delete_recv, -+}; -diff --git a/src/tests/cmocka/test_kcm_json_marshalling.c b/src/tests/cmocka/test_kcm_json_marshalling.c -new file mode 100644 -index 0000000000000000000000000000000000000000..8eff2f501066c70a8730cd3d4dc41b92d7a03e4c ---- /dev/null -+++ b/src/tests/cmocka/test_kcm_json_marshalling.c -@@ -0,0 +1,234 @@ -+/* -+ Copyright (C) 2017 Red Hat -+ -+ SSSD tests: Test KCM JSON marshalling -+ -+ 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 "config.h" -+ -+#include -+#include -+ -+#include "util/util_creds.h" -+#include "responder/kcm/kcmsrv_ccache.h" -+#include "responder/kcm/kcmsrv_ccache_be.h" -+#include "tests/cmocka/common_mock.h" -+ -+#define TEST_REALM "TESTREALM" -+#define TEST_PRINC_COMPONENT "PRINC_NAME" -+ -+#define TEST_CREDS "TESTCREDS" -+ -+const struct kcm_ccdb_ops ccdb_mem_ops; -+const struct kcm_ccdb_ops ccdb_sec_ops; -+ -+struct kcm_marshalling_test_ctx { -+ krb5_context kctx; -+ krb5_principal princ; -+}; -+ -+static int setup_kcm_marshalling(void **state) -+{ -+ struct kcm_marshalling_test_ctx *test_ctx; -+ krb5_error_code kerr; -+ -+ test_ctx = talloc_zero(NULL, struct kcm_marshalling_test_ctx); -+ assert_non_null(test_ctx); -+ -+ kerr = krb5_init_context(&test_ctx->kctx); -+ assert_int_equal(kerr, 0); -+ -+ kerr = krb5_build_principal(test_ctx->kctx, -+ &test_ctx->princ, -+ sizeof(TEST_REALM)-1, TEST_REALM, -+ TEST_PRINC_COMPONENT, NULL); -+ assert_int_equal(kerr, 0); -+ -+ *state = test_ctx; -+ return 0; -+} -+ -+static int teardown_kcm_marshalling(void **state) -+{ -+ struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state, -+ struct kcm_marshalling_test_ctx); -+ assert_non_null(test_ctx); -+ -+ krb5_free_principal(test_ctx->kctx, test_ctx->princ); -+ krb5_free_context(test_ctx->kctx); -+ talloc_free(test_ctx); -+ return 0; -+} -+ -+static void assert_cc_name_equal(struct kcm_ccache *cc1, -+ struct kcm_ccache *cc2) -+{ -+ const char *name1, *name2; -+ -+ name1 = kcm_cc_get_name(cc1); -+ name2 = kcm_cc_get_name(cc2); -+ assert_string_equal(name1, name2); -+} -+ -+static void assert_cc_uuid_equal(struct kcm_ccache *cc1, -+ struct kcm_ccache *cc2) -+{ -+ uuid_t u1, u2; -+ errno_t ret; -+ -+ ret = kcm_cc_get_uuid(cc1, u1); -+ assert_int_equal(ret, EOK); -+ ret = kcm_cc_get_uuid(cc2, u2); -+ assert_int_equal(ret, EOK); -+ ret = uuid_compare(u1, u2); -+ assert_int_equal(ret, 0); -+} -+ -+static void assert_cc_princ_equal(struct kcm_ccache *cc1, -+ struct kcm_ccache *cc2) -+{ -+ krb5_principal p1; -+ krb5_principal p2; -+ char *name1; -+ char *name2; -+ krb5_error_code kerr; -+ -+ p1 = kcm_cc_get_client_principal(cc1); -+ p2 = kcm_cc_get_client_principal(cc1); -+ -+ kerr = krb5_unparse_name(NULL, p1, &name1); -+ assert_int_equal(kerr, 0); -+ kerr = krb5_unparse_name(NULL, p2, &name2); -+ assert_int_equal(kerr, 0); -+ -+ assert_string_equal(name1, name2); -+ krb5_free_unparsed_name(NULL, name1); -+ krb5_free_unparsed_name(NULL, name2); -+} -+ -+static void assert_cc_offset_equal(struct kcm_ccache *cc1, -+ struct kcm_ccache *cc2) -+{ -+ int32_t off1; -+ int32_t off2; -+ -+ off1 = kcm_cc_get_offset(cc1); -+ off2 = kcm_cc_get_offset(cc2); -+ assert_int_equal(off1, off2); -+} -+ -+static void assert_cc_equal(struct kcm_ccache *cc1, -+ struct kcm_ccache *cc2) -+{ -+ assert_cc_name_equal(cc1, cc2); -+ assert_cc_uuid_equal(cc1, cc2); -+ assert_cc_princ_equal(cc1, cc2); -+ assert_cc_offset_equal(cc1, cc2); -+} -+ -+static void test_kcm_ccache_marshall_unmarshall(void **state) -+{ -+ struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state, -+ struct kcm_marshalling_test_ctx); -+ errno_t ret; -+ struct cli_creds owner; -+ struct kcm_ccache *cc; -+ struct kcm_ccache *cc2; -+ const char *url; -+ struct sss_iobuf *payload; -+ const char *name; -+ const char *key; -+ uint8_t *data; -+ -+ owner.ucred.uid = getuid(); -+ owner.ucred.gid = getuid(); -+ -+ name = talloc_asprintf(test_ctx, "%"SPRIuid, getuid()); -+ assert_non_null(name); -+ -+ ret = kcm_cc_new(test_ctx, -+ test_ctx->kctx, -+ &owner, -+ name, -+ test_ctx->princ, -+ &cc); -+ assert_int_equal(ret, EOK); -+ -+ ret = kcm_ccache_to_sec_input(test_ctx, -+ cc, -+ &owner, -+ &url, -+ &payload); -+ assert_int_equal(ret, EOK); -+ -+ key = strrchr(url, '/') + 1; -+ assert_non_null(key); -+ -+ data = sss_iobuf_get_data(payload); -+ assert_non_null(data); -+ -+ ret = sec_kv_to_ccache(test_ctx, -+ key, -+ (const char *) data, -+ &owner, -+ &cc2); -+ assert_int_equal(ret, EOK); -+ -+ assert_cc_equal(cc, cc2); -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ poptContext pc; -+ int opt; -+ int rv; -+ struct poptOption long_options[] = { -+ POPT_AUTOHELP -+ SSSD_DEBUG_OPTS -+ POPT_TABLEEND -+ }; -+ -+ const struct CMUnitTest tests[] = { -+ cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall, -+ setup_kcm_marshalling, -+ teardown_kcm_marshalling), -+ }; -+ -+ /* Set debug level to invalid value so we can deside if -d 0 was used. */ -+ debug_level = SSSDBG_INVALID; -+ -+ pc = poptGetContext(argv[0], argc, argv, long_options, 0); -+ while((opt = poptGetNextOpt(pc)) != -1) { -+ switch(opt) { -+ default: -+ fprintf(stderr, "\nInvalid option %s: %s\n\n", -+ poptBadOption(pc, 0), poptStrerror(opt)); -+ poptPrintUsage(pc, stderr, 0); -+ return 1; -+ } -+ } -+ poptFreeContext(pc); -+ -+ DEBUG_CLI_INIT(debug_level); -+ -+ /* Even though normally the tests should clean up after themselves -+ * they might not after a failed run. Remove the old db to be sure */ -+ tests_set_cwd(); -+ -+ rv = cmocka_run_group_tests(tests, NULL, NULL); -+ -+ return rv; -+} -diff --git a/src/tests/intg/test_kcm.py b/src/tests/intg/test_kcm.py -index ad1e4923bfe339cb040464757431d2ef3bf57ce1..11f80a1803b4ad9b8e8857bf9a8a244d4816f0a2 100644 ---- a/src/tests/intg/test_kcm.py -+++ b/src/tests/intg/test_kcm.py -@@ -27,7 +27,8 @@ import signal - import kdc - import krb5utils - import config --from util import unindent, run_shell -+from util import unindent -+from test_secrets import create_sssd_secrets_fixture - - class KcmTestEnv(object): - def __init__(self, k5kdc, k5util): -@@ -107,15 +108,8 @@ def create_sssd_kcm_fixture(sock_path, request): - return kcm_pid - - --@pytest.fixture --def setup_for_kcm(request, kdc_instance): -- """ -- Just set up the local provider for tests and enable the KCM -- responder -- """ -- kcm_path = os.path.join(config.RUNSTATEDIR, "kcm.socket") -- -- sssd_conf = unindent("""\ -+def create_sssd_conf(kcm_path, ccache_storage): -+ return unindent("""\ - [sssd] - domains = local - services = nss -@@ -125,8 +119,11 @@ def setup_for_kcm(request, kdc_instance): - - [kcm] - socket_path = {kcm_path} -+ ccache_storage = {ccache_storage} - """).format(**locals()) - -+ -+def common_setup_for_kcm_mem(request, kdc_instance, kcm_path, sssd_conf): - kcm_socket_include = unindent(""" - [libdefaults] - default_ccache_name = KCM: -@@ -142,11 +139,35 @@ def setup_for_kcm(request, kdc_instance): - return KcmTestEnv(kdc_instance, k5util) - - --def test_kcm_init_list_destroy(setup_for_kcm): -+@pytest.fixture -+def setup_for_kcm_mem(request, kdc_instance): -+ """ -+ Just set up the local provider for tests and enable the KCM -+ responder -+ """ -+ kcm_path = os.path.join(config.RUNSTATEDIR, "kcm.socket") -+ sssd_conf = create_sssd_conf(kcm_path, "memory") -+ return common_setup_for_kcm_mem(request, kdc_instance, kcm_path, sssd_conf) -+ -+@pytest.fixture -+def setup_secrets(request): -+ create_sssd_secrets_fixture(request) -+ -+@pytest.fixture -+def setup_for_kcm_sec(request, kdc_instance): -+ """ -+ Just set up the local provider for tests and enable the KCM -+ responder -+ """ -+ kcm_path = os.path.join(config.RUNSTATEDIR, "kcm.socket") -+ sssd_conf = create_sssd_conf(kcm_path, "secrets") -+ return common_setup_for_kcm_mem(request, kdc_instance, kcm_path, sssd_conf) -+ -+ -+def kcm_init_list_destroy(testenv): - """ - Test that kinit, kdestroy and klist work with KCM - """ -- testenv = setup_for_kcm - testenv.k5kdc.add_principal("kcmtest", "Secret123") - - ok = testenv.k5util.has_principal("kcmtest@KCMTEST") -@@ -172,12 +193,22 @@ def test_kcm_init_list_destroy(setup_for_kcm): - assert nprincs == 0 - - --def test_kcm_overwrite(setup_for_kcm): -+def test_kcm_mem_init_list_destroy(setup_for_kcm_mem): -+ testenv = setup_for_kcm_mem -+ kcm_init_list_destroy(testenv) -+ -+ -+def test_kcm_sec_init_list_destroy(setup_for_kcm_sec, -+ setup_secrets): -+ testenv = setup_for_kcm_sec -+ kcm_init_list_destroy(testenv) -+ -+ -+def kcm_overwrite(testenv): - """ - That that reusing a ccache reinitializes the cache and doesn't - add the same principal twice - """ -- testenv = setup_for_kcm - testenv.k5kdc.add_principal("kcmtest", "Secret123") - exp_ccache = {'kcmtest@KCMTEST': ['krbtgt/KCMTEST@KCMTEST']} - -@@ -192,12 +223,22 @@ def test_kcm_overwrite(setup_for_kcm): - assert exp_ccache == testenv.k5util.list_all_princs() - - --def test_collection_init_list_destroy(setup_for_kcm): -+def test_kcm_mem_overwrite(setup_for_kcm_mem): -+ testenv = setup_for_kcm_mem -+ kcm_overwrite(testenv) -+ -+ -+def test_kcm_sec_overwrite(setup_for_kcm_sec, -+ setup_secrets): -+ testenv = setup_for_kcm_sec -+ kcm_overwrite(testenv) -+ -+ -+def collection_init_list_destroy(testenv): - """ - Test that multiple principals and service tickets can be stored - in a collection. - """ -- testenv = setup_for_kcm - testenv.k5kdc.add_principal("alice", "alicepw") - testenv.k5kdc.add_principal("bob", "bobpw") - testenv.k5kdc.add_principal("carol", "carolpw") -@@ -241,7 +282,11 @@ def test_collection_init_list_destroy(setup_for_kcm): - - out = testenv.k5util.kdestroy() - assert out == 0 -- assert testenv.k5util.default_principal() == 'bob@KCMTEST' -+ # If the default is removed, KCM just uses whetever is the first entry -+ # in the collection as the default. And sine the KCM back ends don't -+ # guarantee if they are FIFO or LIFO, just check for either alice or bob -+ assert testenv.k5util.default_principal() in \ -+ ['alice@KCMTEST', 'bob@KCMTEST'] - cc_coll = testenv.k5util.list_all_princs() - assert len(cc_coll) == 2 - assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] -@@ -255,11 +300,21 @@ def test_collection_init_list_destroy(setup_for_kcm): - #assert len(cc_coll) == 0 - - --def test_kswitch(setup_for_kcm): -+def test_kcm_mem_collection_init_list_destroy(setup_for_kcm_mem): -+ testenv = setup_for_kcm_mem -+ collection_init_list_destroy(testenv) -+ -+ -+def test_kcm_sec_collection_init_list_destroy(setup_for_kcm_sec, -+ setup_secrets): -+ testenv = setup_for_kcm_sec -+ collection_init_list_destroy(testenv) -+ -+ -+def exercise_kswitch(testenv): - """ - Test switching between principals - """ -- testenv = setup_for_kcm - testenv.k5kdc.add_principal("alice", "alicepw") - testenv.k5kdc.add_principal("bob", "bobpw") - testenv.k5kdc.add_principal("host/somehostname") -@@ -301,12 +356,22 @@ def test_kswitch(setup_for_kcm): - 'host/differenthostname@KCMTEST']) - - --def test_subsidiaries(setup_for_kcm): -+def test_kcm_mem_kswitch(setup_for_kcm_mem): -+ testenv = setup_for_kcm_mem -+ exercise_kswitch(testenv) -+ -+ -+def test_kcm_sec_kswitch(setup_for_kcm_sec, -+ setup_secrets): -+ testenv = setup_for_kcm_sec -+ exercise_kswitch(testenv) -+ -+ -+def exercise_subsidiaries(testenv): - """ - Test that subsidiary caches are usable and KCM: without specifying UID - can be used to identify the collection - """ -- testenv = setup_for_kcm - testenv.k5kdc.add_principal("alice", "alicepw") - testenv.k5kdc.add_principal("bob", "bobpw") - testenv.k5kdc.add_principal("host/somehostname") -@@ -346,11 +411,21 @@ def test_subsidiaries(setup_for_kcm): - 'host/differenthostname@KCMTEST']) - - --def test_kdestroy_nocache(setup_for_kcm): -+def test_kcm_mem_subsidiaries(setup_for_kcm_mem): -+ testenv = setup_for_kcm_mem -+ exercise_subsidiaries(testenv) -+ -+ -+def test_kcm_sec_subsidiaries(setup_for_kcm_sec, -+ setup_secrets): -+ testenv = setup_for_kcm_sec -+ exercise_subsidiaries(testenv) -+ -+ -+def kdestroy_nocache(testenv): - """ - Destroying a non-existing ccache should not throw an error - """ -- testenv = setup_for_kcm - testenv.k5kdc.add_principal("alice", "alicepw") - out, _, _ = testenv.k5util.kinit("alice", "alicepw") - assert out == 0 -@@ -359,3 +434,14 @@ def test_kdestroy_nocache(setup_for_kcm): - assert out == 0 - out = testenv.k5util.kdestroy() - assert out == 0 -+ -+ -+def test_kcm_mem_kdestroy_nocache(setup_for_kcm_mem): -+ testenv = setup_for_kcm_mem -+ exercise_subsidiaries(testenv) -+ -+ -+def test_kcm_sec_kdestroy_nocache(setup_for_kcm_sec, -+ setup_secrets): -+ testenv = setup_for_kcm_sec -+ exercise_subsidiaries(testenv) -diff --git a/src/util/util_errors.c b/src/util/util_errors.c -index 23cfdf9c6116a2c8e569a041e8289b65a112fd08..60c2f439b3e39b1dbff353e429114cb5a3070052 100644 ---- a/src/util/util_errors.c -+++ b/src/util/util_errors.c -@@ -109,6 +109,8 @@ struct err_string error_to_str[] = { - { "KCM operation not implemented" }, /* ERR_KCM_OP_NOT_IMPLEMENTED */ - { "End of credential cache reached" }, /* ERR_KCM_CC_END */ - { "Credential cache name not allowed" }, /* ERR_KCM_WRONG_CCNAME_FORMAT */ -+ { "Cannot encode a JSON object to string" }, /* ERR_JSON_ENCODING */ -+ { "Cannot decode a JSON object from string" }, /* ERR_JSON_DECODING */ - { "ERR_LAST" } /* ERR_LAST */ - }; - -diff --git a/src/util/util_errors.h b/src/util/util_errors.h -index 387d481616db1ed5e22b73fae82632a582fae946..4e9da814702e2cd46edc52fd5c2ae5f640602609 100644 ---- a/src/util/util_errors.h -+++ b/src/util/util_errors.h -@@ -131,6 +131,8 @@ enum sssd_errors { - ERR_KCM_OP_NOT_IMPLEMENTED, - ERR_KCM_CC_END, - ERR_KCM_WRONG_CCNAME_FORMAT, -+ ERR_JSON_ENCODING, -+ ERR_JSON_DECODING, - ERR_LAST /* ALWAYS LAST */ - }; - --- -2.9.3 - diff --git a/SOURCES/0033-SYSTEMD-Clean-pid-file-in-corner-cases.patch b/SOURCES/0033-SYSTEMD-Clean-pid-file-in-corner-cases.patch new file mode 100644 index 0000000..ce1c4ec --- /dev/null +++ b/SOURCES/0033-SYSTEMD-Clean-pid-file-in-corner-cases.patch @@ -0,0 +1,39 @@ +From 7f4a89ff4e7dc7c3ffac24ac87187dca1e9e7d1e Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 8 Nov 2017 14:09:36 +0100 +Subject: [PATCH 33/35] SYSTEMD: Clean pid file in corner cases +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +SSSD can cleanup pid file in case of standard stopping of daemon. +It's done in function monitor_cleanup. However monitor does not have a +change to cleanup file in case of OOM or sending SIGKILL to monitor. + +Even though PIDFile is not necessary for services with Type notify +we should let systemd to clean this file in unexpected situations. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3528 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit f4b808c83ecbaf36c7069440535d62990e32d55d) +--- + src/sysv/systemd/sssd.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/sysv/systemd/sssd.service.in b/src/sysv/systemd/sssd.service.in +index cea848fac80303d6fae12dd84316a91dbc60072d..0c515d34caaa3ea397c4c7e95eef0188df170840 100644 +--- a/src/sysv/systemd/sssd.service.in ++++ b/src/sysv/systemd/sssd.service.in +@@ -10,6 +10,7 @@ EnvironmentFile=-@environment_file@ + ExecStart=@sbindir@/sssd -i ${DEBUG_LOGGER} + Type=notify + NotifyAccess=main ++PIDFile=@localstatedir@/run/sssd.pid + + [Install] + WantedBy=multi-user.target +-- +2.13.6 + diff --git a/SOURCES/0034-CHILD-Pass-information-about-logger-to-children.patch b/SOURCES/0034-CHILD-Pass-information-about-logger-to-children.patch new file mode 100644 index 0000000..a254cd8 --- /dev/null +++ b/SOURCES/0034-CHILD-Pass-information-about-logger-to-children.patch @@ -0,0 +1,198 @@ +From 3ada67750d3d0dc6188c03cc996b98e7578971a4 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 8 Nov 2017 08:13:02 +0100 +Subject: [PATCH 34/35] CHILD: Pass information about logger to children +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Variables debug_to_file or debug_to_stderr were not set +because back-end already user parameter --logger=%s. +And therefore logs were not sent to files. + +It could only work in case of direct usage of --debug-to-files in back-end via +command configuration option. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3433 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit a24954cc19285b197fb287bfa7aa01949c92b17d) +--- + src/p11_child/p11_child_nss.c | 4 +++- + src/providers/ad/ad_gpo_child.c | 3 ++- + src/providers/ipa/selinux_child.c | 3 ++- + src/providers/krb5/krb5_child.c | 3 ++- + src/providers/ldap/ldap_child.c | 3 ++- + src/util/child_common.c | 24 ++++++++++-------------- + 6 files changed, 21 insertions(+), 19 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index e7dbcb689220d1cd2585fbde5f26e84f8fa15cc2..b0ec69be321c4b4186ce851c07bfcc3e1afe9694 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -537,7 +537,7 @@ int main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; +- char *opt_logger = NULL; ++ const char *opt_logger = NULL; + errno_t ret; + TALLOC_CTX *main_ctx = NULL; + char *cert; +@@ -673,7 +673,9 @@ int main(int argc, const char *argv[]) + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } ++ opt_logger = sss_logger_str[FILES_LOGGER]; + } ++ + sss_set_logger(opt_logger); + + DEBUG(SSSDBG_TRACE_FUNC, "p11_child started.\n"); +diff --git a/src/providers/ad/ad_gpo_child.c b/src/providers/ad/ad_gpo_child.c +index 5375cc691e8649c289672b74c4bfe5266c8222c9..a0bd6e13a31fe0f92924d49302d1b8b17bac4d67 100644 +--- a/src/providers/ad/ad_gpo_child.c ++++ b/src/providers/ad/ad_gpo_child.c +@@ -687,7 +687,7 @@ main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; +- char *opt_logger = NULL; ++ const char *opt_logger = NULL; + errno_t ret; + int sysvol_gpt_version; + int result; +@@ -744,6 +744,7 @@ main(int argc, const char *argv[]) + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } ++ opt_logger = sss_logger_str[FILES_LOGGER]; + } + + sss_set_logger(opt_logger); +diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c +index 120492686963241b7e419413f489cc38953e32f2..a7e20f715626d0f3ecef7cc06f3de5d44b6a15c1 100644 +--- a/src/providers/ipa/selinux_child.c ++++ b/src/providers/ipa/selinux_child.c +@@ -206,7 +206,7 @@ int main(int argc, const char *argv[]) + struct response *resp = NULL; + ssize_t written; + bool needs_update; +- char *opt_logger = NULL; ++ const char *opt_logger = NULL; + + struct poptOption long_options[] = { + POPT_AUTOHELP +@@ -254,6 +254,7 @@ int main(int argc, const char *argv[]) + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } ++ opt_logger = sss_logger_str[FILES_LOGGER]; + } + + sss_set_logger(opt_logger); +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index 700338e47a3f9ac6fcf11b4c92364dbdb4f9bcf7..7b56002377ac22472c3eea1aef687109757c22db 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -3020,7 +3020,7 @@ int main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; +- char *opt_logger = NULL; ++ const char *opt_logger = NULL; + errno_t ret; + krb5_error_code kerr; + uid_t fast_uid; +@@ -3097,6 +3097,7 @@ int main(int argc, const char *argv[]) + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } ++ opt_logger = sss_logger_str[FILES_LOGGER]; + } + + sss_set_logger(opt_logger); +diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c +index baeed239db5dc7ffa482edcbc155f25f718c8249..c0618d6d8828f102c32cf56731995e2b370590e7 100644 +--- a/src/providers/ldap/ldap_child.c ++++ b/src/providers/ldap/ldap_child.c +@@ -599,7 +599,7 @@ int main(int argc, const char *argv[]) + int kerr; + int opt; + int debug_fd = -1; +- char *opt_logger = NULL; ++ const char *opt_logger = NULL; + poptContext pc; + TALLOC_CTX *main_ctx = NULL; + uint8_t *buf = NULL; +@@ -657,6 +657,7 @@ int main(int argc, const char *argv[]) + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } ++ opt_logger = sss_logger_str[FILES_LOGGER]; + } + + sss_set_logger(opt_logger); +diff --git a/src/util/child_common.c b/src/util/child_common.c +index dc070f26446305e07cbb34edd1e4d72db72aedc5..203c115f9e7c4ecc2178b5660473d4f960fbbb6d 100644 +--- a/src/util/child_common.c ++++ b/src/util/child_common.c +@@ -630,14 +630,11 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx, + } + + /* Save the current state in case an interrupt changes it */ +- bool child_debug_to_file = debug_to_file; + bool child_debug_timestamps = debug_timestamps; + bool child_debug_microseconds = debug_microseconds; +- bool child_debug_stderr = debug_to_stderr; + + if (!extra_args_only) { +- if (child_debug_to_file) argc++; +- if (child_debug_stderr) argc++; ++ argc++; + } + + if (extra_argv) { +@@ -675,21 +672,20 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx, + goto fail; + } + +- if (child_debug_stderr) { +- argv[--argc] = talloc_strdup(argv, "--logger=stderr"); +- if (argv[argc] == NULL) { +- ret = ENOMEM; +- goto fail; +- } +- } +- +- if (child_debug_to_file) { ++ if (sss_logger == FILES_LOGGER) { + argv[--argc] = talloc_asprintf(argv, "--debug-fd=%d", + child_debug_fd); + if (argv[argc] == NULL) { + ret = ENOMEM; + goto fail; + } ++ } else { ++ argv[--argc] = talloc_asprintf(argv, "--logger=%s", ++ sss_logger_str[sss_logger]); ++ if (argv[argc] == NULL) { ++ ret = ENOMEM; ++ goto fail; ++ } + } + + argv[--argc] = talloc_asprintf(argv, "--debug-timestamps=%d", +@@ -816,7 +812,7 @@ errno_t child_debug_init(const char *logfile, int *debug_fd) + return EOK; + } + +- if (debug_to_file != 0 && *debug_fd == -1) { ++ if (sss_logger == FILES_LOGGER && *debug_fd == -1) { + ret = open_debug_file_ex(logfile, &debug_filep, false); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Error setting up logging (%d) [%s]\n", +-- +2.13.6 + diff --git a/SOURCES/0034-KCM-Make-the-secrets-ccache-back-end-configurable-ma.patch b/SOURCES/0034-KCM-Make-the-secrets-ccache-back-end-configurable-ma.patch deleted file mode 100644 index 2d65a32..0000000 --- a/SOURCES/0034-KCM-Make-the-secrets-ccache-back-end-configurable-ma.patch +++ /dev/null @@ -1,219 +0,0 @@ -From 6236b14d20151053f5ccad1fc8ee9b669d4b0ffb Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 14 Mar 2017 11:17:05 +0100 -Subject: [PATCH 34/36] KCM: Make the secrets ccache back end configurable, - make secrets the default -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Adds a new option 'ccache_storage' that allows to select either the -memory back end or the secrets back end. The secrets back end is the -default one and this option is even undocumented. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/confdb/confdb.h | 1 + - src/config/cfg_rules.ini | 1 + - src/responder/kcm/kcm.c | 49 ++++++++++++++++++++++++++++++++---- - src/responder/kcm/kcmsrv_ccache.c | 2 +- - src/responder/kcm/kcmsrv_ccache.h | 6 +---- - src/responder/kcm/kcmsrv_ccache_be.h | 1 + - src/responder/kcm/kcmsrv_pvt.h | 7 ++++++ - 7 files changed, 56 insertions(+), 11 deletions(-) - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index c443e869a7a6782265b42c4ad122867c4e3dd8e0..fb60675ca8beb2c2a157bf021ed9cad362742988 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -234,6 +234,7 @@ - /* KCM Service */ - #define CONFDB_KCM_CONF_ENTRY "config/kcm" - #define CONFDB_KCM_SOCKET "socket_path" -+#define CONFDB_KCM_DB "ccache_storage" /* Undocumented on purpose */ - - struct confdb_ctx; - struct config_file_ctx; -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 5e789c51658c51c0af1338d23d6c0f30f40bf119..67a5d1f5ad447a942b437ffd04a7f5d7cfe77d7f 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -280,6 +280,7 @@ option = fd_limit - option = client_idle_timeout - option = description - option = socket_path -+option = ccache_storage - - [rule/allowed_domain_options] - validator = ini_allowed_options -diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c -index 2c12ef215ce3967df183e51c20590c5f439d278f..063c27b915b4b92f6259496feee891aa94a498b6 100644 ---- a/src/responder/kcm/kcm.c -+++ b/src/responder/kcm/kcm.c -@@ -47,6 +47,37 @@ static int kcm_responder_ctx_destructor(void *ptr) - return 0; - } - -+static errno_t kcm_get_ccdb_be(struct kcm_ctx *kctx) -+{ -+ errno_t ret; -+ char *str_db; -+ -+ ret = confdb_get_string(kctx->rctx->cdb, -+ kctx->rctx, -+ kctx->rctx->confdb_service_path, -+ CONFDB_KCM_DB, -+ "secrets", -+ &str_db); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get the KCM database type [%d]: %s\n", -+ ret, strerror(ret)); -+ return ret; -+ } -+ -+ DEBUG(SSSDBG_CONF_SETTINGS, "KCM database type: %s\n", str_db); -+ if (strcasecmp(str_db, "memory") == 0) { -+ kctx->cc_be = CCDB_BE_MEMORY; -+ return EOK; -+ } else if (strcasecmp(str_db, "secrets") == 0) { -+ kctx->cc_be = CCDB_BE_SECRETS; -+ return EOK; -+ } -+ -+ DEBUG(SSSDBG_FATAL_FAILURE, "Unexpected KCM database type %s\n", str_db); -+ return EOK; -+} -+ - static int kcm_get_config(struct kcm_ctx *kctx) - { - int ret; -@@ -88,14 +119,21 @@ static int kcm_get_config(struct kcm_ctx *kctx) - &sock_name); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, -- "Cannot get the client idle timeout [%d]: %s\n", -+ "Cannot get KCM socket path [%d]: %s\n", - ret, strerror(ret)); - goto done; - } - kctx->rctx->sock_name = sock_name; - -+ ret = kcm_get_ccdb_be(kctx); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get KCM ccache DB [%d]: %s\n", -+ ret, strerror(ret)); -+ goto done; -+ } -+ - ret = EOK; -- - done: - return ret; - } -@@ -111,7 +149,8 @@ static int kcm_data_destructor(void *ptr) - } - - static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx, -- struct tevent_context *ev) -+ struct tevent_context *ev, -+ enum kcm_ccdb_be cc_be) - { - struct kcm_resp_ctx *kcm_data; - krb5_error_code kret; -@@ -122,7 +161,7 @@ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx, - return NULL; - } - -- kcm_data->db = kcm_ccdb_init(kcm_data, ev, CCDB_BE_MEMORY); -+ kcm_data->db = kcm_ccdb_init(kcm_data, ev, cc_be); - if (kcm_data->db == NULL) { - talloc_free(kcm_data); - return NULL; -@@ -176,7 +215,7 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx, - goto fail; - } - -- kctx->kcm_data = kcm_data_setup(kctx, ev); -+ kctx->kcm_data = kcm_data_setup(kctx, ev, kctx->cc_be); - if (kctx->kcm_data == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, - "fatal error initializing responder data\n"); -diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c -index 2ae120269b0c62275ba2acdff6d6daa8b7077708..a22184e0f2b1300f3678bb343b6a110bf144a36b 100644 ---- a/src/responder/kcm/kcmsrv_ccache.c -+++ b/src/responder/kcm/kcmsrv_ccache.c -@@ -244,7 +244,7 @@ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, - break; - case CCDB_BE_SECRETS: - DEBUG(SSSDBG_FUNC_DATA, "KCM back end: sssd-secrets\n"); -- /* Not implemented yet */ -+ ccdb->ops = &ccdb_sec_ops; - break; - default: - DEBUG(SSSDBG_CRIT_FAILURE, "Unknown ccache database\n"); -diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h -index 18c8c47ad4ecb24521a85a1833b239c7a2a8bb45..36c481c5335d557318f0ed0204d93e533b4b6c41 100644 ---- a/src/responder/kcm/kcmsrv_ccache.h -+++ b/src/responder/kcm/kcmsrv_ccache.h -@@ -29,6 +29,7 @@ - #include "util/util.h" - #include "util/sss_iobuf.h" - #include "util/util_creds.h" -+#include "responder/kcm/kcmsrv_pvt.h" - - #define UUID_BYTES 16 - #define UUID_STR_SIZE 37 -@@ -113,11 +114,6 @@ errno_t kcm_cc_store_cred_blob(struct kcm_ccache *cc, - struct kcm_cred *kcm_cc_get_cred(struct kcm_ccache *cc); - struct kcm_cred *kcm_cc_next_cred(struct kcm_cred *crd); - --enum kcm_ccdb_be { -- CCDB_BE_MEMORY, -- CCDB_BE_SECRETS, --}; -- - /* An opaque database that contains all the ccaches */ - struct kcm_ccdb; - -diff --git a/src/responder/kcm/kcmsrv_ccache_be.h b/src/responder/kcm/kcmsrv_ccache_be.h -index 1bd2b6981e227675866e82e0a5389445cac4df66..a0796c298bae15a01adf612a6195a494ba6b4d23 100644 ---- a/src/responder/kcm/kcmsrv_ccache_be.h -+++ b/src/responder/kcm/kcmsrv_ccache_be.h -@@ -200,5 +200,6 @@ struct kcm_ccdb_ops { - }; - - extern const struct kcm_ccdb_ops ccdb_mem_ops; -+extern const struct kcm_ccdb_ops ccdb_sec_ops; - - #endif /* _KCMSRV_CCACHE_BE_ */ -diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h -index a29680246c1e616da75e1bbff951ce2fad66fb65..74f30c00014105ed533744779b02c5d42523722d 100644 ---- a/src/responder/kcm/kcmsrv_pvt.h -+++ b/src/responder/kcm/kcmsrv_pvt.h -@@ -49,6 +49,12 @@ struct kcm_resp_ctx { - struct kcm_ccdb *db; - }; - -+/* Supported ccache back ends */ -+enum kcm_ccdb_be { -+ CCDB_BE_MEMORY, -+ CCDB_BE_SECRETS, -+}; -+ - /* - * responder context that contains both the responder data, - * like the ccaches and the sssd-specific stuff like the -@@ -58,6 +64,7 @@ struct kcm_ctx { - struct resp_ctx *rctx; - int fd_limit; - char *socket_path; -+ enum kcm_ccdb_be cc_be; - - struct kcm_resp_ctx *kcm_data; - }; --- -2.9.3 - diff --git a/SOURCES/0035-KCM-Queue-requests-by-the-same-UID.patch b/SOURCES/0035-KCM-Queue-requests-by-the-same-UID.patch deleted file mode 100644 index 338c394..0000000 --- a/SOURCES/0035-KCM-Queue-requests-by-the-same-UID.patch +++ /dev/null @@ -1,909 +0,0 @@ -From 688e8d8ffe331a1dd75a78002bf212277f2d7664 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 21 Mar 2017 13:25:11 +0100 -Subject: [PATCH 35/36] KCM: Queue requests by the same UID -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In order to avoid race conditions, we queue requests towards the KCM -responder coming from the same client UID. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce -Reviewed-by: Lukáš Slebodník ---- - Makefile.am | 21 ++- - src/responder/kcm/kcm.c | 7 + - src/responder/kcm/kcmsrv_cmd.c | 10 +- - src/responder/kcm/kcmsrv_op_queue.c | 264 ++++++++++++++++++++++++++ - src/responder/kcm/kcmsrv_ops.c | 44 ++++- - src/responder/kcm/kcmsrv_ops.h | 1 + - src/responder/kcm/kcmsrv_pvt.h | 20 ++ - src/tests/cmocka/test_kcm_queue.c | 365 ++++++++++++++++++++++++++++++++++++ - 8 files changed, 721 insertions(+), 11 deletions(-) - create mode 100644 src/responder/kcm/kcmsrv_op_queue.c - create mode 100644 src/tests/cmocka/test_kcm_queue.c - -diff --git a/Makefile.am b/Makefile.am -index e9eaa312c91e3aee40bcf13c90a0ad8c683045d5..91afdd669aa11a3cc316588d3b51d7e8e9c91cb8 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -304,7 +304,10 @@ non_interactive_cmocka_based_tests += test_inotify - endif # HAVE_INOTIFY - - if BUILD_KCM --non_interactive_cmocka_based_tests += test_kcm_json -+non_interactive_cmocka_based_tests += \ -+ test_kcm_json \ -+ test_kcm_queue \ -+ $(NULL) - endif # BUILD_KCM - - if BUILD_SAMBA -@@ -1501,6 +1504,7 @@ sssd_kcm_SOURCES = \ - src/responder/kcm/kcmsrv_ccache_json.c \ - src/responder/kcm/kcmsrv_ccache_secrets.c \ - src/responder/kcm/kcmsrv_ops.c \ -+ src/responder/kcm/kcmsrv_op_queue.c \ - src/util/sss_sockets.c \ - src/util/sss_krb5.c \ - src/util/sss_iobuf.c \ -@@ -3402,6 +3406,21 @@ test_kcm_json_LDADD = \ - $(SSSD_INTERNAL_LTLIBS) \ - libsss_test_common.la \ - $(NULL) -+ -+test_kcm_queue_SOURCES = \ -+ src/tests/cmocka/test_kcm_queue.c \ -+ src/responder/kcm/kcmsrv_op_queue.c \ -+ $(NULL) -+test_kcm_queue_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(NULL) -+test_kcm_queue_LDADD = \ -+ $(CMOCKA_LIBS) \ -+ $(SSSD_LIBS) \ -+ $(SSSD_INTERNAL_LTLIBS) \ -+ libsss_test_common.la \ -+ $(NULL) -+ - endif # BUILD_KCM - - endif # HAVE_CMOCKA -diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c -index 063c27b915b4b92f6259496feee891aa94a498b6..3ee978066c589a5cc38b0ae358f741d389d00e7a 100644 ---- a/src/responder/kcm/kcm.c -+++ b/src/responder/kcm/kcm.c -@@ -133,6 +133,13 @@ static int kcm_get_config(struct kcm_ctx *kctx) - goto done; - } - -+ kctx->qctx = kcm_ops_queue_create(kctx); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot create KCM request queue [%d]: %s\n", -+ ret, strerror(ret)); -+ goto done; -+ } - ret = EOK; - done: - return ret; -diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c -index 537e88953fd1a190a9a73bcdd430d8e0db8f9291..81015de4a91617de3dca444cde95b636c8d5c0d1 100644 ---- a/src/responder/kcm/kcmsrv_cmd.c -+++ b/src/responder/kcm/kcmsrv_cmd.c -@@ -353,14 +353,18 @@ struct kcm_req_ctx { - - static void kcm_cmd_request_done(struct tevent_req *req); - --static errno_t kcm_cmd_dispatch(struct kcm_req_ctx *req_ctx) -+static errno_t kcm_cmd_dispatch(struct kcm_ctx *kctx, -+ struct kcm_req_ctx *req_ctx) - { - struct tevent_req *req; - struct cli_ctx *cctx; - - cctx = req_ctx->cctx; - -- req = kcm_cmd_send(req_ctx, cctx->ev, req_ctx->kctx->kcm_data, -+ req = kcm_cmd_send(req_ctx, -+ cctx->ev, -+ kctx->qctx, -+ req_ctx->kctx->kcm_data, - req_ctx->cctx->creds, - &req_ctx->op_io.request, - req_ctx->op_io.op); -@@ -505,7 +509,7 @@ static void kcm_recv(struct cli_ctx *cctx) - /* do not read anymore, client is done sending */ - TEVENT_FD_NOT_READABLE(cctx->cfde); - -- ret = kcm_cmd_dispatch(req); -+ ret = kcm_cmd_dispatch(kctx, req); - if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, - "Failed to dispatch KCM operation [%d]: %s\n", -diff --git a/src/responder/kcm/kcmsrv_op_queue.c b/src/responder/kcm/kcmsrv_op_queue.c -new file mode 100644 -index 0000000000000000000000000000000000000000..f6c425dd5b64877c8b7401e488dd6565157fc9b5 ---- /dev/null -+++ b/src/responder/kcm/kcmsrv_op_queue.c -@@ -0,0 +1,264 @@ -+/* -+ SSSD -+ -+ KCM Server - the KCM operations wait queue -+ -+ Copyright (C) Red Hat, 2017 -+ -+ 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 "util/util.h" -+#include "util/util_creds.h" -+#include "responder/kcm/kcmsrv_pvt.h" -+ -+#define QUEUE_HASH_SIZE 32 -+ -+struct kcm_ops_queue_entry { -+ struct tevent_req *req; -+ uid_t uid; -+ -+ hash_table_t *wait_queue_hash; -+ -+ struct kcm_ops_queue_entry *head; -+ struct kcm_ops_queue_entry *next; -+ struct kcm_ops_queue_entry *prev; -+}; -+ -+struct kcm_ops_queue_ctx { -+ /* UID: dlist of kcm_ops_queue_entry */ -+ hash_table_t *wait_queue_hash; -+}; -+ -+/* -+ * Per-UID wait queue -+ * -+ * They key in the hash table is the UID of the peer. The value of each -+ * hash table entry is a linked list of kcm_ops_queue_entry structures -+ * which primarily hold the tevent request being queued. -+ */ -+struct kcm_ops_queue_ctx *kcm_ops_queue_create(TALLOC_CTX *mem_ctx) -+{ -+ errno_t ret; -+ struct kcm_ops_queue_ctx *queue_ctx; -+ -+ queue_ctx = talloc_zero(mem_ctx, struct kcm_ops_queue_ctx); -+ if (queue_ctx == NULL) { -+ return NULL; -+ } -+ -+ ret = sss_hash_create_ex(mem_ctx, QUEUE_HASH_SIZE, -+ &queue_ctx->wait_queue_hash, 0, 0, 0, 0, -+ NULL, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "sss_hash_create failed [%d]: %s\n", ret, sss_strerror(ret)); -+ talloc_free(queue_ctx); -+ return NULL; -+ } -+ -+ return queue_ctx; -+} -+ -+static int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry) -+{ -+ int ret; -+ struct kcm_ops_queue_entry *next_entry; -+ hash_key_t key; -+ -+ if (entry == NULL) { -+ return 1; -+ } -+ -+ /* Take the next entry from the queue */ -+ next_entry = entry->next; -+ -+ /* Remove the current entry from the queue */ -+ DLIST_REMOVE(entry->head, entry); -+ -+ if (next_entry == NULL) { -+ key.type = HASH_KEY_ULONG; -+ key.ul = entry->uid; -+ -+ /* If this was the last entry, remove the key (the UID) from the -+ * hash table to signal the queue is empty -+ */ -+ ret = hash_delete(entry->wait_queue_hash, &key); -+ if (ret != HASH_SUCCESS) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to remove wait queue for user %"SPRIuid"\n", -+ entry->uid); -+ return 1; -+ } -+ return 0; -+ } -+ -+ /* Otherwise, mark the current head as done to run the next request */ -+ tevent_req_done(next_entry->req); -+ return 0; -+} -+ -+static errno_t kcm_op_queue_add(hash_table_t *wait_queue_hash, -+ struct kcm_ops_queue_entry *entry, -+ uid_t uid) -+{ -+ errno_t ret; -+ hash_key_t key; -+ hash_value_t value; -+ struct kcm_ops_queue_entry *head = NULL; -+ -+ key.type = HASH_KEY_ULONG; -+ key.ul = uid; -+ -+ ret = hash_lookup(wait_queue_hash, &key, &value); -+ switch (ret) { -+ case HASH_SUCCESS: -+ /* The key with this UID already exists. Its value is request queue -+ * for the UID, so let's just add the current request to the end -+ * of the queue and wait for the previous requests to finish -+ */ -+ if (value.type != HASH_VALUE_PTR) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected hash value type.\n"); -+ return EINVAL; -+ } -+ -+ head = talloc_get_type(value.ptr, struct kcm_ops_queue_entry); -+ if (head == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid queue pointer\n"); -+ return EINVAL; -+ } -+ -+ entry->head = head; -+ DLIST_ADD_END(head, entry, struct kcm_ops_queue_entry *); -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "Waiting in queue\n"); -+ ret = EAGAIN; -+ break; -+ -+ case HASH_ERROR_KEY_NOT_FOUND: -+ /* No request for this UID yet. Enqueue this request in case -+ * another one comes in and return EOK to run the current request -+ * immediatelly -+ */ -+ entry->head = entry; -+ -+ value.type = HASH_VALUE_PTR; -+ value.ptr = entry; -+ -+ ret = hash_enter(wait_queue_hash, &key, &value); -+ if (ret != HASH_SUCCESS) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "hash_enter failed.\n"); -+ return EIO; -+ } -+ -+ DEBUG(SSSDBG_TRACE_LIBS, -+ "Added a first request to the queue, running immediately\n"); -+ ret = EOK; -+ break; -+ -+ default: -+ DEBUG(SSSDBG_CRIT_FAILURE, "hash_lookup failed.\n"); -+ return EIO; -+ } -+ -+ talloc_steal(wait_queue_hash, entry); -+ talloc_set_destructor(entry, kcm_op_queue_entry_destructor); -+ return ret; -+} -+ -+struct kcm_op_queue_state { -+ struct kcm_ops_queue_entry *entry; -+}; -+ -+/* -+ * Enqueue a request. -+ * -+ * If the request queue /for the given ID/ is empty, that is, if this -+ * request is the first one in the queue, run the request immediatelly. -+ * -+ * Otherwise just add it to the queue and wait until the previous request -+ * finishes and only at that point mark the current request as done, which -+ * will trigger calling the recv function and allow the request to continue. -+ */ -+struct tevent_req *kcm_op_queue_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ops_queue_ctx *qctx, -+ struct cli_creds *client) -+{ -+ errno_t ret; -+ struct tevent_req *req; -+ struct kcm_op_queue_state *state; -+ uid_t uid; -+ -+ uid = cli_creds_get_uid(client); -+ -+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_queue_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ -+ state->entry = talloc_zero(state, struct kcm_ops_queue_entry); -+ if (state->entry == NULL) { -+ ret = ENOMEM; -+ goto immediate; -+ } -+ state->entry->req = req; -+ state->entry->uid = uid; -+ state->entry->wait_queue_hash = qctx->wait_queue_hash; -+ -+ DEBUG(SSSDBG_FUNC_DATA, -+ "Adding request by %"SPRIuid" to the wait queue\n", uid); -+ -+ ret = kcm_op_queue_add(qctx->wait_queue_hash, state->entry, uid); -+ if (ret == EOK) { -+ DEBUG(SSSDBG_TRACE_LIBS, -+ "Wait queue was empty, running immediately\n"); -+ goto immediate; -+ } else if (ret != EAGAIN) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot enqueue request [%d]: %s\n", ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "Waiting our turn in the queue\n"); -+ return req; -+ -+immediate: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+/* -+ * The queue recv function is called when this request is 'activated'. The queue -+ * entry should be allocated on the same memory context as the enqueued request -+ * to trigger freeing the kcm_ops_queue_entry structure destructor when the -+ * parent request is done and its tevent_req freed. This would in turn unblock -+ * the next request in the queue -+ */ -+errno_t kcm_op_queue_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ops_queue_entry **_entry) -+{ -+ struct kcm_op_queue_state *state = tevent_req_data(req, -+ struct kcm_op_queue_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *_entry = talloc_steal(mem_ctx, state->entry); -+ return EOK; -+} -diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c -index 50e8cc635424e15d53e3c8d122c5525044f59c8a..2feaf51f227ce9d90f706229ce7ac201b282dc6f 100644 ---- a/src/responder/kcm/kcmsrv_ops.c -+++ b/src/responder/kcm/kcmsrv_ops.c -@@ -67,17 +67,21 @@ struct kcm_op { - - struct kcm_cmd_state { - struct kcm_op *op; -+ struct tevent_context *ev; - -+ struct kcm_ops_queue_entry *queue_entry; - struct kcm_op_ctx *op_ctx; - struct sss_iobuf *reply; - - uint32_t op_ret; - }; - -+static void kcm_cmd_queue_done(struct tevent_req *subreq); - static void kcm_cmd_done(struct tevent_req *subreq); - - struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, -+ struct kcm_ops_queue_ctx *qctx, - struct kcm_resp_ctx *kcm_data, - struct cli_creds *client, - struct kcm_data *input, -@@ -93,6 +97,7 @@ struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, - return NULL; - } - state->op = op; -+ state->ev = ev; - - if (op == NULL) { - ret = EINVAL; -@@ -154,18 +159,43 @@ struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, - goto immediate; - } - -- subreq = op->fn_send(state, ev, state->op_ctx); -+ subreq = kcm_op_queue_send(state, ev, qctx, client); - if (subreq == NULL) { - ret = ENOMEM; - goto immediate; - } -+ tevent_req_set_callback(subreq, kcm_cmd_queue_done, req); -+ return req; -+ -+immediate: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void kcm_cmd_queue_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); -+ struct kcm_cmd_state *state = tevent_req_data(req, struct kcm_cmd_state); -+ errno_t ret; -+ -+ /* When this request finishes, it frees the queue_entry which unblocks -+ * other requests by the same UID -+ */ -+ ret = kcm_op_queue_recv(subreq, state, &state->queue_entry); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot acquire queue slot\n"); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ subreq = state->op->fn_send(state, state->ev, state->op_ctx); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } - tevent_req_set_callback(subreq, kcm_cmd_done, req); -- return req; -- --immediate: -- tevent_req_error(req, ret); -- tevent_req_post(req, ev); -- return req; - } - - static void kcm_cmd_done(struct tevent_req *subreq) -diff --git a/src/responder/kcm/kcmsrv_ops.h b/src/responder/kcm/kcmsrv_ops.h -index 8e6feaf56a10b73c8b6375aea9ef26c392b5b492..67d9f86026bf949548471f2280c130ebefd2f865 100644 ---- a/src/responder/kcm/kcmsrv_ops.h -+++ b/src/responder/kcm/kcmsrv_ops.h -@@ -34,6 +34,7 @@ const char *kcm_opt_name(struct kcm_op *op); - - struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, -+ struct kcm_ops_queue_ctx *qctx, - struct kcm_resp_ctx *kcm_data, - struct cli_creds *client, - struct kcm_data *input, -diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h -index 74f30c00014105ed533744779b02c5d42523722d..f081a6bf0c6e40d2f8a83b07f9bbc2abacff359d 100644 ---- a/src/responder/kcm/kcmsrv_pvt.h -+++ b/src/responder/kcm/kcmsrv_pvt.h -@@ -25,6 +25,7 @@ - #include "config.h" - - #include -+#include - #include "responder/common/responder.h" - - /* -@@ -65,6 +66,7 @@ struct kcm_ctx { - int fd_limit; - char *socket_path; - enum kcm_ccdb_be cc_be; -+ struct kcm_ops_queue_ctx *qctx; - - struct kcm_resp_ctx *kcm_data; - }; -@@ -78,4 +80,22 @@ int kcm_connection_setup(struct cli_ctx *cctx); - */ - krb5_error_code sss2krb5_error(errno_t err); - -+/* We enqueue all requests by the same UID to avoid concurrency issues -+ * especially when performing multiple round-trips to sssd-secrets. In -+ * future, we should relax the queue to allow multiple read-only operations -+ * if no write operations are in progress. -+ */ -+struct kcm_ops_queue_entry; -+ -+struct kcm_ops_queue_ctx *kcm_ops_queue_create(TALLOC_CTX *mem_ctx); -+ -+struct tevent_req *kcm_op_queue_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ops_queue_ctx *qctx, -+ struct cli_creds *client); -+ -+errno_t kcm_op_queue_recv(struct tevent_req *req, -+ TALLOC_CTX *mem_ctx, -+ struct kcm_ops_queue_entry **_entry); -+ - #endif /* __KCMSRV_PVT_H__ */ -diff --git a/src/tests/cmocka/test_kcm_queue.c b/src/tests/cmocka/test_kcm_queue.c -new file mode 100644 -index 0000000000000000000000000000000000000000..ba0d2405629960df5c623848f3207b7c80fa948d ---- /dev/null -+++ b/src/tests/cmocka/test_kcm_queue.c -@@ -0,0 +1,365 @@ -+/* -+ Copyright (C) 2017 Red Hat -+ -+ SSSD tests: Test KCM wait queue -+ -+ 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 "config.h" -+ -+#include -+#include -+ -+#include "util/util.h" -+#include "util/util_creds.h" -+#include "tests/cmocka/common_mock.h" -+#include "responder/kcm/kcmsrv_pvt.h" -+ -+#define INVALID_ID -1 -+#define FAST_REQ_ID 0 -+#define SLOW_REQ_ID 1 -+ -+#define FAST_REQ_DELAY 1 -+#define SLOW_REQ_DELAY 2 -+ -+struct timed_request_state { -+ struct tevent_context *ev; -+ struct kcm_ops_queue_ctx *qctx; -+ struct cli_creds *client; -+ int delay; -+ int req_id; -+ -+ struct kcm_ops_queue_entry *queue_entry; -+}; -+ -+static void timed_request_start(struct tevent_req *subreq); -+static void timed_request_done(struct tevent_context *ev, -+ struct tevent_timer *te, -+ struct timeval current_time, -+ void *pvt); -+ -+static struct tevent_req *timed_request_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct kcm_ops_queue_ctx *qctx, -+ struct cli_creds *client, -+ int delay, -+ int req_id) -+{ -+ struct tevent_req *req; -+ struct tevent_req *subreq; -+ struct timed_request_state *state; -+ -+ req = tevent_req_create(mem_ctx, &state, struct timed_request_state); -+ if (req == NULL) { -+ return NULL; -+ } -+ state->ev = ev; -+ state->qctx = qctx; -+ state->client = client; -+ state->delay = delay; -+ state->req_id = req_id; -+ -+ DEBUG(SSSDBG_TRACE_ALL, "Request %p with delay %d\n", req, delay); -+ -+ subreq = kcm_op_queue_send(state, ev, qctx, client); -+ if (subreq == NULL) { -+ return NULL; -+ } -+ tevent_req_set_callback(subreq, timed_request_start, req); -+ -+ return req; -+} -+ -+static void timed_request_start(struct tevent_req *subreq) -+{ -+ struct timeval tv; -+ struct tevent_timer *timeout = NULL; -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct timed_request_state *state = tevent_req_data(req, -+ struct timed_request_state); -+ errno_t ret; -+ -+ ret = kcm_op_queue_recv(subreq, state, &state->queue_entry); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tv = tevent_timeval_current_ofs(state->delay, 0); -+ timeout = tevent_add_timer(state->ev, state, tv, timed_request_done, req); -+ if (timeout == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ -+ return; -+} -+ -+static void timed_request_done(struct tevent_context *ev, -+ struct tevent_timer *te, -+ struct timeval current_time, -+ void *pvt) -+{ -+ struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); -+ DEBUG(SSSDBG_TRACE_ALL, "Request %p done\n", req); -+ tevent_req_done(req); -+} -+ -+static errno_t timed_request_recv(struct tevent_req *req, -+ int *req_id) -+{ -+ struct timed_request_state *state = tevent_req_data(req, -+ struct timed_request_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ *req_id = state->req_id; -+ return EOK; -+} -+ -+struct test_ctx { -+ struct kcm_ops_queue_ctx *qctx; -+ struct tevent_context *ev; -+ -+ int *req_ids; -+ -+ int num_requests; -+ int finished_requests; -+ bool done; -+ errno_t error; -+}; -+ -+static int setup_kcm_queue(void **state) -+{ -+ struct test_ctx *tctx; -+ -+ tctx = talloc_zero(NULL, struct test_ctx); -+ assert_non_null(tctx); -+ -+ tctx->ev = tevent_context_init(tctx); -+ assert_non_null(tctx->ev); -+ -+ tctx->qctx = kcm_ops_queue_create(tctx); -+ assert_non_null(tctx->qctx); -+ -+ *state = tctx; -+ return 0; -+} -+ -+static int teardown_kcm_queue(void **state) -+{ -+ struct test_ctx *tctx = talloc_get_type(*state, struct test_ctx); -+ talloc_free(tctx); -+ return 0; -+} -+ -+static void test_kcm_queue_done(struct tevent_req *req) -+{ -+ struct test_ctx *test_ctx = tevent_req_callback_data(req, -+ struct test_ctx); -+ int req_id = INVALID_ID; -+ -+ test_ctx->error = timed_request_recv(req, &req_id); -+ talloc_zfree(req); -+ if (test_ctx->error != EOK) { -+ test_ctx->done = true; -+ return; -+ } -+ -+ if (test_ctx->req_ids[test_ctx->finished_requests] != req_id) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Request %d finished, expected %d\n", -+ req_id, test_ctx->req_ids[test_ctx->finished_requests]); -+ test_ctx->error = EIO; -+ test_ctx->done = true; -+ return; -+ } -+ -+ test_ctx->finished_requests++; -+ if (test_ctx->finished_requests == test_ctx->num_requests) { -+ test_ctx->done = true; -+ return; -+ } -+} -+ -+/* -+ * Just make sure that a single pass through the queue works -+ */ -+static void test_kcm_queue_single(void **state) -+{ -+ struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx); -+ struct tevent_req *req; -+ struct cli_creds client; -+ static int req_ids[] = { 0 }; -+ -+ client.ucred.uid = getuid(); -+ client.ucred.gid = getgid(); -+ -+ req = timed_request_send(test_ctx, -+ test_ctx->ev, -+ test_ctx->qctx, -+ &client, 1, 0); -+ assert_non_null(req); -+ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx); -+ -+ test_ctx->num_requests = 1; -+ test_ctx->req_ids = req_ids; -+ -+ while (test_ctx->done == false) { -+ tevent_loop_once(test_ctx->ev); -+ } -+ assert_int_equal(test_ctx->error, EOK); -+} -+ -+/* -+ * Test that multiple requests from the same ID wait for one another -+ */ -+static void test_kcm_queue_multi_same_id(void **state) -+{ -+ struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx); -+ struct tevent_req *req; -+ struct cli_creds client; -+ /* The slow request will finish first because request from -+ * the same ID are serialized -+ */ -+ static int req_ids[] = { SLOW_REQ_ID, FAST_REQ_ID }; -+ -+ client.ucred.uid = getuid(); -+ client.ucred.gid = getgid(); -+ -+ req = timed_request_send(test_ctx, -+ test_ctx->ev, -+ test_ctx->qctx, -+ &client, -+ SLOW_REQ_DELAY, -+ SLOW_REQ_ID); -+ assert_non_null(req); -+ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx); -+ -+ req = timed_request_send(test_ctx, -+ test_ctx->ev, -+ test_ctx->qctx, -+ &client, -+ FAST_REQ_DELAY, -+ FAST_REQ_ID); -+ assert_non_null(req); -+ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx); -+ -+ test_ctx->num_requests = 2; -+ test_ctx->req_ids = req_ids; -+ -+ while (test_ctx->done == false) { -+ tevent_loop_once(test_ctx->ev); -+ } -+ assert_int_equal(test_ctx->error, EOK); -+} -+ -+/* -+ * Test that multiple requests from different IDs don't wait for one -+ * another and can run concurrently -+ */ -+static void test_kcm_queue_multi_different_id(void **state) -+{ -+ struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx); -+ struct tevent_req *req; -+ struct cli_creds client; -+ /* In this test, the fast request will finish sooner because -+ * both requests are from different IDs, allowing them to run -+ * concurrently -+ */ -+ static int req_ids[] = { FAST_REQ_ID, SLOW_REQ_ID }; -+ -+ client.ucred.uid = getuid(); -+ client.ucred.gid = getgid(); -+ -+ req = timed_request_send(test_ctx, -+ test_ctx->ev, -+ test_ctx->qctx, -+ &client, -+ SLOW_REQ_DELAY, -+ SLOW_REQ_ID); -+ assert_non_null(req); -+ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx); -+ -+ client.ucred.uid = getuid() + 1; -+ client.ucred.gid = getgid() + 1; -+ -+ req = timed_request_send(test_ctx, -+ test_ctx->ev, -+ test_ctx->qctx, -+ &client, -+ FAST_REQ_DELAY, -+ FAST_REQ_ID); -+ assert_non_null(req); -+ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx); -+ -+ test_ctx->num_requests = 2; -+ test_ctx->req_ids = req_ids; -+ -+ while (test_ctx->done == false) { -+ tevent_loop_once(test_ctx->ev); -+ } -+ assert_int_equal(test_ctx->error, EOK); -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ poptContext pc; -+ int opt; -+ int rv; -+ struct poptOption long_options[] = { -+ POPT_AUTOHELP -+ SSSD_DEBUG_OPTS -+ POPT_TABLEEND -+ }; -+ -+ const struct CMUnitTest tests[] = { -+ cmocka_unit_test_setup_teardown(test_kcm_queue_single, -+ setup_kcm_queue, -+ teardown_kcm_queue), -+ cmocka_unit_test_setup_teardown(test_kcm_queue_multi_same_id, -+ setup_kcm_queue, -+ teardown_kcm_queue), -+ cmocka_unit_test_setup_teardown(test_kcm_queue_multi_different_id, -+ setup_kcm_queue, -+ teardown_kcm_queue), -+ }; -+ -+ /* Set debug level to invalid value so we can deside if -d 0 was used. */ -+ debug_level = SSSDBG_INVALID; -+ -+ pc = poptGetContext(argv[0], argc, argv, long_options, 0); -+ while((opt = poptGetNextOpt(pc)) != -1) { -+ switch(opt) { -+ default: -+ fprintf(stderr, "\nInvalid option %s: %s\n\n", -+ poptBadOption(pc, 0), poptStrerror(opt)); -+ poptPrintUsage(pc, stderr, 0); -+ return 1; -+ } -+ } -+ poptFreeContext(pc); -+ -+ DEBUG_CLI_INIT(debug_level); -+ -+ /* Even though normally the tests should clean up after themselves -+ * they might not after a failed run. Remove the old db to be sure */ -+ tests_set_cwd(); -+ -+ rv = cmocka_run_group_tests(tests, NULL, NULL); -+ -+ return rv; -+} --- -2.9.3 - diff --git a/SOURCES/0035-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch b/SOURCES/0035-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch new file mode 100644 index 0000000..0854ab3 --- /dev/null +++ b/SOURCES/0035-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch @@ -0,0 +1,58 @@ +From 1f46fa6760913de0f757e39106936d24e5736912 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 7 Nov 2017 23:34:42 +0100 +Subject: [PATCH 35/35] LDAP: Improve error treatment from sdap_cli_connect() + in ldap_auth +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Because we weren't treating the errors coming from +sdap_cli_connect_recv() properly we ended up introducing a regression in +the commit add72860c7, related to offline authentication. + +From now on, let's properly treat errors coming from auth_connect_send(), +which were treated before by going offline when be_resolve_server_recv() +failed, and propagate ETIMEDOUT to the request, thus going offline and +allowing offline authentication on those cases. + +Related: +https://pagure.io/SSSD/sssd/issue/3451 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Sumit Bose +(cherry picked from commit 20d18db36096e3fa2636143a83a12a2e3a7f26d6) +--- + src/providers/ldap/ldap_auth.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c +index a3b1480aae4272d2e10f105a1eaf3a5816c3487c..2e0e2cfd6f8af2bf0c9ad15bd956a55a34777a3c 100644 +--- a/src/providers/ldap/ldap_auth.c ++++ b/src/providers/ldap/ldap_auth.c +@@ -716,8 +716,20 @@ static void auth_connect_done(struct tevent_req *subreq) + ret = sdap_cli_connect_recv(subreq, state, NULL, &state->sh, NULL); + talloc_zfree(subreq); + if (ret != EOK) { +- if (auth_connect_send(req) == NULL) { +- tevent_req_error(req, ENOMEM); ++ /* As sdap_cli_connect_recv() returns EIO in case all the servers are ++ * down and we have to go offline, let's treat it accordingly here and ++ * allow the PAM responder to with to offline authentication. ++ * ++ * Unfortunately, there's not much pattern within our code and the way ++ * to indicate we're going down in this part of the code is returning ++ * an ETIMEDOUT. ++ */ ++ if (ret == EIO) { ++ tevent_req_error(req, ETIMEDOUT); ++ } else { ++ if (auth_connect_send(req) == NULL) { ++ tevent_req_error(req, ENOMEM); ++ } + } + return; + } +-- +2.13.6 + diff --git a/SOURCES/0036-KCM-Idle-terminate-the-responder-if-the-secrets-back.patch b/SOURCES/0036-KCM-Idle-terminate-the-responder-if-the-secrets-back.patch deleted file mode 100644 index a466a17..0000000 --- a/SOURCES/0036-KCM-Idle-terminate-the-responder-if-the-secrets-back.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 7e6a8e7a6c37122fce8781e5f8e82458905960b3 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 21 Mar 2017 14:26:54 +0100 -Subject: [PATCH 36/36] KCM: Idle-terminate the responder if the secrets back - end is used -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Existing with memory database would be fatal as we keep the ccaches in -memory then, but if the ccaches are stored in sssd-secrets, we can just -exit on idle. - -Reviewed-by: Michal Židek -Reviewed-by: Simo Sorce ---- - src/config/cfg_rules.ini | 1 + - src/responder/kcm/kcm.c | 9 +++++++++ - 2 files changed, 10 insertions(+) - -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 67a5d1f5ad447a942b437ffd04a7f5d7cfe77d7f..933ebccd828189d923d2186753dfbc0b5c0814ce 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -281,6 +281,7 @@ option = client_idle_timeout - option = description - option = socket_path - option = ccache_storage -+option = responder_idle_timeout - - [rule/allowed_domain_options] - validator = ini_allowed_options -diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c -index 3ee978066c589a5cc38b0ae358f741d389d00e7a..2202f96381a2622a2c5433e281172287b325f960 100644 ---- a/src/responder/kcm/kcm.c -+++ b/src/responder/kcm/kcm.c -@@ -133,6 +133,15 @@ static int kcm_get_config(struct kcm_ctx *kctx) - goto done; - } - -+ if (kctx->cc_be == CCDB_BE_SECRETS) { -+ ret = responder_setup_idle_timeout_config(kctx->rctx); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Cannot set up idle responder timeout\n"); -+ /* Not fatal */ -+ } -+ } -+ - kctx->qctx = kcm_ops_queue_create(kctx); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, --- -2.9.3 - diff --git a/SOURCES/0036-p11_child-return-multiple-certs.patch b/SOURCES/0036-p11_child-return-multiple-certs.patch new file mode 100644 index 0000000..d504f7f --- /dev/null +++ b/SOURCES/0036-p11_child-return-multiple-certs.patch @@ -0,0 +1,598 @@ +From 426dd731fe7c804c4b9d96c62d1a60a9022dcb09 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 17 Jan 2017 15:55:18 +0100 +Subject: [PATCH 36/46] p11_child: return multiple certs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch refactors the handling of certificates in p11_child. Not only +the first but all certificates suitable for authentication are returned. +The PAM responder component calling p11_child is refactored to handle +multiple certificate returned by p11_child but so far only returns the +first one to its callers. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +(cherry picked from commit 39fd336e4390ece3a8465714735ef4203f329e54) +--- + src/p11_child/p11_child_nss.c | 131 +++++++++++++--------- + src/responder/pam/pamsrv.h | 2 + + src/responder/pam/pamsrv_p11.c | 242 +++++++++++++++++++++++------------------ + 3 files changed, 219 insertions(+), 156 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index b0ec69be321c4b4186ce851c07bfcc3e1afe9694..50bde2f4f91f6c00260b0db383d0962112686ebc 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -72,8 +72,7 @@ static char *password_passthrough(PK11SlotInfo *slot, PRBool retry, void *arg) + int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + enum op_mode mode, const char *pin, + struct cert_verify_opts *cert_verify_opts, +- char **cert, char **token_name_out, char **module_name_out, +- char **key_id_out) ++ char **_multi) + { + int ret; + SECStatus rv; +@@ -110,7 +109,10 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + PK11SlotListElement *le; + SECItem *key_id = NULL; + char *key_id_str = NULL; +- ++ CERTCertList *valid_certs = NULL; ++ char *cert_b64 = NULL; ++ char *multi = NULL; ++ PRCList *node; + + nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, ¶meters, flags); + if (nss_ctx == NULL) { +@@ -303,6 +305,14 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + } + + found_cert = NULL; ++ valid_certs = CERT_NewCertList(); ++ if (valid_certs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_NewCertList failed [%d].\n", ++ PR_GetError()); ++ ret = ENOMEM; ++ goto done; ++ } ++ + DEBUG(SSSDBG_TRACE_ALL, "Filtered certificates:\n"); + for (cert_list_node = CERT_LIST_HEAD(cert_list); + !CERT_LIST_END(cert_list_node, cert_list); +@@ -326,6 +336,13 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + } + } + ++ rv = CERT_AddCertToListTail(valid_certs, cert_list_node->cert); ++ if (rv != SECSuccess) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "CERT_AddCertToListTail failed [%d].\n", PR_GetError()); ++ ret = EIO; ++ goto done; ++ } + + if (found_cert == NULL) { + found_cert = cert_list_node->cert; +@@ -352,9 +369,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + + if (found_cert == NULL) { + DEBUG(SSSDBG_TRACE_ALL, "No certificate found.\n"); +- *cert = NULL; +- *token_name_out = NULL; +- *module_name_out = NULL; ++ *_multi = NULL; + ret = EOK; + goto done; + } +@@ -421,51 +436,55 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + "Certificate verified and validated.\n"); + } + +- key_id = PK11_GetLowLevelKeyIDForCert(slot, found_cert, NULL); +- if (key_id == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "PK11_GetLowLevelKeyIDForCert failed [%d].\n", +- PR_GetError()); +- ret = EINVAL; +- goto done; +- } +- +- key_id_str = CERT_Hexify(key_id, PR_FALSE); +- if (key_id_str == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", PR_GetError()); ++ multi = talloc_strdup(mem_ctx, ""); ++ if (multi == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create output string.\n"); + ret = ENOMEM; + goto done; + } + +- DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n", key_id_str); ++ for (cert_list_node = CERT_LIST_HEAD(valid_certs); ++ !CERT_LIST_END(cert_list_node, valid_certs); ++ cert_list_node = CERT_LIST_NEXT(cert_list_node)) { + +- *key_id_out = talloc_strdup(mem_ctx, key_id_str); +- if (*key_id_out == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy key id.\n"); +- ret = ENOMEM; +- goto done; +- } ++ found_cert = cert_list_node->cert; + +- *cert = sss_base64_encode(mem_ctx, found_cert->derCert.data, +- found_cert->derCert.len); +- if (*cert == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "sss_base64_encode failed.\n"); +- ret = ENOMEM; +- goto done; +- } ++ SECITEM_FreeItem(key_id, PR_TRUE); ++ PORT_Free(key_id_str); ++ key_id = PK11_GetLowLevelKeyIDForCert(slot, found_cert, NULL); ++ if (key_id == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "PK11_GetLowLevelKeyIDForCert failed [%d].\n", ++ PR_GetError()); ++ ret = EINVAL; ++ goto done; ++ } + +- *token_name_out = talloc_strdup(mem_ctx, token_name); +- if (*token_name_out == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy slot name.\n"); +- ret = ENOMEM; +- goto done; +- } ++ key_id_str = CERT_Hexify(key_id, PR_FALSE); ++ if (key_id_str == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", ++ PR_GetError()); ++ ret = ENOMEM; ++ goto done; ++ } + +- *module_name_out = talloc_strdup(mem_ctx, module_name); +- if (*module_name_out == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy module_name_out name.\n"); +- ret = ENOMEM; +- goto done; ++ talloc_free(cert_b64); ++ cert_b64 = sss_base64_encode(mem_ctx, found_cert->derCert.data, ++ found_cert->derCert.len); ++ if (cert_b64 == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_base64_encode failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n", ++ key_id_str); ++ ++ multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n", ++ token_name, module_name, key_id_str, ++ cert_b64); + } ++ *_multi = multi; + + ret = EOK; + +@@ -474,6 +493,18 @@ done: + PK11_FreeSlot(slot); + } + ++ if (valid_certs != NULL) { ++ /* The certificates can be found in valid_certs and cert_list and ++ * CERT_DestroyCertList() will free the certificates as well. To avoid ++ * a double free the nodes from valid_certs are removed first because ++ * valid_certs will only have a sub-set of the certificates. */ ++ while (!PR_CLIST_IS_EMPTY(&valid_certs->list)) { ++ node = PR_LIST_HEAD(&valid_certs->list); ++ PR_REMOVE_LINK(node); ++ } ++ CERT_DestroyCertList(valid_certs); ++ } ++ + if (cert_list != NULL) { + CERT_DestroyCertList(cert_list); + } +@@ -483,6 +514,8 @@ done: + + PORT_Free(signed_random_value.data); + ++ talloc_free(cert_b64); ++ + rv = NSS_ShutdownContext(nss_ctx); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d].\n", +@@ -540,17 +573,14 @@ int main(int argc, const char *argv[]) + const char *opt_logger = NULL; + errno_t ret; + TALLOC_CTX *main_ctx = NULL; +- char *cert; + enum op_mode mode = OP_NONE; + enum pin_mode pin_mode = PIN_NONE; + char *pin = NULL; + char *slot_name_in = NULL; +- char *token_name_out = NULL; +- char *module_name_out = NULL; +- char *key_id_out = NULL; + char *nss_db = NULL; + struct cert_verify_opts *cert_verify_opts; + char *verify_opts = NULL; ++ char *multi = NULL; + + struct poptOption long_options[] = { + POPT_AUTOHELP +@@ -715,17 +745,14 @@ int main(int argc, const char *argv[]) + } + + ret = do_work(main_ctx, nss_db, slot_name_in, mode, pin, cert_verify_opts, +- &cert, &token_name_out, &module_name_out, &key_id_out); ++ &multi); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n"); + goto fail; + } + +- if (cert != NULL) { +- fprintf(stdout, "%s\n", token_name_out); +- fprintf(stdout, "%s\n", module_name_out); +- fprintf(stdout, "%s\n", key_id_out); +- fprintf(stdout, "%s\n", cert); ++ if (multi != NULL) { ++ fprintf(stdout, "%s", multi); + } + + talloc_free(main_ctx); +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index 57a37b72594f030995f5e22255eb7a8fcd63d10e..896f71befbc9947a53b5eb20cba0bb3d104c4cf2 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -88,6 +88,8 @@ int LOCAL_pam_handler(struct pam_auth_req *preq); + + errno_t p11_child_init(struct pam_ctx *pctx); + ++struct cert_auth_info; ++ + struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int child_debug_fd, +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index 4dce43800c3c6b026c545df35c846269cbb49610..ff32d1e726808caa36ca7cca557220866ef1a9ab 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -35,6 +35,15 @@ + #define P11_CHILD_LOG_FILE "p11_child" + #define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child" + ++struct cert_auth_info { ++ char *cert; ++ char *token_name; ++ char *module_name; ++ char *key_id; ++ struct cert_auth_info *prev; ++ struct cert_auth_info *next; ++}; ++ + errno_t p11_child_init(struct pam_ctx *pctx) + { + return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd); +@@ -132,18 +141,15 @@ static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx, + } + + static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, +- ssize_t buf_len, char **_cert, +- char **_token_name, char **_module_name, +- char **_key_id) ++ ssize_t buf_len, ++ struct cert_auth_info **_cert_list) + { + int ret; + TALLOC_CTX *tmp_ctx = NULL; + uint8_t *p; + uint8_t *pn; +- char *cert = NULL; +- char *token_name = NULL; +- char *module_name = NULL; +- char *key_id = NULL; ++ struct cert_auth_info *cert_list = NULL; ++ struct cert_auth_info *cert_auth_info; + + if (buf_len < 0) { + DEBUG(SSSDBG_CRIT_FAILURE, +@@ -157,108 +163,132 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, + goto done; + } + +- p = memchr(buf, '\n', buf_len); +- if (p == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "Missing new-line in p11_child response.\n"); +- return EINVAL; +- } +- if (p == buf) { +- DEBUG(SSSDBG_OP_FAILURE, "Missing counter in p11_child response.\n"); +- return EINVAL; +- } +- + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + +- token_name = talloc_strndup(tmp_ctx, (char*) buf, (p - buf)); +- if (token_name == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); +- ret = ENOMEM; +- goto done; +- } ++ p = buf; + +- p++; +- pn = memchr(p, '\n', buf_len - (p - buf)); +- if (pn == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Missing new-line in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ do { ++ cert_auth_info = talloc_zero(tmp_ctx, struct cert_auth_info); ++ if (cert_auth_info == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); ++ return ENOMEM; ++ } + +- if (pn == p) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Missing module name in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ pn = memchr(p, '\n', buf_len - (p - buf)); ++ if (pn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing new-line in p11_child response.\n"); ++ return EINVAL; ++ } ++ if (pn == p) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing counter in p11_child response.\n"); ++ return EINVAL; ++ } + +- module_name = talloc_strndup(tmp_ctx, (char *) p, (pn - p)); +- if (module_name == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); +- ret = ENOMEM; +- goto done; +- } +- DEBUG(SSSDBG_TRACE_ALL, "Found module name [%s].\n", module_name); ++ cert_auth_info->token_name = talloc_strndup(cert_auth_info, (char *)p, ++ (pn - p)); ++ if (cert_auth_info->token_name == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "Found token name [%s].\n", ++ cert_auth_info->token_name); + +- p = ++pn; +- pn = memchr(p, '\n', buf_len - (p - buf)); +- if (pn == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Missing new-line in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ p = ++pn; ++ pn = memchr(p, '\n', buf_len - (p - buf)); ++ if (pn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing new-line in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } + +- if (pn == p) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Missing key id in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ if (pn == p) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing module name in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } + +- key_id = talloc_strndup(tmp_ctx, (char *) p, (pn - p)); +- if (key_id == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); +- ret = ENOMEM; +- goto done; +- } +- DEBUG(SSSDBG_TRACE_ALL, "Found key id [%s].\n", key_id); ++ cert_auth_info->module_name = talloc_strndup(cert_auth_info, (char *)p, ++ (pn - p)); ++ if (cert_auth_info->module_name == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "Found module name [%s].\n", ++ cert_auth_info->module_name); + +- p = pn + 1; +- pn = memchr(p, '\n', buf_len - (p - buf)); +- if (pn == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Missing new-line in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ p = ++pn; ++ pn = memchr(p, '\n', buf_len - (p - buf)); ++ if (pn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing new-line in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } + +- if (pn == p) { +- DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ if (pn == p) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing key id in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } + +- cert = talloc_strndup(tmp_ctx, (char *) p, (pn - p)); +- if(cert == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); +- ret = ENOMEM; +- goto done; +- } +- DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert); ++ cert_auth_info->key_id = talloc_strndup(cert_auth_info, (char *)p, ++ (pn - p)); ++ if (cert_auth_info->key_id == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "Found key id [%s].\n", cert_auth_info->key_id); ++ ++ p = ++pn; ++ pn = memchr(p, '\n', buf_len - (p - buf)); ++ if (pn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing new-line in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ if (pn == p) { ++ DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ cert_auth_info->cert = talloc_strndup(cert_auth_info, (char *)p, ++ (pn - p)); ++ if (cert_auth_info->cert == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert_auth_info->cert); ++ ++ DLIST_ADD(cert_list, cert_auth_info); ++ ++ p = ++pn; ++ } while ((pn - buf) < buf_len); + + ret = EOK; + + done: + if (ret == EOK) { +- *_token_name = talloc_steal(mem_ctx, token_name); +- *_cert = talloc_steal(mem_ctx, cert); +- *_module_name = talloc_steal(mem_ctx, module_name); +- *_key_id = talloc_steal(mem_ctx, key_id); ++ DLIST_FOR_EACH(cert_auth_info, cert_list) { ++ talloc_steal(mem_ctx, cert_auth_info); ++ } ++ ++ *_cert_list = cert_list; + } + + talloc_free(tmp_ctx); +@@ -273,10 +303,8 @@ struct pam_check_cert_state { + struct tevent_context *ev; + + struct child_io_fds *io; +- char *cert; +- char *token_name; +- char *module_name; +- char *key_id; ++ ++ struct cert_auth_info *cert_list; + }; + + static void p11_child_write_done(struct tevent_req *subreq); +@@ -349,9 +377,6 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + + state->ev = ev; + state->child_status = EFAULT; +- state->cert = NULL; +- state->token_name = NULL; +- state->module_name = NULL; + state->io = talloc(state, struct child_io_fds); + if (state->io == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n"); +@@ -514,11 +539,9 @@ static void p11_child_done(struct tevent_req *subreq) + + PIPE_FD_CLOSE(state->io->read_from_child_fd); + +- ret = parse_p11_child_response(state, buf, buf_len, &state->cert, +- &state->token_name, &state->module_name, +- &state->key_id); ++ ret = parse_p11_child_response(state, buf, buf_len, &state->cert_list); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_respose failed.\n"); ++ DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_response failed.\n"); + tevent_req_error(req, ret); + return; + } +@@ -551,20 +574,31 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + + TEVENT_REQ_RETURN_ON_ERROR(req); + ++ if (state->cert_list == NULL) { ++ *token_name = NULL; ++ *cert = NULL; ++ *module_name = NULL; ++ *key_id = NULL; ++ } ++ + if (cert != NULL) { +- *cert = talloc_steal(mem_ctx, state->cert); ++ *cert = (state->cert_list == NULL) ? NULL ++ : talloc_steal(mem_ctx, state->cert_list->cert); + } + + if (token_name != NULL) { +- *token_name = talloc_steal(mem_ctx, state->token_name); ++ *token_name = (state->cert_list == NULL) ? NULL ++ : talloc_steal(mem_ctx, state->cert_list->token_name); + } + + if (module_name != NULL) { +- *module_name = talloc_steal(mem_ctx, state->module_name); ++ *module_name = (state->cert_list == NULL) ? NULL ++ : talloc_steal(mem_ctx, state->cert_list->module_name); + } + + if (key_id != NULL) { +- *key_id = talloc_steal(mem_ctx, state->key_id); ++ *key_id = (state->cert_list == NULL) ? NULL ++ : talloc_steal(mem_ctx, state->cert_list->key_id); + } + + return EOK; +-- +2.13.6 + diff --git a/SOURCES/0037-CONFIGURE-Fix-fallback-if-pkg-config-for-uuid-is-mis.patch b/SOURCES/0037-CONFIGURE-Fix-fallback-if-pkg-config-for-uuid-is-mis.patch deleted file mode 100644 index bdf9ef7..0000000 --- a/SOURCES/0037-CONFIGURE-Fix-fallback-if-pkg-config-for-uuid-is-mis.patch +++ /dev/null @@ -1,30 +0,0 @@ -From bb7c93869d53a412ce2537180752158861755ac4 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 27 Mar 2017 11:59:01 +0200 -Subject: [PATCH 37/54] CONFIGURE: Fix fallback if pkg-config for uuid is - missing -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Fabiano Fidêncio ---- - src/external/libuuid.m4 | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/external/libuuid.m4 b/src/external/libuuid.m4 -index 55411a2118bd787c9d50ba61f9cb791e1c76088d..323521c9224e443f40a15b417038d2dcea9b66f3 100644 ---- a/src/external/libuuid.m4 -+++ b/src/external/libuuid.m4 -@@ -4,7 +4,7 @@ AC_SUBST(UUID_CFLAGS) - PKG_CHECK_MODULES([UUID], [uuid], [found_uuid=yes], [found_uuid=no]) - - SSS_AC_EXPAND_LIB_DIR() --AS_IF([test x"$found_uuid" = xyes], -+AS_IF([test x"$found_uuid" != xyes], - [AC_CHECK_HEADERS([uuid/uuid.h], - [AC_CHECK_LIB([uuid], - [uuid_generate], --- -2.9.3 - diff --git a/SOURCES/0037-PAM-handled-multiple-certs-in-the-responder.patch b/SOURCES/0037-PAM-handled-multiple-certs-in-the-responder.patch new file mode 100644 index 0000000..dfac98b --- /dev/null +++ b/SOURCES/0037-PAM-handled-multiple-certs-in-the-responder.patch @@ -0,0 +1,1074 @@ +From f4cac6544b5b6fb094d2088bf75f443fb74028bc Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 25 Aug 2017 12:51:09 +0200 +Subject: [PATCH 37/47] PAM: handled multiple certs in the responder +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch refactors the handling of the certificate and the attributes +to address the certificate on the Smartcard (module name, token name and +key id). Instead of using individual variables the values are put into a +new struct cert_auth_info. Since the new struct can be used as a list +the PAM responder can now handle multiple certificates on the Smartcard +and can send the needed data to pam_sss with multiple SSS_PAM_CERT_INFO +messages. + +Unit tests are added to confirm the expected behavior. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +(cherry picked from commit 0bdd8800c16f39b8fe308d20694ad905c669dff3) + +The following binaries have been removed from the original patch: +- src/tests/cmocka/p11_nssdb_2certs/cert9.db +- src/tests/cmocka/p11_nssdb_2certs/key4.db + +The reason for that is that we can't apply a patch which is a binary +file using rpm, thus removing the patches here and adding them as source +files in the sssd.spec seems to be the best solution. +--- + Makefile.am | 2 + + src/responder/pam/pamsrv.h | 25 ++- + src/responder/pam/pamsrv_cmd.c | 257 ++++++++++++++++++--------- + src/responder/pam/pamsrv_p11.c | 181 ++++++++++++++----- + src/tests/cmocka/p11_nssdb_2certs/pkcs11.txt | 4 + + src/tests/cmocka/test_pam_srv.c | 216 +++++++++++++++++++++- + src/tests/whitespace_test | 2 +- + 7 files changed, 538 insertions(+), 149 deletions(-) + create mode 100644 src/tests/cmocka/p11_nssdb_2certs/pkcs11.txt + +diff --git a/Makefile.am b/Makefile.am +index bbc90d9bad4d22ca0284ea95281a487d42399c05..4ed872a532daf9b934537cc5f64ce77778121e2a 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -481,6 +481,8 @@ dist_noinst_DATA = \ + contrib/ci/sssd.supp \ + src/tests/cmocka/p11_nssdb/cert9.db \ + src/tests/cmocka/p11_nssdb/key4.db \ ++ src/tests/cmocka/p11_nssdb_2certs/cert9.db \ ++ src/tests/cmocka/p11_nssdb_2certs/key4.db \ + $(SYSTEMTAP_PROBES) \ + $(NULL) + +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index 896f71befbc9947a53b5eb20cba0bb3d104c4cf2..f15f7f19f1f38626288416c9f2038371c6f58b47 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -73,10 +73,8 @@ struct pam_auth_req { + struct pam_auth_dp_req *dpreq_spy; + + struct ldb_message *user_obj; +- struct ldb_result *cert_user_objs; +- char *token_name; +- char *module_name; +- char *key_id; ++ struct cert_auth_info *cert_list; ++ struct cert_auth_info *current_cert; + bool cert_auth_local; + }; + +@@ -89,6 +87,16 @@ int LOCAL_pam_handler(struct pam_auth_req *preq); + errno_t p11_child_init(struct pam_ctx *pctx); + + struct cert_auth_info; ++const char *sss_cai_get_cert(struct cert_auth_info *i); ++const char *sss_cai_get_token_name(struct cert_auth_info *i); ++const char *sss_cai_get_module_name(struct cert_auth_info *i); ++const char *sss_cai_get_key_id(struct cert_auth_info *i); ++struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i); ++struct ldb_result *sss_cai_get_cert_user_objs(struct cert_auth_info *i); ++void sss_cai_set_cert_user_objs(struct cert_auth_info *i, ++ struct ldb_result *cert_user_objs); ++void sss_cai_check_users(struct cert_auth_info **list, size_t *_cert_count, ++ size_t *_cert_user_count); + + struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +@@ -98,12 +106,11 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + const char *verify_opts, + struct pam_data *pd); + errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, +- char **cert, char **token_name, char **module_name, +- char **key_id); ++ struct cert_auth_info **cert_list); + +-errno_t add_pam_cert_response(struct pam_data *pd, const char *user, +- const char *token_name, const char *module_name, +- const char *key_id, enum response_type type); ++errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, ++ struct cert_auth_info *cert_info, ++ enum response_type type); + + bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd); + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index 51d8185650cf823da289a3398b10133065d82ae4..8b2c086e206796ad4c977495be957c56b3255e7f 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1389,21 +1389,17 @@ done: + return pam_check_user_done(preq, ret); + } + ++static errno_t pam_user_by_cert_step(struct pam_auth_req *preq); + static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req); + static void pam_forwarder_cert_cb(struct tevent_req *req) + { + struct pam_auth_req *preq = tevent_req_callback_data(req, + struct pam_auth_req); +- struct cli_ctx *cctx = preq->cctx; + struct pam_data *pd; + errno_t ret = EOK; +- char *cert; +- struct pam_ctx *pctx = +- talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx); ++ const char *cert; + +- ret = pam_check_cert_recv(req, preq, &cert, &preq->token_name, +- &preq->module_name, +- &preq->key_id); ++ ret = pam_check_cert_recv(req, preq, &preq->cert_list); + talloc_free(req); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "get_cert request failed.\n"); +@@ -1412,6 +1408,8 @@ static void pam_forwarder_cert_cb(struct tevent_req *req) + + pd = preq->pd; + ++ cert = sss_cai_get_cert(preq->cert_list); ++ + if (cert == NULL) { + if (pd->logon_name == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, +@@ -1431,21 +1429,42 @@ static void pam_forwarder_cert_cb(struct tevent_req *req) + goto done; + } + ++ preq->current_cert = preq->cert_list; ++ ret = pam_user_by_cert_step(preq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "pam_user_by_cert_step failed.\n"); ++ goto done; ++ } ++ ++ return; ++ ++done: ++ pam_check_user_done(preq, ret); ++} ++ ++static errno_t pam_user_by_cert_step(struct pam_auth_req *preq) ++{ ++ struct cli_ctx *cctx = preq->cctx; ++ struct tevent_req *req; ++ struct pam_ctx *pctx = ++ talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx); ++ ++ if (preq->current_cert == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Missing certificate data.\n"); ++ return EINVAL; ++ } + + req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx, + pctx->rctx->ncache, 0, + preq->req_dom_type, NULL, +- cert); ++ sss_cai_get_cert(preq->current_cert)); + if (req == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n"); +- ret = ENOMEM; +- goto done; ++ return ENOMEM; + } ++ + tevent_req_set_callback(req, pam_forwarder_lookup_by_cert_done, preq); +- return; +- +-done: +- pam_check_user_done(preq, ret); ++ return EOK; + } + + static errno_t get_results_from_all_domains(TALLOC_CTX *mem_ctx, +@@ -1511,6 +1530,9 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + struct pam_auth_req *preq = tevent_req_callback_data(req, + struct pam_auth_req); + const char *cert_user = NULL; ++ size_t cert_count = 0; ++ size_t cert_user_count = 0; ++ struct ldb_result *cert_user_objs; + + ret = cache_req_recv(preq, req, &results); + talloc_zfree(req); +@@ -1521,12 +1543,39 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + + if (ret == EOK) { + ret = get_results_from_all_domains(preq, results, +- &preq->cert_user_objs); ++ &cert_user_objs); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "get_results_from_all_domains failed.\n"); + goto done; + } + ++ sss_cai_set_cert_user_objs(preq->current_cert, cert_user_objs); ++ } ++ ++ preq->current_cert = sss_cai_get_next(preq->current_cert); ++ if (preq->current_cert != NULL) { ++ ret = pam_user_by_cert_step(preq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "pam_user_by_cert_step failed.\n"); ++ goto done; ++ } ++ return; ++ } ++ ++ sss_cai_check_users(&preq->cert_list, &cert_count, &cert_user_count); ++ DEBUG(SSSDBG_TRACE_ALL, ++ "Found [%zu] certificates and [%zu] related users.\n", ++ cert_count, cert_user_count); ++ ++ if (cert_user_count == 0) { ++ if (preq->pd->logon_name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Missing logon name and no certificate user found.\n"); ++ ret = ENOENT; ++ goto done; ++ } ++ } else { ++ + if (preq->pd->logon_name == NULL) { + if (preq->pd->cmd != SSS_PAM_PREAUTH) { + DEBUG(SSSDBG_CRIT_FAILURE, +@@ -1535,9 +1584,39 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + goto done; + } + +- if (preq->cert_user_objs->count == 1) { ++ if (cert_count > 1) { ++ for (preq->current_cert = preq->cert_list; ++ preq->current_cert != NULL; ++ preq->current_cert = sss_cai_get_next(preq->current_cert)) { ++ ++ ret = add_pam_cert_response(preq->pd, "", ++ preq->current_cert, ++ preq->cctx->rctx->domains->user_name_hint ++ ? SSS_PAM_CERT_INFO_WITH_HINT ++ : SSS_PAM_CERT_INFO); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "add_pam_cert_response failed.\n"); ++ preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; ++ } ++ } ++ ++ ret = EOK; ++ preq->pd->pam_status = PAM_SUCCESS; ++ pam_reply(preq); ++ goto done; ++ } ++ ++ if (cert_user_count == 1) { ++ cert_user_objs = sss_cai_get_cert_user_objs(preq->cert_list); ++ if (cert_user_objs == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Missing certificate user.\n"); ++ ret = ENOENT; ++ goto done; ++ } ++ + cert_user = ldb_msg_find_attr_as_string( +- preq->cert_user_objs->msgs[0], ++ cert_user_objs->msgs[0], + SYSDB_NAME, NULL); + if (cert_user == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, +@@ -1564,9 +1643,7 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + + if (preq->cctx->rctx->domains->user_name_hint) { + ret = add_pam_cert_response(preq->pd, cert_user, +- preq->token_name, +- preq->module_name, +- preq->key_id, ++ preq->cert_list, + SSS_PAM_CERT_INFO_WITH_HINT); + preq->pd->pam_status = PAM_SUCCESS; + if (ret != EOK) { +@@ -1596,13 +1673,6 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + goto done; + } + } +- } else { +- if (preq->pd->logon_name == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Missing logon name and no certificate user found.\n"); +- ret = ENOENT; +- goto done; +- } + } + + if (preq->user_obj == NULL) { +@@ -1884,7 +1954,9 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) + struct pam_ctx *pctx = + talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx); + const char *cert_user; ++ struct ldb_result *cert_user_objs; + size_t c; ++ bool found = false; + + if (!preq->pd->domain) { + preq->pd->domain = preq->domain->name; +@@ -1921,76 +1993,87 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) + return; + } + +- if (may_do_cert_auth(pctx, preq->pd) && preq->cert_user_objs != NULL) { ++ if (may_do_cert_auth(pctx, preq->pd) && preq->cert_list != NULL) { + /* Check if user matches certificate user */ +- for (c = 0; c < preq->cert_user_objs->count; c++) { +- cert_user = ldb_msg_find_attr_as_string( +- preq->cert_user_objs->msgs[c], +- SYSDB_NAME, +- NULL); +- if (cert_user == NULL) { +- /* Even if there might be other users mapped to the +- * certificate a missing SYSDB_NAME indicates some critical +- * condition which justifies that the whole request is aborted +- * */ +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Certificate user object has no name.\n"); +- preq->pd->pam_status = PAM_USER_UNKNOWN; +- pam_reply(preq); +- return; ++ found = false; ++ for (preq->current_cert = preq->cert_list; ++ preq->current_cert != NULL; ++ preq->current_cert = sss_cai_get_next(preq->current_cert)) { ++ ++ cert_user_objs = sss_cai_get_cert_user_objs(preq->current_cert); ++ if (cert_user_objs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Unexpteced missing certificate user, " ++ "trying next certificate.\n"); ++ continue; + } + +- /* pam_check_user_search() calls pd_set_primary_name() is the search +- * was successful, so pd->user contains the canonical sysdb name +- * as well */ +- if (ldb_dn_compare(preq->cert_user_objs->msgs[c]->dn, +- preq->user_obj->dn) == 0) { +- +- if (preq->pd->cmd == SSS_PAM_PREAUTH) { +- ret = sss_authtok_set_sc(preq->pd->authtok, +- SSS_AUTHTOK_TYPE_SC_PIN, NULL, 0, +- preq->token_name, 0, +- preq->module_name, 0, +- preq->key_id, 0); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_set_sc failed, " +- "Smartcard authentication " +- "detection might fail in the " +- "backend.\n"); +- } +- +- ret = add_pam_cert_response(preq->pd, cert_user, +- preq->token_name, +- preq->module_name, +- preq->key_id, +- SSS_PAM_CERT_INFO); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); +- preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; +- } +- } +- +- /* We are done if we do not have to call the backend */ +- if (preq->pd->cmd == SSS_PAM_AUTHENTICATE +- && preq->cert_auth_local) { +- preq->pd->pam_status = PAM_SUCCESS; +- preq->callback = pam_reply; ++ for (c = 0; c < cert_user_objs->count; c++) { ++ cert_user = ldb_msg_find_attr_as_string(cert_user_objs->msgs[c], ++ SYSDB_NAME, NULL); ++ if (cert_user == NULL) { ++ /* Even if there might be other users mapped to the ++ * certificate a missing SYSDB_NAME indicates some critical ++ * condition which justifies that the whole request is aborted ++ * */ ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Certificate user object has no name.\n"); ++ preq->pd->pam_status = PAM_USER_UNKNOWN; + pam_reply(preq); + return; + } ++ ++ if (ldb_dn_compare(cert_user_objs->msgs[c]->dn, ++ preq->user_obj->dn) == 0) { ++ found = true; ++ if (preq->pd->cmd == SSS_PAM_PREAUTH) { ++ ret = sss_authtok_set_sc(preq->pd->authtok, ++ SSS_AUTHTOK_TYPE_SC_PIN, NULL, 0, ++ sss_cai_get_token_name(preq->current_cert), 0, ++ sss_cai_get_module_name(preq->current_cert), 0, ++ sss_cai_get_key_id(preq->current_cert), 0); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sss_authtok_set_sc failed, Smartcard " ++ "authentication detection might fail in " ++ "the backend.\n"); ++ } ++ ++ /* FIXME: use the right cert info */ ++ ret = add_pam_cert_response(preq->pd, cert_user, ++ preq->current_cert, ++ SSS_PAM_CERT_INFO); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); ++ preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; ++ } ++ } ++ ++ } + } + } + +- if (preq->pd->cmd == SSS_PAM_PREAUTH) { +- DEBUG(SSSDBG_TRACE_FUNC, +- "User and certificate user do not match, " +- "continue with other authentication methods.\n"); ++ if (found) { ++ /* We are done if we do not have to call the backend */ ++ if (preq->pd->cmd == SSS_PAM_AUTHENTICATE ++ && preq->cert_auth_local) { ++ preq->pd->pam_status = PAM_SUCCESS; ++ preq->callback = pam_reply; ++ pam_reply(preq); ++ return; ++ } + } else { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "User and certificate user do not match.\n"); +- preq->pd->pam_status = PAM_AUTH_ERR; +- pam_reply(preq); +- return; ++ if (preq->pd->cmd == SSS_PAM_PREAUTH) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "User and certificate user do not match, " ++ "continue with other authentication methods.\n"); ++ } else { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "User and certificate user do not match.\n"); ++ preq->pd->pam_status = PAM_AUTH_ERR; ++ pam_reply(preq); ++ return; ++ } + } + } + +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index ff32d1e726808caa36ca7cca557220866ef1a9ab..57c8e1e464f4262f2d78f869c52ca48bd469d90a 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -40,10 +40,80 @@ struct cert_auth_info { + char *token_name; + char *module_name; + char *key_id; ++ struct ldb_result *cert_user_objs; + struct cert_auth_info *prev; + struct cert_auth_info *next; + }; + ++const char *sss_cai_get_cert(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->cert : NULL; ++} ++ ++const char *sss_cai_get_token_name(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->token_name : NULL; ++} ++ ++const char *sss_cai_get_module_name(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->module_name : NULL; ++} ++ ++const char *sss_cai_get_key_id(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->key_id : NULL; ++} ++ ++struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->next : NULL; ++} ++ ++struct ldb_result *sss_cai_get_cert_user_objs(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->cert_user_objs : NULL; ++} ++ ++void sss_cai_set_cert_user_objs(struct cert_auth_info *i, ++ struct ldb_result *cert_user_objs) ++{ ++ if (i->cert_user_objs != NULL) { ++ talloc_free(i->cert_user_objs); ++ } ++ i->cert_user_objs = talloc_steal(i, cert_user_objs); ++} ++ ++void sss_cai_check_users(struct cert_auth_info **list, size_t *_cert_count, ++ size_t *_cert_user_count) ++{ ++ struct cert_auth_info *c; ++ struct cert_auth_info *tmp; ++ size_t cert_count = 0; ++ size_t cert_user_count = 0; ++ struct ldb_result *user_objs; ++ ++ DLIST_FOR_EACH_SAFE(c, tmp, *list) { ++ user_objs = sss_cai_get_cert_user_objs(c); ++ if (user_objs != NULL) { ++ cert_count++; ++ cert_user_count += user_objs->count; ++ } else { ++ DLIST_REMOVE(*list, c); ++ } ++ } ++ ++ if (_cert_count != NULL) { ++ *_cert_count = cert_count; ++ } ++ ++ if (_cert_user_count != NULL) { ++ *_cert_user_count = cert_user_count; ++ } ++ ++ return; ++} ++ + errno_t p11_child_init(struct pam_ctx *pctx) + { + return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd); +@@ -566,39 +636,71 @@ static void p11_child_timeout(struct tevent_context *ev, + } + + errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, +- char **cert, char **token_name, char **module_name, +- char **key_id) ++ struct cert_auth_info **cert_list) + { ++ struct cert_auth_info *tmp_cert_auth_info; + struct pam_check_cert_state *state = + tevent_req_data(req, struct pam_check_cert_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + +- if (state->cert_list == NULL) { +- *token_name = NULL; +- *cert = NULL; +- *module_name = NULL; +- *key_id = NULL; ++ if (cert_list != NULL) { ++ DLIST_FOR_EACH(tmp_cert_auth_info, state->cert_list) { ++ talloc_steal(mem_ctx, tmp_cert_auth_info); ++ } ++ ++ *cert_list = state->cert_list; + } + +- if (cert != NULL) { +- *cert = (state->cert_list == NULL) ? NULL +- : talloc_steal(mem_ctx, state->cert_list->cert); ++ return EOK; ++} ++ ++static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, ++ struct cert_auth_info *cert_info, ++ uint8_t **_msg, size_t *_msg_len) ++{ ++ uint8_t *msg = NULL; ++ size_t msg_len; ++ const char *token_name; ++ const char *module_name; ++ const char *key_id; ++ size_t user_len; ++ size_t token_len; ++ size_t module_len; ++ size_t key_id_len; ++ const char *username = ""; ++ ++ if (sysdb_username != NULL) { ++ username = sysdb_username; + } + +- if (token_name != NULL) { +- *token_name = (state->cert_list == NULL) ? NULL +- : talloc_steal(mem_ctx, state->cert_list->token_name); ++ token_name = sss_cai_get_token_name(cert_info); ++ module_name = sss_cai_get_module_name(cert_info); ++ key_id = sss_cai_get_key_id(cert_info); ++ ++ user_len = strlen(username) + 1; ++ token_len = strlen(token_name) + 1; ++ module_len = strlen(module_name) + 1; ++ key_id_len = strlen(key_id) + 1; ++ msg_len = user_len + token_len + module_len + key_id_len; ++ ++ msg = talloc_zero_size(mem_ctx, msg_len); ++ if (msg == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); ++ return ENOMEM; + } + +- if (module_name != NULL) { +- *module_name = (state->cert_list == NULL) ? NULL +- : talloc_steal(mem_ctx, state->cert_list->module_name); ++ memcpy(msg, username, user_len); ++ memcpy(msg + user_len, token_name, token_len); ++ memcpy(msg + user_len + token_len, module_name, module_len); ++ memcpy(msg + user_len + token_len + module_len, key_id, key_id_len); ++ ++ if (_msg != NULL) { ++ *_msg = msg; + } + +- if (key_id != NULL) { +- *key_id = (state->cert_list == NULL) ? NULL +- : talloc_steal(mem_ctx, state->cert_list->key_id); ++ if (_msg_len != NULL) { ++ *_msg_len = msg_len; + } + + return EOK; +@@ -613,18 +715,13 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + #define PKCS11_LOGIN_TOKEN_ENV_NAME "PKCS11_LOGIN_TOKEN_NAME" + + errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, +- const char *token_name, const char *module_name, +- const char *key_id, enum response_type type) ++ struct cert_auth_info *cert_info, ++ enum response_type type) + { + uint8_t *msg = NULL; + char *env = NULL; +- size_t user_len; + size_t msg_len; +- size_t slot_len; +- size_t module_len; +- size_t key_id_len; + int ret; +- const char *username = ""; + + if (type != SSS_PAM_CERT_INFO && type != SSS_PAM_CERT_INFO_WITH_HINT) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid response type [%d].\n", type); +@@ -632,26 +729,14 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, + } + + if ((type == SSS_PAM_CERT_INFO && sysdb_username == NULL) +- || token_name == NULL || module_name == NULL || key_id == NULL) { ++ || cert_info == NULL ++ || sss_cai_get_token_name(cert_info) == NULL ++ || sss_cai_get_module_name(cert_info) == NULL ++ || sss_cai_get_key_id(cert_info) == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n"); + return EINVAL; + } + +- if (sysdb_username != NULL) { +- username = sysdb_username; +- } +- user_len = strlen(username) + 1; +- slot_len = strlen(token_name) + 1; +- module_len = strlen(module_name) + 1; +- key_id_len = strlen(key_id) + 1; +- msg_len = user_len + slot_len + module_len + key_id_len; +- +- msg = talloc_zero_size(pd, msg_len); +- if (msg == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); +- return ENOMEM; +- } +- + /* sysdb_username is a fully-qualified name which is used by pam_sss when + * prompting the user for the PIN and as login name if it wasn't set by + * the PAM caller but has to be determined based on the inserted +@@ -659,10 +744,12 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, + * re_expression config option was set in a way that user@domain cannot be + * handled anymore some more logic has to be added here. But for the time + * being I think using sysdb_username is fine. */ +- memcpy(msg, username, user_len); +- memcpy(msg + user_len, token_name, slot_len); +- memcpy(msg + user_len + slot_len, module_name, module_len); +- memcpy(msg + user_len + slot_len + module_len, key_id, key_id_len); ++ ++ ret = pack_cert_data(pd, sysdb_username, cert_info, &msg, &msg_len); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "pack_cert_data failed.\n"); ++ return ret; ++ } + + ret = pam_add_response(pd, type, msg_len, msg); + talloc_free(msg); +@@ -674,7 +761,7 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, + + if (strcmp(pd->service, "gdm-smartcard") == 0) { + env = talloc_asprintf(pd, "%s=%s", PKCS11_LOGIN_TOKEN_ENV_NAME, +- token_name); ++ sss_cai_get_token_name(cert_info)); + if (env == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); + return ENOMEM; +diff --git a/src/tests/cmocka/p11_nssdb_2certs/pkcs11.txt b/src/tests/cmocka/p11_nssdb_2certs/pkcs11.txt +new file mode 100644 +index 0000000000000000000000000000000000000000..73f5279c338dffe25ad2fad8c9cafae2f3c4cdfe +--- /dev/null ++++ b/src/tests/cmocka/p11_nssdb_2certs/pkcs11.txt +@@ -0,0 +1,4 @@ ++library= ++name=NSS Internal PKCS #11 Module ++parameters=configdir='sql:../src/tests/cmocka/p11_nssdb' certPrefix='' keyPrefix='' secmod='secmod.db' flags= updatedir='' updateCertPrefix='' updateKeyPrefix='' updateid='' updateTokenDescription='' ++NSS=Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={slotFlags=[RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512] askpw=any timeout=30}) +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 351067eb664431cda159f73590de772920504380..7f0ed706512ffe0866c0e1fb7e6baa16bec942d8 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -47,6 +47,9 @@ + #define NSS_DB_PATH TESTS_PATH + #define NSS_DB "sql:"NSS_DB_PATH + ++#define NSS_DB_PATH_2CERTS TESTS_PATH "_2certs" ++#define NSS_DB_2CERTS "sql:"NSS_DB_PATH_2CERTS ++ + #define TEST_TOKEN_NAME "SSSD Test Token" + #define TEST_MODULE_NAME "NSS-Internal" + #define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7" +@@ -74,6 +77,28 @@ + "8Z+9gqZhCa7FEKJOPNR9RVtJs0qUUutMZrp1zpyx0GTmXQBA7LbgPxy8L68uymEQ" \ + "XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g=" + ++#define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C" ++#define TEST_TOKEN_2ND_CERT \ ++"MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ ++"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ ++"NDEzMDFaFw0xODA1MTMxNDEzMDFaMCUxEjAQBgNVBAoMCUlQQS5ERVZFTDEPMA0G" \ ++"A1UEAwwGSVBBIFJBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3abE" \ ++"8LmIc6QN16VVxsMlN/rrCOoZKyyJolSzpP4+K66t+KZUiW/1j1MZogjyYyD39U1F" \ ++"zpa2H+pID74XYrdiqP7sp+uE9/k2XOv/nN3FobXDt+fSINLDriCmxNhUZqpgo2uq" \ ++"Mmka+yx2iJZwkntEoJTcd3aynoa2Sa2ZZbkMBy5p6/pUQKwnD6scOwe6mUDppIBK" \ ++"+ZZRm+u/NDdIRFI5wfKLRR1r/ONaJA9nz1TxSEsgLsjG/1m+Zbb6lGG4pePIFkQ9" \ ++"Iotpi64obBh93oIxzQR29lBG/FMjQVHlPIbx+xuGx11Vtp5pAomgFz0HRrj0leI7" \ ++"bROE+jnC/VGPLQD2aQIDAQABo4GWMIGTMB8GA1UdIwQYMBaAFPci/0Km5D/L5z7Y" \ ++"qwEc7E1/GwgcMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAYYlaHR0cDovL2lw" \ ++"YS1kZXZlbC5pcGEuZGV2ZWw6ODAvY2Evb2NzcDAOBgNVHQ8BAf8EBAMCBPAwHQYD" \ ++"VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBg" \ ++"4Sppx2C3eXPJ4Pd9XElkQPOaBReXf1vV0uk/GlK+rG+aAqAkA2Lryx5PK/iAuzAU" \ ++"M6JUpELuQYgqugoCgBXMgsMlpAO/0C3CFq4ZH3KgIsRlRngKPrt6RG0UPMRD1CE2" \ ++"tSVkwUWvyK83lDiu2BbWDXyMyz5eZOlp7uHusf5BKvob8jEndHj1YzaNTmVSsDM5" \ ++"kiIwf8qgFhsO1HCq08PtAnbVHhqkcvnmIJN98eNWNfTKodDmFVbN8gB0wK+WB5ii" \ ++"WVOw7+3/zF1QgqnYX3t+kPLRryip/wvTZkzXWwMNj/W6UHgjNF/4gWGoBgCHu+u3" \ ++"EvjMmbVSrEkesibpGQS5" ++ + + static char CACHED_AUTH_TIMEOUT_STR[] = "4"; + static const int CACHED_AUTH_TIMEOUT = 4; +@@ -111,6 +136,13 @@ static errno_t setup_nss_db(void) + return ret; + } + ++ ret = mkdir(NSS_DB_PATH_2CERTS, 0775); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to create " NSS_DB_PATH_2CERTS ".\n"); ++ return ret; ++ } ++ + child_pid = fork(); + if (child_pid == 0) { /* child */ + ret = execlp("certutil", "certutil", "-N", "--empty-password", "-d", +@@ -127,6 +159,22 @@ static errno_t setup_nss_db(void) + return ret; + } + ++ child_pid = fork(); ++ if (child_pid == 0) { /* child */ ++ ret = execlp("certutil", "certutil", "-N", "--empty-password", "-d", ++ NSS_DB_2CERTS, NULL); ++ if (ret == -1) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "execl() failed.\n"); ++ exit(-1); ++ } ++ } else if (child_pid > 0) { ++ wait(&status); ++ } else { ++ ret = errno; ++ DEBUG(SSSDBG_FATAL_FAILURE, "fork() failed\n"); ++ return ret; ++ } ++ + fp = fopen(NSS_DB_PATH"/pkcs11.txt", "w"); + if (fp == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "fopen() failed.\n"); +@@ -148,6 +196,27 @@ static errno_t setup_nss_db(void) + return ret; + } + ++ fp = fopen(NSS_DB_PATH_2CERTS"/pkcs11.txt", "w"); ++ if (fp == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fopen() failed.\n"); ++ return ret; ++ } ++ ret = fprintf(fp, "library=libsoftokn3.so\nname=soft\n"); ++ if (ret < 0) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n"); ++ return ret; ++ } ++ ret = fprintf(fp, "parameters=configdir='sql:%s/src/tests/cmocka/p11_nssdb_2certs' dbSlotDescription='SSSD Test Slot' dbTokenDescription='SSSD Test Token' secmod='secmod.db' flags=readOnly \n\n", ABS_SRC_DIR); ++ if (ret < 0) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n"); ++ return ret; ++ } ++ ret = fclose(fp); ++ if (ret != 0) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fclose() failed.\n"); ++ return ret; ++ } ++ + return EOK; + } + +@@ -174,6 +243,26 @@ static void cleanup_nss_db(void) + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to remove " NSS_DB_PATH "\n"); + } ++ ++ ret = unlink(NSS_DB_PATH_2CERTS"/cert9.db"); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove cert9.db.\n"); ++ } ++ ++ ret = unlink(NSS_DB_PATH_2CERTS"/key4.db"); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove key4.db.\n"); ++ } ++ ++ ret = unlink(NSS_DB_PATH_2CERTS"/pkcs11.txt"); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove pkcs11.db.\n"); ++ } ++ ++ ret = rmdir(NSS_DB_PATH_2CERTS); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove " NSS_DB_PATH "\n"); ++ } + } + + struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx) +@@ -749,7 +838,8 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + } + + static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, +- enum response_type type, const char *name) ++ enum response_type type, const char *name, ++ const char *name2) + { + size_t rp = 0; + uint32_t val; +@@ -763,7 +853,11 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + if (name == NULL || *name == '\0') { + assert_int_equal(val, 1); + } else { +- assert_int_equal(val, 2); ++ if (name2 == NULL || *name2 == '\0') { ++ assert_int_equal(val, 2); ++ } else { ++ assert_int_equal(val, 3); ++ } + + SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); + assert_int_equal(val, SSS_PAM_DOMAIN_NAME); +@@ -801,6 +895,33 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + ++ if (name2 != NULL && *name2 != '\0') { ++ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); ++ assert_int_equal(val, type); ++ ++ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); ++ assert_int_equal(val, (strlen(name) + 1 ++ + sizeof(TEST_TOKEN_NAME) ++ + sizeof(TEST_MODULE_NAME) ++ + sizeof(TEST2_KEY_ID))); ++ ++ assert_int_equal(*(body + rp + strlen(name)), 0); ++ assert_string_equal(body + rp, name); ++ rp += strlen(name) + 1; ++ ++ assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0); ++ assert_string_equal(body + rp, TEST_TOKEN_NAME); ++ rp += sizeof(TEST_TOKEN_NAME); ++ ++ assert_int_equal(*(body + rp + sizeof(TEST_MODULE_NAME) - 1), 0); ++ assert_string_equal(body + rp, TEST_MODULE_NAME); ++ rp += sizeof(TEST_MODULE_NAME); ++ ++ assert_int_equal(*(body + rp + sizeof(TEST2_KEY_ID) - 1), 0); ++ assert_string_equal(body + rp, TEST2_KEY_ID); ++ rp += sizeof(TEST2_KEY_ID); ++ } ++ + assert_int_equal(rp, blen); + + return EOK; +@@ -809,7 +930,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) + { + return test_pam_cert_check_ex(status, body, blen, +- SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME); ++ SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME, ++ NULL); + } + + static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body, +@@ -817,14 +939,22 @@ static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body, + { + return test_pam_cert_check_ex(status, body, blen, + SSS_PAM_CERT_INFO_WITH_HINT, +- "pamuser@"TEST_DOM_NAME); ++ "pamuser@"TEST_DOM_NAME, NULL); + } + + static int test_pam_cert_check_with_hint_no_user(uint32_t status, uint8_t *body, + size_t blen) + { + return test_pam_cert_check_ex(status, body, blen, +- SSS_PAM_CERT_INFO_WITH_HINT, ""); ++ SSS_PAM_CERT_INFO_WITH_HINT, "", NULL); ++} ++ ++static int test_pam_cert_check_2certs(uint32_t status, uint8_t *body, ++ size_t blen) ++{ ++ return test_pam_cert_check_ex(status, body, blen, ++ SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME, ++ "pamuser@"TEST_DOM_NAME); + } + + static int test_pam_offline_chauthtok_check(uint32_t status, +@@ -1737,6 +1867,33 @@ static int test_lookup_by_cert_cb(void *pvt) + + return EOK; + } ++static int test_lookup_by_cert_cb_2nd_cert_same_user(void *pvt) ++{ ++ int ret; ++ struct sysdb_attrs *attrs; ++ unsigned char *der = NULL; ++ size_t der_size; ++ ++ test_lookup_by_cert_cb(pvt); ++ ++ attrs = sysdb_new_attrs(pam_test_ctx); ++ assert_non_null(attrs); ++ ++ der = sss_base64_decode(pam_test_ctx, TEST_TOKEN_2ND_CERT, &der_size); ++ assert_non_null(der); ++ ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); ++ talloc_free(der); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_set_user_attr(pam_test_ctx->tctx->dom, ++ pam_test_ctx->pam_user_fqdn, ++ attrs, ++ LDB_FLAG_MOD_ADD); ++ assert_int_equal(ret, EOK); ++ ++ return EOK; ++} + + static int test_lookup_by_cert_double_cb(void *pvt) + { +@@ -2094,6 +2251,51 @@ void test_pam_cert_auth_double_cert(void **state) + assert_int_equal(ret, EOK); + } + ++void test_pam_cert_preauth_2certs_one_mapping(void **state) ++{ ++ int ret; ++ ++ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB_2CERTS); ++ ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, ++ test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_pam_cert_check); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_pam_cert_preauth_2certs_two_mappings(void **state) ++{ ++ int ret; ++ ++ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB_2CERTS); ++ ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, ++ test_lookup_by_cert_cb_2nd_cert_same_user, ++ TEST_TOKEN_CERT, false); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_pam_cert_check_2certs); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ + void test_filter_response(void **state) + { + int ret; +@@ -2523,6 +2725,10 @@ int main(int argc, const char *argv[]) + pam_test_teardown), + cmocka_unit_test_setup_teardown(test_pam_cert_auth_double_cert, + pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_pam_cert_preauth_2certs_one_mapping, ++ pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_pam_cert_preauth_2certs_two_mappings, ++ pam_test_setup, pam_test_teardown), + #endif /* HAVE_NSS */ + + cmocka_unit_test_setup_teardown(test_filter_response, +diff --git a/src/tests/whitespace_test b/src/tests/whitespace_test +index 799e35358b1d5ae4b10c4405068fb507cb234b6f..f055ed4c255db4001194844f45a9df7cda774b38 100755 +--- a/src/tests/whitespace_test ++++ b/src/tests/whitespace_test +@@ -39,7 +39,7 @@ fi + declare found_file=false + while read file; do + [[ $file == "src/config/testconfigs/noparse.api.conf" ]] && continue +- [[ $file =~ ^src/tests/cmocka/p11_nssdb/.*db ]] && continue ++ [[ $file =~ ^src/tests/cmocka/p11_nssdb.*/.*db ]] && continue + test `tail -c 1 $ABS_TOP_SRCDIR/$file` && \ + echo "Missing new line at the eof: $file" && \ + found_file=true +-- +2.13.6 + diff --git a/SOURCES/0038-intg-fix-configure-failure-with-strict-cflags.patch b/SOURCES/0038-intg-fix-configure-failure-with-strict-cflags.patch deleted file mode 100644 index 5c7c3be..0000000 --- a/SOURCES/0038-intg-fix-configure-failure-with-strict-cflags.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 076bd32668f7ea194389ddd526ea81f9bf12fb0e Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Tue, 28 Mar 2017 12:18:13 +0200 -Subject: [PATCH 38/54] intg: fix configure failure with strict cflags -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The warning -Wstrict-prototypes is a part of AM_CFLAGS which was appended -for CFLAGS in make target intgcheck-prepare. And combination with -strict CFLAGS in environment variable (e.g. -Werror) caused failures. - -sh$ CFLAGS="-Werror" make intgcheck-prepare - -checking for gcc... gcc -checking whether the C compiler works... no -configure: error: in `/home/build/sssd/ci-build-debug/intg/bld': -configure: error: C compiler cannot create executables - -configure:3719: checking whether the C compiler works -configure:3741: gcc -g3 -O2 -Werror -D_FILE_OFFSET_BITS=64 - -D_LARGEFILE_SOURCE -Wall -Wshadow -Wstrict-prototypes - -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings - -Wundef -Werror-implicit-function-declaration - -Winit-self -Wmissing-include-dirs -fno-strict-aliasing - -std=gnu99 -DKCM_PEER_UID=1000 conftest.c >&5 -conftest.c:11:1: error: function declaration isn't a prototype [-Werror=strict-prototypes] - main () - ^~~~ -cc1: all warnings being treated as errors - -Reviewed-by: Pavel Březina ---- - Makefile.am | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Makefile.am b/Makefile.am -index 91afdd669aa11a3cc316588d3b51d7e8e9c91cb8..359feddef298b0013c726409b7ba8b86504abf09 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -3486,7 +3486,7 @@ intgcheck-prepare: - --without-semanage \ - --enable-files-domain \ - $(INTGCHECK_CONFIGURE_FLAGS) \ -- CFLAGS="$$CFLAGS $(AM_CFLAGS) -DKCM_PEER_UID=$$(id -u)"; \ -+ CFLAGS="$$CFLAGS -DKCM_PEER_UID=$$(id -u)"; \ - $(MAKE) $(AM_MAKEFLAGS) ; \ - : Force single-thread install to workaround concurrency issues; \ - $(MAKE) $(AM_MAKEFLAGS) -j1 install; \ --- -2.9.3 - diff --git a/SOURCES/0038-pam_sss-refactoring-use-struct-cert_auth_info.patch b/SOURCES/0038-pam_sss-refactoring-use-struct-cert_auth_info.patch new file mode 100644 index 0000000..fc2b370 --- /dev/null +++ b/SOURCES/0038-pam_sss-refactoring-use-struct-cert_auth_info.patch @@ -0,0 +1,680 @@ +From cee84ed12721092bc40bc02dc66ce3efbb2bac74 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 16 Oct 2017 14:13:10 +0200 +Subject: [PATCH 38/46] pam_sss: refactoring, use struct cert_auth_info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Similar as in the PAM responder this patch replaces the individual +certificate authentication related attributes by a struct which can be +used as a list. With the pam_sss can handle multiple SSS_PAM_CERT_INFO +message and place the data in individual list items. + +If multiple certificates are returned before prompting for the PIN a +dialog to select a certificate is shown to the users. If available a GDM +PAM extension is used to let the user choose from a list. All coded +needed at runtime to check if the extension is available and handle the +data is provided by GDM as macros. This means that there are no +additional run-time requirements. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +(cherry picked from commit 122830e67472390b41edc73f0cfcd5c5705b726b) +--- + contrib/sssd.spec.in | 9 + + src/external/pam.m4 | 12 ++ + src/sss_client/pam_message.h | 8 +- + src/sss_client/pam_sss.c | 439 ++++++++++++++++++++++++++++++++++--------- + 4 files changed, 370 insertions(+), 98 deletions(-) + +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index 1ee64d5a2a64635984260fceced779f4804e8b31..d9323bf1a2d84f4219f8ab11886e5ce87b401c15 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -121,6 +121,12 @@ + %global with_kcm_option --without-kcm + %endif + ++%if (0%{?fedora} >= 27 || (0%{?rhel} >= 7 && 0%{?rhel7_minor} > 4)) ++ %global with_gdm_pam_extensions 1 ++%else ++ %global with_gdm_pam_extensions 0 ++%endif ++ + Name: @PACKAGE_NAME@ + Version: @PACKAGE_VERSION@ + Release: 0@PRERELEASE_VERSION@%{?dist} +@@ -233,6 +239,9 @@ BuildRequires: libuuid-devel + BuildRequires: jansson-devel + BuildRequires: libcurl-devel + %endif ++%if (0%{?with_gdm_pam_extensions} == 1) ++BuildRequires: gdm-devel ++%endif + + %description + Provides a set of daemons to manage access to remote directories and +diff --git a/src/external/pam.m4 b/src/external/pam.m4 +index 4776b6ae338409f0a2729dfc4cf5962463a40dfd..0dc7f19d0df6a4588cf893ecff6e518111462433 100644 +--- a/src/external/pam.m4 ++++ b/src/external/pam.m4 +@@ -27,3 +27,15 @@ AC_CHECK_FUNCS(pam_modutil_getlogin pam_vsyslog) + + dnl restore LIBS + LIBS="$save_LIBS" ++ ++PKG_CHECK_MODULES([GDM_PAM_EXTENSIONS], [gdm-pam-extensions], ++ [found_gdm_pam_extensions=yes], ++ [AC_MSG_NOTICE([gdm-pam-extensions were not found. gdm support ++for multiple certificates will not be build. ++])]) ++ ++AC_SUBST(GDM_PAM_EXTENSIONS_CFLAGS) ++ ++AS_IF([test x"$found_gdm_pam_extensions" = xyes], ++ [AC_DEFINE_UNQUOTED(HAVE_GDM_PAM_EXTENSIONS, 1, ++ [Build with gdm-pam-extensions support])]) +diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h +index f215392f6879f01a0ca12abc8807bac5fc1f1cbb..11526a80a767ff5602b194d14765ff261e8f9707 100644 +--- a/src/sss_client/pam_message.h ++++ b/src/sss_client/pam_message.h +@@ -29,6 +29,8 @@ + + #include "sss_client/sss_cli.h" + ++struct cert_auth_info; ++ + struct pam_items { + const char *pam_service; + const char *pam_user; +@@ -59,11 +61,9 @@ struct pam_items { + char *first_factor; + bool password_prompting; + +- char *cert_user; +- char *token_name; +- char *module_name; +- char *key_id; + bool user_name_hint; ++ struct cert_auth_info *cert_list; ++ struct cert_auth_info *selected_cert; + }; + + int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer); +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index 303809b9ea05b5a8709c05ae230d5f289b57de31..c147d4b3d76443d69e27eb2da042f8eebd1ae6ab 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -36,6 +36,10 @@ + #include + #include + ++#ifdef HAVE_GDM_PAM_EXTENSIONS ++#include ++#endif ++ + #include "sss_pam_compat.h" + #include "sss_pam_macros.h" + +@@ -43,6 +47,7 @@ + #include "pam_message.h" + #include "util/atomic_io.h" + #include "util/authtok-utils.h" ++#include "util/dlinklist.h" + + #include + #define _(STRING) dgettext (PACKAGE, STRING) +@@ -118,6 +123,40 @@ static void close_fd(pam_handle_t *pamh, void *ptr, int err) + sss_pam_close_fd(); + } + ++struct cert_auth_info { ++ char *cert_user; ++ char *cert; ++ char *token_name; ++ char *module_name; ++ char *key_id; ++ struct cert_auth_info *prev; ++ struct cert_auth_info *next; ++}; ++ ++static void free_cai(struct cert_auth_info *cai) ++{ ++ if (cai != NULL) { ++ free(cai->cert_user); ++ free(cai->cert); ++ free(cai->token_name); ++ free(cai->key_id); ++ free(cai); ++ } ++} ++ ++static void free_cert_list(struct cert_auth_info *list) ++{ ++ struct cert_auth_info *cai; ++ struct cert_auth_info *cai_next; ++ ++ if (list != NULL) { ++ DLIST_FOR_EACH_SAFE(cai, cai_next, list) { ++ DLIST_REMOVE(list, cai); ++ free_cai(cai); ++ } ++ } ++} ++ + static void overwrite_and_free_authtoks(struct pam_items *pi) + { + if (pi->pam_authtok != NULL) { +@@ -158,17 +197,9 @@ static void overwrite_and_free_pam_items(struct pam_items *pi) + free(pi->otp_challenge); + pi->otp_challenge = NULL; + +- free(pi->cert_user); +- pi->cert_user = NULL; +- +- free(pi->token_name); +- pi->token_name = NULL; +- +- free(pi->module_name); +- pi->module_name = NULL; +- +- free(pi->key_id); +- pi->key_id = NULL; ++ free_cert_list(pi->cert_list); ++ pi->cert_list = NULL; ++ pi->selected_cert = NULL; + } + + static int null_strcmp(const char *s1, const char *s2) { +@@ -821,6 +852,90 @@ static int eval_user_info_response(pam_handle_t *pamh, size_t buflen, + return ret; + } + ++static int parse_cert_info(struct pam_items *pi, uint8_t *buf, size_t len, ++ size_t *p, const char **cert_user) ++{ ++ struct cert_auth_info *cai = NULL; ++ size_t offset; ++ int ret; ++ ++ if (buf[*p + (len - 1)] != '\0') { ++ D(("cert info does not end with \\0.")); ++ return EINVAL; ++ } ++ ++ cai = calloc(1, sizeof(struct cert_auth_info)); ++ if (cai == NULL) { ++ return ENOMEM; ++ } ++ ++ cai->cert_user = strdup((char *) &buf[*p]); ++ if (cai->cert_user == NULL) { ++ D(("strdup failed")); ++ ret = ENOMEM; ++ goto done; ++ } ++ if (cert_user != NULL) { ++ *cert_user = cai->cert_user; ++ } ++ ++ offset = strlen(cai->cert_user) + 1; ++ if (offset >= len) { ++ D(("Cert message size mismatch")); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ cai->token_name = strdup((char *) &buf[*p + offset]); ++ if (cai->token_name == NULL) { ++ D(("strdup failed")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ offset += strlen(cai->token_name) + 1; ++ if (offset >= len) { ++ D(("Cert message size mismatch")); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ cai->module_name = strdup((char *) &buf[*p + offset]); ++ if (cai->module_name == NULL) { ++ D(("strdup failed")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ offset += strlen(cai->module_name) + 1; ++ if (offset >= len) { ++ D(("Cert message size mismatch")); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ cai->key_id = strdup((char *) &buf[*p + offset]); ++ if (cai->key_id == NULL) { ++ D(("strdup failed")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s]", ++ cai->cert_user, cai->token_name, cai->module_name, ++ cai->key_id)); ++ ++ DLIST_ADD(pi->cert_list, cai); ++ ret = 0; ++ ++done: ++ if (ret != 0) { ++ free_cai(cai); ++ } ++ ++ return ret; ++} ++ + static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, + struct pam_items *pi) + { +@@ -832,6 +947,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, + int32_t len; + int32_t pam_status; + size_t offset; ++ const char *cert_user; + + if (buflen < (2*sizeof(int32_t))) { + D(("response buffer is too small")); +@@ -988,27 +1104,21 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, + break; + } + +- free(pi->cert_user); +- pi->cert_user = strdup((char *) &buf[p]); +- if (pi->cert_user == NULL) { +- D(("strdup failed")); +- break; +- } +- +- if (type == SSS_PAM_CERT_INFO && *pi->cert_user == '\0') { +- D(("Invalid CERT message")); +- break; +- } +- + if (type == SSS_PAM_CERT_INFO_WITH_HINT) { + pi->user_name_hint = true; + } else { + pi->user_name_hint = false; + } + ++ ret = parse_cert_info(pi, buf, len, &p, &cert_user); ++ if (ret != 0) { ++ D(("Failed to parse cert info")); ++ break; ++ } ++ + if ((pi->pam_user == NULL || *(pi->pam_user) == '\0') +- && *pi->cert_user != '\0') { +- ret = pam_set_item(pamh, PAM_USER, pi->cert_user); ++ && *cert_user != '\0') { ++ ret = pam_set_item(pamh, PAM_USER, cert_user); + if (ret != PAM_SUCCESS) { + D(("Failed to set PAM_USER during " + "Smartcard authentication [%s]", +@@ -1027,59 +1137,6 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, + + pi->pam_user_size = strlen(pi->pam_user) + 1; + } +- +- offset = strlen(pi->cert_user) + 1; +- if (offset >= len) { +- D(("Cert message size mismatch")); +- free(pi->cert_user); +- pi->cert_user = NULL; +- break; +- } +- free(pi->token_name); +- pi->token_name = strdup((char *) &buf[p + offset]); +- if (pi->token_name == NULL) { +- D(("strdup failed")); +- free(pi->cert_user); +- pi->cert_user = NULL; +- break; +- } +- +- offset += strlen(pi->token_name) + 1; +- if (offset >= len) { +- D(("Cert message size mismatch")); +- free(pi->cert_user); +- pi->cert_user = NULL; +- free(pi->token_name); +- pi->token_name = NULL; +- break; +- } +- free(pi->module_name); +- pi->module_name = strdup((char *) &buf[p + offset]); +- if (pi->module_name == NULL) { +- D(("strdup failed")); +- break; +- } +- +- offset += strlen(pi->module_name) + 1; +- if (offset >= len) { +- D(("Cert message size mismatch")); +- free(pi->cert_user); +- pi->cert_user = NULL; +- free(pi->token_name); +- pi->token_name = NULL; +- free(pi->module_name); +- pi->module_name = NULL; +- break; +- } +- free(pi->key_id); +- pi->key_id = strdup((char *) &buf[p + offset]); +- if (pi->key_id == NULL) { +- D(("strdup failed")); +- break; +- } +- D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s]", +- pi->cert_user, pi->token_name, pi->module_name, +- pi->key_id)); + break; + case SSS_PASSWORD_PROMPTING: + D(("Password prompting available.")); +@@ -1175,10 +1232,8 @@ static int get_pam_items(pam_handle_t *pamh, uint32_t flags, + pi->otp_challenge = NULL; + pi->password_prompting = false; + +- pi->cert_user = NULL; +- pi->token_name = NULL; +- pi->module_name = NULL; +- pi->key_id = NULL; ++ pi->cert_list = NULL; ++ pi->selected_cert = NULL; + + return PAM_SUCCESS; + } +@@ -1484,6 +1539,184 @@ done: + + #define SC_PROMPT_FMT "PIN for %s" + ++#ifndef discard_const ++#define discard_const(ptr) ((void *)((uintptr_t)(ptr))) ++#endif ++ ++#define CERT_SEL_PROMPT_FMT "Certificate: %s" ++#define SEL_TITLE discard_const("Please select a certificate") ++ ++static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi) ++{ ++#ifdef HAVE_GDM_PAM_EXTENSIONS ++ int ret; ++ size_t cert_count = 0; ++ size_t c; ++ const struct pam_conv *conv; ++ struct cert_auth_info *cai; ++ GdmPamExtensionChoiceListRequest *request = NULL; ++ GdmPamExtensionChoiceListResponse *response = NULL; ++ struct pam_message prompt_message; ++ const struct pam_message *prompt_messages[1]; ++ struct pam_response *reply = NULL; ++ char *prompt; ++ ++ if (!GDM_PAM_EXTENSION_SUPPORTED(GDM_PAM_EXTENSION_CHOICE_LIST)) { ++ return ENOTSUP; ++ } ++ ++ if (pi->cert_list == NULL) { ++ return EINVAL; ++ } ++ ++ DLIST_FOR_EACH(cai, pi->cert_list) { ++ cert_count++; ++ } ++ ++ ret = pam_get_item(pamh, PAM_CONV, (const void **)&conv); ++ if (ret != PAM_SUCCESS) { ++ ret = EIO; ++ return ret; ++ } ++ ++ request = calloc(1, GDM_PAM_EXTENSION_CHOICE_LIST_REQUEST_SIZE(cert_count)); ++ if (request == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ GDM_PAM_EXTENSION_CHOICE_LIST_REQUEST_INIT(request, SEL_TITLE, cert_count); ++ ++ c = 0; ++ DLIST_FOR_EACH(cai, pi->cert_list) { ++ ret = asprintf(&prompt, CERT_SEL_PROMPT_FMT, cai->key_id); ++ if (ret == -1) { ++ ret = ENOMEM; ++ goto done; ++ } ++ request->list.items[c].key = cai->key_id; ++ request->list.items[c++].text = prompt; ++ } ++ ++ GDM_PAM_EXTENSION_MESSAGE_TO_BINARY_PROMPT_MESSAGE(request, ++ &prompt_message); ++ prompt_messages[0] = &prompt_message; ++ ++ ret = conv->conv(1, prompt_messages, &reply, conv->appdata_ptr); ++ if (ret != PAM_SUCCESS) { ++ ret = EIO; ++ goto done; ++ } ++ ++ ret = EIO; ++ response = GDM_PAM_EXTENSION_REPLY_TO_CHOICE_LIST_RESPONSE(reply); ++ if (response->key == NULL) { ++ goto done; ++ } ++ ++ DLIST_FOR_EACH(cai, pi->cert_list) { ++ if (strcmp(response->key, cai->key_id) == 0) { ++ pam_info(pamh, "Certificate ‘%s’ selected", cai->key_id); ++ pi->selected_cert = cai; ++ ret = 0; ++ break; ++ } ++ } ++ ++done: ++ if (request != NULL) { ++ for (c = 0; c < cert_count; c++) { ++ free(discard_const(request->list.items[c++].text)); ++ } ++ free(request); ++ } ++ free(response); ++ ++ return ret; ++#else ++ return ENOTSUP; ++#endif ++} ++ ++#define TEXT_CERT_SEL_PROMPT_FMT "%s[%zu] Certificate: %s\n" ++#define TEXT_SEL_TITLE discard_const("Please select a certificate by typing " \ ++ "the corresponding number\n") ++static int prompt_multi_cert(pam_handle_t *pamh, struct pam_items *pi) ++{ ++ int ret; ++ size_t cert_count = 0; ++ size_t tries = 0; ++ long int resp = -1; ++ struct cert_auth_info *cai; ++ char *prompt; ++ char *tmp; ++ char *answer; ++ char *ep; ++ ++ /* First check if gdm extension is supported */ ++ ret = prompt_multi_cert_gdm(pamh, pi); ++ if (ret != ENOTSUP) { ++ return ret; ++ } ++ ++ if (pi->cert_list == NULL) { ++ return EINVAL; ++ } ++ ++ prompt = strdup(TEXT_SEL_TITLE); ++ if (prompt == NULL) { ++ return ENOMEM; ++ } ++ ++ DLIST_FOR_EACH(cai, pi->cert_list) { ++ cert_count++; ++ ret = asprintf(&tmp, TEXT_CERT_SEL_PROMPT_FMT, prompt, cert_count, ++ cai->key_id); ++ free(prompt); ++ if (ret == -1) { ++ return ENOMEM; ++ } ++ ++ prompt = tmp; ++ } ++ ++ do { ++ ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_ON, prompt, NULL, ++ &answer); ++ if (ret != PAM_SUCCESS) { ++ D(("do_pam_conversation failed.")); ++ break; ++ } ++ ++ errno = 0; ++ resp = strtol(answer, &ep, 10); ++ if (errno == 0 && *ep == '\0' && resp > 0 && resp <= cert_count) { ++ /* do not free answer ealier because ep is pointing to it */ ++ free(answer); ++ break; ++ } ++ free(answer); ++ resp = -1; ++ } while (++tries < 5); ++ free(prompt); ++ ++ pi->selected_cert = NULL; ++ ret = ENOENT; ++ if (resp > 0 && resp <= cert_count) { ++ cert_count = 0; ++ DLIST_FOR_EACH(cai, pi->cert_list) { ++ cert_count++; ++ if (resp == cert_count) { ++ pam_info(pamh, "Certificate ‘%s’ selected", cai->key_id); ++ pi->selected_cert = cai; ++ ret = 0; ++ break; ++ } ++ } ++ } ++ ++ return ret; ++} ++ + static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) + { + int ret; +@@ -1495,19 +1728,20 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) + const struct pam_message *mesg[2] = { NULL, NULL }; + struct pam_message m[2] = { { 0 }, { 0 } }; + struct pam_response *resp = NULL; ++ struct cert_auth_info *cai = pi->selected_cert; + +- if (pi->token_name == NULL || *pi->token_name == '\0') { ++ if (cai == NULL || cai->token_name == NULL || *cai->token_name == '\0') { + return EINVAL; + } + +- size = sizeof(SC_PROMPT_FMT) + strlen(pi->token_name); ++ size = sizeof(SC_PROMPT_FMT) + strlen(cai->token_name); + prompt = malloc(size); + if (prompt == NULL) { + D(("malloc failed.")); + return ENOMEM; + } + +- ret = snprintf(prompt, size, SC_PROMPT_FMT, pi->token_name); ++ ret = snprintf(prompt, size, SC_PROMPT_FMT, cai->token_name); + if (ret < 0 || ret >= size) { + D(("snprintf failed.")); + free(prompt); +@@ -1604,9 +1838,9 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) + pi->pam_authtok_size=0; + } else { + +- ret = sss_auth_pack_sc_blob(answer, 0, pi->token_name, 0, +- pi->module_name, 0, +- pi->key_id, 0, ++ ret = sss_auth_pack_sc_blob(answer, 0, cai->token_name, 0, ++ cai->module_name, 0, ++ cai->key_id, 0, + NULL, 0, &needed_size); + if (ret != EAGAIN) { + D(("sss_auth_pack_sc_blob failed.")); +@@ -1621,9 +1855,9 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) + goto done; + } + +- ret = sss_auth_pack_sc_blob(answer, 0, pi->token_name, 0, +- pi->module_name, 0, +- pi->key_id, 0, ++ ret = sss_auth_pack_sc_blob(answer, 0, cai->token_name, 0, ++ cai->module_name, 0, ++ cai->key_id, 0, + (uint8_t *) pi->pam_authtok, needed_size, + &needed_size); + if (ret != EOK) { +@@ -1786,7 +2020,17 @@ static int get_authtok_for_authentication(pam_handle_t *pamh, + ret = prompt_2fa(pamh, pi, _("First Factor: "), + _("Second Factor: ")); + } +- } else if (pi->token_name != NULL && *(pi->token_name) != '\0') { ++ } else if (pi->cert_list != NULL) { ++ if (pi->cert_list->next == NULL) { ++ /* Only one certificate */ ++ pi->selected_cert = pi->cert_list; ++ } else { ++ ret = prompt_multi_cert(pamh, pi); ++ if (ret != 0) { ++ D(("Failed to select certificate")); ++ return PAM_AUTHTOK_ERR; ++ } ++ } + ret = prompt_sc_pin(pamh, pi); + } else { + ret = prompt_password(pamh, pi, _("Password: ")); +@@ -1905,14 +2149,21 @@ static int check_login_token_name(pam_handle_t *pamh, struct pam_items *pi, + char *prompt = NULL; + size_t size; + char *answer = NULL; ++ /* TODO: check multiple cert case */ ++ struct cert_auth_info *cai = pi->cert_list; ++ ++ if (cai == NULL) { ++ D(("No certificate information available")); ++ return EINVAL; ++ } + + login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME"); + if (login_token_name == NULL) { + return PAM_SUCCESS; + } + +- while (pi->token_name == NULL +- || strcmp(login_token_name, pi->token_name) != 0) { ++ while (cai->token_name == NULL ++ || strcmp(login_token_name, cai->token_name) != 0) { + size = sizeof(SC_ENTER_FMT) + strlen(login_token_name); + prompt = malloc(size); + if (prompt == NULL) { +-- +2.13.6 + diff --git a/SOURCES/0039-intg-Remove-bashism-from-intgcheck-prepare.patch b/SOURCES/0039-intg-Remove-bashism-from-intgcheck-prepare.patch deleted file mode 100644 index d10c770..0000000 --- a/SOURCES/0039-intg-Remove-bashism-from-intgcheck-prepare.patch +++ /dev/null @@ -1,54 +0,0 @@ -From c49fc8fded9ed87e37189bf877f04ef462974420 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 27 Mar 2017 14:44:29 +0200 -Subject: [PATCH 39/54] intg: Remove bashism from intgcheck-prepare - -env variable UID is not defined in all shells (eg. dash) -We also need to move invocation of "id -u" before nss_wraper -is enabled otherwise we would get root instead of real user. - -=================================== FAILURES =================================== -________________________ test_kcm_mem_init_list_destroy ________________________ -Traceback (most recent call last): - File "/home/build/sssd/src/tests/intg/test_kcm.py", line 198, in test_kcm_mem_init_list_destroy - kcm_init_list_destroy(testenv) - File "/home/build/sssd/src/tests/intg/test_kcm.py", line 183, in kcm_init_list_destroy - exp_ccname = testenv.ccname() - File "/home/build/sssd/src/tests/intg/test_kcm.py", line 45, in ccname - my_uid = self.my_uid() - File "/home/build/sssd/src/tests/intg/test_kcm.py", line 41, in my_uid - return int(s_myuid) -ValueError: invalid literal for int() with base 10: '' - -And we already use different approach in top level Makefile.am -3488) $(INTGCHECK_CONFIGURE_FLAGS) \ -3489) CFLAGS="$$CFLAGS $(AM_CFLAGS) -DKCM_PEER_UID=$$(id -u)"; \ -3490) $(MAKE) $(AM_MAKEFLAGS) ; \ - -Reviewed-by: Jakub Hrozek ---- - src/tests/intg/Makefile.am | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am -index 8526beace09b15c99aa27ac98d5038d1980f6a71..8566106e9017a8d3c9e7a3898a3a886e2966e346 100644 ---- a/src/tests/intg/Makefile.am -+++ b/src/tests/intg/Makefile.am -@@ -76,6 +76,7 @@ intgcheck-installed: config.py passwd group - PATH="$(abs_builddir):$(abs_srcdir):$$PATH" \ - PYTHONPATH="$(abs_builddir):$(abs_srcdir)" \ - LDB_MODULES_PATH="$(DESTDIR)$(ldblibdir)" \ -+ NON_WRAPPED_UID=$$(id -u) \ - LD_PRELOAD="$$nss_wrapper $$uid_wrapper" \ - NSS_WRAPPER_PASSWD="$(abs_builddir)/passwd" \ - NSS_WRAPPER_GROUP="$(abs_builddir)/group" \ -@@ -83,6 +84,5 @@ intgcheck-installed: config.py passwd group - NSS_WRAPPER_MODULE_FN_PREFIX="sss" \ - UID_WRAPPER=1 \ - UID_WRAPPER_ROOT=1 \ -- NON_WRAPPED_UID=$$(echo $$UID) \ - fakeroot $(PYTHON2) $(PYTEST) -v --tb=native $(INTGCHECK_PYTEST_ARGS) . - rm -f $(DESTDIR)$(logpath)/* --- -2.9.3 - diff --git a/SOURCES/0039-p11_child-use-options-to-select-certificate-for-auth.patch b/SOURCES/0039-p11_child-use-options-to-select-certificate-for-auth.patch new file mode 100644 index 0000000..4b476fc --- /dev/null +++ b/SOURCES/0039-p11_child-use-options-to-select-certificate-for-auth.patch @@ -0,0 +1,609 @@ +From e857005c207e514c487ba75daf20ca4be5321c38 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 27 Oct 2017 10:13:36 +0200 +Subject: [PATCH 39/46] p11_child: use options to select certificate for + authentication +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +New options are added to p11_child to select a specific certificate +during authentication. + +The related unit tests are updated by adding the needed attributes to +the requests. The was not necessary before because although the +attribute were already send by pam_sss they were not used in the PAM +responder but only forwarded to the back where they were used by the +PKINIT code to select the expected certificate. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +(cherry picked from commit 0a8024af282b271ad2185f68703d9f4e766d2bdc) +--- + src/p11_child/p11_child_nss.c | 213 ++++++++++++++++++++++++++-------------- + src/responder/pam/pamsrv_p11.c | 30 +++++- + src/tests/cmocka/test_pam_srv.c | 64 ++++++++---- + 3 files changed, 210 insertions(+), 97 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index 50bde2f4f91f6c00260b0db383d0962112686ebc..c676375cf7f6677a1d7f38f09b9bb5fd820d60c5 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -67,12 +67,34 @@ static char *password_passthrough(PK11SlotInfo *slot, PRBool retry, void *arg) + return PL_strdup((char *)arg); + } + ++static char *get_key_id_str(PK11SlotInfo *slot, CERTCertificate *cert) ++{ ++ SECItem *key_id = NULL; ++ char *key_id_str = NULL; + ++ key_id = PK11_GetLowLevelKeyIDForCert(slot, cert, NULL); ++ if (key_id == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "PK11_GetLowLevelKeyIDForCert failed [%d].\n", ++ PR_GetError()); ++ return NULL; ++ } + +-int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, ++ key_id_str = CERT_Hexify(key_id, PR_FALSE); ++ SECITEM_FreeItem(key_id, PR_TRUE); ++ if (key_id_str == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", PR_GetError()); ++ return NULL; ++ } ++ ++ return key_id_str; ++} ++ ++int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + enum op_mode mode, const char *pin, + struct cert_verify_opts *cert_verify_opts, +- char **_multi) ++ const char *module_name_in, const char *token_name_in, ++ const char *key_id_in, char **_multi) + { + int ret; + SECStatus rv; +@@ -153,42 +175,31 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + mod_list_item->module->dllName); + } + +- if (slot_name_in != NULL) { +- slot = PK11_FindSlotByName(slot_name_in); +- if (slot == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "PK11_FindSlotByName failed for [%s]: [%d].\n", +- slot_name_in, PR_GetError()); +- return EIO; +- } +- } else { +- +- list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, +- NULL); +- if (list == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "PK11_GetAllTokens failed.\n"); +- return EIO; +- } ++ list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, ++ NULL); ++ if (list == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "PK11_GetAllTokens failed.\n"); ++ return EIO; ++ } + +- for (le = list->head; le; le = le->next) { +- CK_SLOT_INFO slInfo; ++ for (le = list->head; le; le = le->next) { ++ CK_SLOT_INFO slInfo; + +- slInfo.flags = 0; +- rv = PK11_GetSlotInfo(le->slot, &slInfo); +- DEBUG(SSSDBG_TRACE_ALL, +- "Description [%s] Manufacturer [%s] flags [%lu].\n", +- slInfo.slotDescription, slInfo.manufacturerID, slInfo.flags); +- if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) { +- slot = PK11_ReferenceSlot(le->slot); +- break; +- } +- } +- PK11_FreeSlotList(list); +- if (slot == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "No removable slots found.\n"); +- return EIO; ++ slInfo.flags = 0; ++ rv = PK11_GetSlotInfo(le->slot, &slInfo); ++ DEBUG(SSSDBG_TRACE_ALL, ++ "Description [%s] Manufacturer [%s] flags [%lu].\n", ++ slInfo.slotDescription, slInfo.manufacturerID, slInfo.flags); ++ if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) { ++ slot = PK11_ReferenceSlot(le->slot); ++ break; + } + } +- ++ PK11_FreeSlotList(list); ++ if (slot == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "No removable slots found.\n"); ++ return EIO; ++ } + + slot_id = PK11_GetSlotID(slot); + module_id = PK11_GetModuleID(slot); +@@ -317,24 +328,60 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + for (cert_list_node = CERT_LIST_HEAD(cert_list); + !CERT_LIST_END(cert_list_node, cert_list); + cert_list_node = CERT_LIST_NEXT(cert_list_node)) { +- if (cert_list_node->cert) { +- DEBUG(SSSDBG_TRACE_ALL, "found cert[%s][%s]\n", +- cert_list_node->cert->nickname, +- cert_list_node->cert->subjectName); ++ if (cert_list_node->cert == NULL) { ++ DEBUG(SSSDBG_TRACE_ALL, "--- empty cert list node ---\n"); ++ continue; ++ } + +- if (cert_verify_opts->do_verification) { +- rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert, +- PR_TRUE, +- certificateUsageSSLClient, +- NULL, NULL); +- if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Certificate [%s][%s] not valid [%d], skipping.\n", +- cert_list_node->cert->nickname, +- cert_list_node->cert->subjectName, PR_GetError()); +- continue; +- } ++ DEBUG(SSSDBG_TRACE_ALL, ++ "found cert[%s][%s]\n", ++ cert_list_node->cert->nickname, ++ cert_list_node->cert->subjectName); ++ ++ if (cert_verify_opts->do_verification) { ++ rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert, ++ PR_TRUE, ++ certificateUsageSSLClient, ++ NULL, NULL); ++ if (rv != SECSuccess) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Certificate [%s][%s] not valid [%d], skipping.\n", ++ cert_list_node->cert->nickname, ++ cert_list_node->cert->subjectName, PR_GetError()); ++ continue; + } ++ } ++ ++ if (key_id_in != NULL) { ++ PORT_Free(key_id_str); ++ key_id_str = NULL; ++ key_id_str = get_key_id_str(slot, cert_list_node->cert); ++ } ++ /* Check if we found the certificates we needed for authentication or ++ * the requested ones for pre-auth. For authentication all attributes ++ * must be given and match, for pre-auth only the given ones must ++ * match. */ ++ DEBUG(SSSDBG_TRACE_ALL, "%s %s %s %s %s %s.\n", ++ module_name_in, module_name, token_name_in, token_name, ++ key_id_in, key_id_str); ++ if ((mode == OP_AUTH ++ && module_name_in != NULL ++ && token_name_in != NULL ++ && key_id_in != NULL ++ && key_id_str != NULL ++ && strcmp(key_id_in, key_id_str) == 0 ++ && strcmp(token_name_in, token_name) == 0 ++ && strcmp(module_name_in, module_name) == 0) ++ || (mode == OP_PREAUTH ++ && (module_name_in == NULL ++ || (module_name_in != NULL ++ && strcmp(module_name_in, module_name) == 0)) ++ && (token_name_in == NULL ++ || (token_name_in != NULL ++ && strcmp(token_name_in, token_name) == 0)) ++ && (key_id_in == NULL ++ || (key_id_in != NULL && key_id_str != NULL ++ && strcmp(key_id_in, key_id_str) == 0)))) { + + rv = CERT_AddCertToListTail(valid_certs, cert_list_node->cert); + if (rv != SECSuccess) { +@@ -343,15 +390,6 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + ret = EIO; + goto done; + } +- +- if (found_cert == NULL) { +- found_cert = cert_list_node->cert; +- } else { +- DEBUG(SSSDBG_TRACE_ALL, "More than one certificate found, " \ +- "using just the first one.\n"); +- } +- } else { +- DEBUG(SSSDBG_TRACE_ALL, "--- empty cert list node ---\n"); + } + } + +@@ -367,7 +405,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + } + } + +- if (found_cert == NULL) { ++ if (CERT_LIST_EMPTY(valid_certs)) { + DEBUG(SSSDBG_TRACE_ALL, "No certificate found.\n"); + *_multi = NULL; + ret = EOK; +@@ -375,6 +413,23 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + } + + if (mode == OP_AUTH) { ++ cert_list_node = CERT_LIST_HEAD(valid_certs); ++ if (!CERT_LIST_END(CERT_LIST_NEXT(cert_list_node), valid_certs)) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "More than one certificate found for authentication, " ++ "aborting!\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ found_cert = cert_list_node->cert; ++ if (found_cert == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "No certificate found for authentication, aborting!\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ + rv = PK11_GenerateRandom(random_value, sizeof(random_value)); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +@@ -449,21 +504,10 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + + found_cert = cert_list_node->cert; + +- SECITEM_FreeItem(key_id, PR_TRUE); + PORT_Free(key_id_str); +- key_id = PK11_GetLowLevelKeyIDForCert(slot, found_cert, NULL); +- if (key_id == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, +- "PK11_GetLowLevelKeyIDForCert failed [%d].\n", +- PR_GetError()); +- ret = EINVAL; +- goto done; +- } +- +- key_id_str = CERT_Hexify(key_id, PR_FALSE); ++ key_id_str = get_key_id_str(slot, found_cert); + if (key_id_str == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "get_key_id_str [%d].\n", PR_GetError()); + ret = ENOMEM; + goto done; + } +@@ -576,11 +620,13 @@ int main(int argc, const char *argv[]) + enum op_mode mode = OP_NONE; + enum pin_mode pin_mode = PIN_NONE; + char *pin = NULL; +- char *slot_name_in = NULL; + char *nss_db = NULL; + struct cert_verify_opts *cert_verify_opts; + char *verify_opts = NULL; + char *multi = NULL; ++ char *module_name = NULL; ++ char *token_name = NULL; ++ char *key_id = NULL; + + struct poptOption long_options[] = { + POPT_AUTOHELP +@@ -605,6 +651,12 @@ int main(int argc, const char *argv[]) + NULL}, + {"nssdb", 0, POPT_ARG_STRING, &nss_db, 0, _("NSS DB to use"), + NULL}, ++ {"module_name", 0, POPT_ARG_STRING, &module_name, 0, ++ _("Module name for authentication"), NULL}, ++ {"token_name", 0, POPT_ARG_STRING, &token_name, 0, ++ _("Token name for authentication"), NULL}, ++ {"key_id", 0, POPT_ARG_STRING, &key_id, 0, ++ _("Key ID for authentication"), NULL}, + POPT_TABLEEND + }; + +@@ -730,6 +782,15 @@ int main(int argc, const char *argv[]) + } + talloc_steal(main_ctx, debug_prg_name); + ++ if (mode == OP_AUTH && (module_name == NULL || token_name == NULL ++ || key_id == NULL)) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "--module_name, --token_name and --key_id must be for " ++ "authentication"); ++ ret = EINVAL; ++ goto fail; ++ } ++ + ret = parse_cert_verify_opts(main_ctx, verify_opts, &cert_verify_opts); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Failed to parse verifiy option.\n"); +@@ -744,8 +805,8 @@ int main(int argc, const char *argv[]) + } + } + +- ret = do_work(main_ctx, nss_db, slot_name_in, mode, pin, cert_verify_opts, +- &multi); ++ ret = do_work(main_ctx, nss_db, mode, pin, cert_verify_opts, module_name, ++ token_name, key_id, &multi); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n"); + goto fail; +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index 57c8e1e464f4262f2d78f869c52ca48bd469d90a..4d5572164763ed0b3a842019f820680a4dc2dfdc 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -399,10 +399,13 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + struct timeval tv; + int pipefd_to_child[2] = PIPE_INIT; + int pipefd_from_child[2] = PIPE_INIT; +- const char *extra_args[7] = { NULL }; ++ const char *extra_args[13] = { NULL }; + uint8_t *write_buf = NULL; + size_t write_buf_len = 0; + size_t arg_c; ++ const char *module_name = NULL; ++ const char *token_name = NULL; ++ const char *key_id = NULL; + + req = tevent_req_create(mem_ctx, &state, struct pam_check_cert_state); + if (req == NULL) { +@@ -423,6 +426,30 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + extra_args[arg_c++] = verify_opts; + extra_args[arg_c++] = "--verify"; + } ++ ++ if (sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_SC_PIN ++ || sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_SC_KEYPAD) { ++ ret = sss_authtok_get_sc(pd->authtok, NULL, NULL, &token_name, NULL, ++ &module_name, NULL, &key_id, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc failed.\n"); ++ goto done; ++ } ++ ++ if (module_name != NULL && *module_name != '\0') { ++ extra_args[arg_c++] = module_name; ++ extra_args[arg_c++] = "--module_name"; ++ } ++ if (token_name != NULL && *token_name != '\0') { ++ extra_args[arg_c++] = token_name; ++ extra_args[arg_c++] = "--token_name"; ++ } ++ if (key_id != NULL && *key_id != '\0') { ++ extra_args[arg_c++] = key_id; ++ extra_args[arg_c++] = "--key_id"; ++ } ++ } ++ + if (pd->cmd == SSS_PAM_AUTHENTICATE) { + extra_args[arg_c++] = "--auth"; + switch (sss_authtok_get_type(pd->authtok)) { +@@ -437,6 +464,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + ret = EINVAL; + goto done; + } ++ + } else if (pd->cmd == SSS_PAM_PREAUTH) { + extra_args[arg_c++] = "--pre"; + } else { +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 7f0ed706512ffe0866c0e1fb7e6baa16bec942d8..5c1f621ccead75717d1721714d953d7d4d415d7b 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -687,7 +687,9 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, + } + + static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, +- const char *pin, const char *service, ++ const char *pin, const char *token_name, ++ const char *module_name, const char *key_id, ++ const char *service, + acct_cb_t acct_cb, const char *cert, + bool only_one_provider_call) + { +@@ -697,6 +699,7 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, + struct pam_items pi = { 0 }; + int ret; + bool already_mocked = false; ++ size_t needed_size; + + if (name != NULL) { + pi.pam_user = name; +@@ -707,9 +710,21 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, + } + + if (pin != NULL) { +- pi.pam_authtok = discard_const(pin); +- pi.pam_authtok_size = strlen(pi.pam_authtok) + 1; ++ ret = sss_auth_pack_sc_blob(pin, 0, token_name, 0, module_name, 0, ++ key_id, 0, NULL, 0, &needed_size); ++ assert_int_equal(ret, EAGAIN); ++ ++ pi.pam_authtok = malloc(needed_size); ++ assert_non_null(pi.pam_authtok); ++ ++ ret = sss_auth_pack_sc_blob(pin, 0, token_name, 0, module_name, 0, ++ key_id, 0, ++ (uint8_t *)pi.pam_authtok, needed_size, ++ &needed_size); ++ assert_int_equal(ret, EOK); ++ + pi.pam_authtok_type = SSS_AUTHTOK_TYPE_SC_PIN; ++ pi.pam_authtok_size = needed_size; + } + + pi.pam_service = service == NULL ? "login" : service; +@@ -724,6 +739,7 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, + pi.cli_pid = 12345; + + ret = pack_message_v3(&pi, &buf_size, &m_buf); ++ free(pi.pam_authtok); + assert_int_equal(ret, 0); + + buf = talloc_memdup(mem_ctx, m_buf, buf_size); +@@ -1732,7 +1748,8 @@ void test_pam_preauth_no_logon_name(void **state) + { + int ret; + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, false); ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -1824,7 +1841,8 @@ void test_pam_preauth_cert_nocert(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, "/no/path"); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, false); ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -1962,7 +1980,7 @@ void test_pam_preauth_cert_nomatch(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb, NULL, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -1984,7 +2002,7 @@ void test_pam_preauth_cert_match(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2007,8 +2025,9 @@ void test_pam_preauth_cert_match_gdm_smartcard(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, "gdm-smartcard", +- test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, ++ "gdm-smartcard", test_lookup_by_cert_cb, ++ TEST_TOKEN_CERT, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2029,7 +2048,7 @@ void test_pam_preauth_cert_match_wrong_user(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_wrong_user_cb, + TEST_TOKEN_CERT, false); + +@@ -2061,7 +2080,7 @@ void test_pam_preauth_cert_no_logon_name(void **state) + * Additionally sss_parse_inp_recv() must be mocked because the cache + * request will be done with the username found by the certificate + * lookup. */ +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); + mock_account_recv_simple(); + mock_parse_inp("pamuser", NULL, EOK); +@@ -2090,7 +2109,7 @@ void test_pam_preauth_cert_no_logon_name_with_hint(void **state) + * Since user name hint is enabled we do not have to search the user + * during pre-auth and there is no need for an extra mocked response as in + * test_pam_preauth_cert_no_logon_name. */ +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2112,7 +2131,7 @@ void test_pam_preauth_cert_no_logon_name_double_cert(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2135,7 +2154,7 @@ void test_pam_preauth_cert_no_logon_name_double_cert_with_hint(void **state) + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + pam_test_ctx->rctx->domains->user_name_hint = true; + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2157,7 +2176,8 @@ void test_pam_preauth_no_cert_no_logon_name(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, "/no/path"); + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, false); ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2178,7 +2198,7 @@ void test_pam_preauth_cert_no_logon_name_no_match(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb, NULL, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2206,7 +2226,9 @@ void test_pam_cert_auth(void **state) + * is looked up. Since the first mocked reply already adds the certificate + * to the user entry the lookup by certificate will already find the user + * in the cache and no second request to the backend is needed. */ +- mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", ++ "NSS-Internal", ++ "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL, + test_lookup_by_cert_cb, TEST_TOKEN_CERT, true); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); +@@ -2232,7 +2254,9 @@ void test_pam_cert_auth_double_cert(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", ++ "NSS-Internal", ++ "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL, + test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, true); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); +@@ -2257,7 +2281,7 @@ void test_pam_cert_preauth_2certs_one_mapping(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB_2CERTS); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2279,7 +2303,7 @@ void test_pam_cert_preauth_2certs_two_mappings(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB_2CERTS); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb_2nd_cert_same_user, + TEST_TOKEN_CERT, false); + +-- +2.13.6 + diff --git a/SOURCES/0040-UTIL-Introduce-subdomain_create_conf_path.patch b/SOURCES/0040-UTIL-Introduce-subdomain_create_conf_path.patch deleted file mode 100644 index 0dc6e0c..0000000 --- a/SOURCES/0040-UTIL-Introduce-subdomain_create_conf_path.patch +++ /dev/null @@ -1,127 +0,0 @@ -From ddfa743159541de498816764c06bf4b13fb923f7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 28 Mar 2017 18:33:46 +0200 -Subject: [PATCH 40/54] UTIL: Introduce subdomain_create_conf_path() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This is a utility function that replaces the create_subdom_conf_path(). -Differently than the latter, it only takes one parameter and is going to -be used in a few different places (thus adding it to util.h). - -Reviewed-by: Fabiano Fidêncio -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukas Slebodnik ---- - src/providers/ad/ad_common.c | 7 ------- - src/providers/ad/ad_common.h | 4 ---- - src/providers/ad/ad_subdomains.c | 4 +--- - src/providers/ipa/ipa_subdomains_server.c | 4 +--- - src/util/domain_info_utils.c | 15 +++++++++++++++ - src/util/util.h | 3 +++ - 6 files changed, 20 insertions(+), 17 deletions(-) - -diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c -index ec952d3bb4587516ea26fd27c212d5620e2f3dda..f893b748a2ddcff1eab6e8d919d2aa950b825446 100644 ---- a/src/providers/ad/ad_common.c -+++ b/src/providers/ad/ad_common.c -@@ -33,13 +33,6 @@ errno_t ad_set_search_bases(struct sdap_options *id_opts); - static errno_t ad_set_sdap_options(struct ad_options *ad_opts, - struct sdap_options *id_opts); - --char *create_subdom_conf_path(TALLOC_CTX *mem_ctx, -- const char *conf_path, -- const char *subdom_name) --{ -- return talloc_asprintf(mem_ctx, "%s/%s", conf_path, subdom_name); --} -- - static struct sdap_options * - ad_create_default_sdap_options(TALLOC_CTX *mem_ctx) - { -diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h -index e02b932cd2da737254de8417d5c82fcdcf14e8d7..2981550f6c390929501ec8942e861b16ea0a5cb0 100644 ---- a/src/providers/ad/ad_common.h -+++ b/src/providers/ad/ad_common.h -@@ -99,10 +99,6 @@ struct ad_options { - struct be_nsupdate_ctx *dyndns_ctx; - }; - --char *create_subdom_conf_path(TALLOC_CTX *mem_ctx, -- const char *conf_path, -- const char *subdom_name); -- - errno_t - ad_get_common_options(TALLOC_CTX *mem_ctx, - struct confdb_ctx *cdb, -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index 156ecab4272029d69c8b596eff041498a7524ce4..eecae9c9ca82ad67874c13a3c7b7c617d6232d5c 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -171,9 +171,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, - return EINVAL; - } - -- subdom_conf_path = create_subdom_conf_path(id_ctx, -- be_ctx->conf_path, -- subdom->name); -+ subdom_conf_path = subdomain_create_conf_path(id_ctx, subdom); - if (subdom_conf_path == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "subdom_conf_path failed\n"); - return ENOMEM; -diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c -index ae3baf036e4278fb67d86b42742fb7e80b46724e..e8ee30392d84f84e30bcdaa3d2110ba130b1ad73 100644 ---- a/src/providers/ipa/ipa_subdomains_server.c -+++ b/src/providers/ipa/ipa_subdomains_server.c -@@ -176,9 +176,7 @@ static struct ad_options *ipa_ad_options_new(struct be_ctx *be_ctx, - forest_realm = subdom->forest_root->realm; - forest = subdom->forest_root->forest; - -- subdom_conf_path = create_subdom_conf_path(id_ctx, -- be_ctx->conf_path, -- subdom->name); -+ subdom_conf_path = subdomain_create_conf_path(id_ctx, subdom); - if (subdom_conf_path == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "subdom_conf_path failed\n"); - return NULL; -diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c -index 6ef6bcfb8c078a360673b6bdd2364fc2918cb324..a7f118842aa8ba870143b2f2b425a3e3c0ea5a78 100644 ---- a/src/util/domain_info_utils.c -+++ b/src/util/domain_info_utils.c -@@ -870,3 +870,18 @@ bool is_email_from_domain(const char *email, struct sss_domain_info *dom) - - return false; - } -+ -+char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *subdomain) -+{ -+ if (!IS_SUBDOMAIN(subdomain)) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "The domain \"%s\" is not a subdomain.\n", -+ subdomain->name); -+ return NULL; -+ } -+ -+ return talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL "/%s", -+ subdomain->parent->name, -+ subdomain->name); -+} -diff --git a/src/util/util.h b/src/util/util.h -index a2dc89b8ddb999437eda551ac17af28672d8759c..82760940269ad8883e725e3a5cf463486c9cfd36 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -551,6 +551,9 @@ find_domain_by_object_name(struct sss_domain_info *domain, - bool subdomain_enumerates(struct sss_domain_info *parent, - const char *sd_name); - -+char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *subdomain); -+ - errno_t sssd_domain_init(TALLOC_CTX *mem_ctx, - struct confdb_ctx *cdb, - const char *domain_name, --- -2.9.3 - diff --git a/SOURCES/0040-pam-add-prompt-string-for-certificate-authentication.patch b/SOURCES/0040-pam-add-prompt-string-for-certificate-authentication.patch new file mode 100644 index 0000000..8d94ce2 --- /dev/null +++ b/SOURCES/0040-pam-add-prompt-string-for-certificate-authentication.patch @@ -0,0 +1,337 @@ +From 4f09838b50cc771d52c7b00cc47fb3362d8ecda2 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 30 Oct 2017 08:03:42 +0100 +Subject: [PATCH 40/46] pam: add prompt string for certificate authentication +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A new certificate attribute is added which contains a string which is +used in the certificate selection list displayed to the user. The +Subject-DN of the certificate is used here because it is present in all +certificate and in general differs for certificate with different usage. +libsss_certmap is used to extract the subject-DN from the certificate +and convert it into a string. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +(cherry picked from commit 06c2300353faf3983e38fecb1d6afe1f6cc8fe32) +--- + Makefile.am | 2 ++ + src/responder/pam/pamsrv_p11.c | 65 ++++++++++++++++++++++++++++++++++++++++- + src/sss_client/pam_sss.c | 31 ++++++++++++++++---- + src/tests/cmocka/test_pam_srv.c | 23 +++++++++++++-- + 4 files changed, 111 insertions(+), 10 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 4ed872a532daf9b934537cc5f64ce77778121e2a..16bcb4efc028b05c1196249245f4f3091b9366af 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1400,6 +1400,7 @@ sssd_pam_LDADD = \ + $(SELINUX_LIBS) \ + $(PAM_LIBS) \ + $(SYSTEMD_DAEMON_LIBS) \ ++ libsss_certmap.la \ + $(SSSD_INTERNAL_LTLIBS) \ + $(NULL) + +@@ -2423,6 +2424,7 @@ pam_srv_tests_LDADD = \ + $(SYSTEMD_DAEMON_LIBS) \ + libsss_test_common.la \ + libsss_idmap.la \ ++ libsss_certmap.la \ + $(NULL) + + EXTRA_responder_get_domains_tests_DEPENDENCIES = \ +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index 4d5572164763ed0b3a842019f820680a4dc2dfdc..5a3eeff0ec977829a9ad8c80b4fc6b2e06857097 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -26,6 +26,8 @@ + #include "util/child_common.h" + #include "util/strtonum.h" + #include "responder/pam/pamsrv.h" ++#include "lib/certmap/sss_certmap.h" ++#include "util/crypto/sss_crypto.h" + + + #ifndef SSSD_LIBEXEC_PATH +@@ -683,6 +685,54 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + return EOK; + } + ++static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert) ++{ ++ int ret; ++ struct sss_certmap_ctx *ctx = NULL; ++ unsigned char *der = NULL; ++ size_t der_size; ++ char *prompt = NULL; ++ char *filter = NULL; ++ char **domains = NULL; ++ ++ ret = sss_certmap_init(mem_ctx, NULL, NULL, &ctx); ++ if (ret != 0) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n"); ++ return NULL; ++ } ++ ++ ret = sss_certmap_add_rule(ctx, 10, "KRB5:.*", ++ "LDAP:{subject_dn!nss}", NULL); ++ if (ret != 0) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_add_rule failed.\n"); ++ goto done; ++ } ++ ++ der = sss_base64_decode(mem_ctx, cert, &der_size); ++ if (der == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n"); ++ goto done; ++ } ++ ++ ret = sss_certmap_get_search_filter(ctx, der, der_size, &filter, &domains); ++ if (ret != 0) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_get_search_filter failed.\n"); ++ goto done; ++ } ++ ++ prompt = talloc_strdup(mem_ctx, filter); ++ if (prompt == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ } ++ ++done: ++ sss_certmap_free_filter_and_domains(filter, domains); ++ sss_certmap_free_ctx(ctx); ++ talloc_free(der); ++ ++ return prompt; ++} ++ + static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + struct cert_auth_info *cert_info, + uint8_t **_msg, size_t *_msg_len) +@@ -692,16 +742,24 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + const char *token_name; + const char *module_name; + const char *key_id; ++ char *prompt; + size_t user_len; + size_t token_len; + size_t module_len; + size_t key_id_len; ++ size_t prompt_len; + const char *username = ""; + + if (sysdb_username != NULL) { + username = sysdb_username; + } + ++ prompt = get_cert_prompt(mem_ctx, sss_cai_get_cert(cert_info)); ++ if (prompt == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "get_cert_prompt failed.\n"); ++ return EIO; ++ } ++ + token_name = sss_cai_get_token_name(cert_info); + module_name = sss_cai_get_module_name(cert_info); + key_id = sss_cai_get_key_id(cert_info); +@@ -710,10 +768,12 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + token_len = strlen(token_name) + 1; + module_len = strlen(module_name) + 1; + key_id_len = strlen(key_id) + 1; +- msg_len = user_len + token_len + module_len + key_id_len; ++ prompt_len = strlen(prompt) + 1; ++ msg_len = user_len + token_len + module_len + key_id_len + prompt_len; + + msg = talloc_zero_size(mem_ctx, msg_len); + if (msg == NULL) { ++ talloc_free(prompt); + DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); + return ENOMEM; + } +@@ -722,6 +782,9 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + memcpy(msg + user_len, token_name, token_len); + memcpy(msg + user_len + token_len, module_name, module_len); + memcpy(msg + user_len + token_len + module_len, key_id, key_id_len); ++ memcpy(msg + user_len + token_len + module_len + key_id_len, ++ prompt, prompt_len); ++ talloc_free(prompt); + + if (_msg != NULL) { + *_msg = msg; +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index c147d4b3d76443d69e27eb2da042f8eebd1ae6ab..1dc51ea0536a92a63ec2f4d97f65dbb02604dbb3 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -129,6 +129,7 @@ struct cert_auth_info { + char *token_name; + char *module_name; + char *key_id; ++ char *prompt_str; + struct cert_auth_info *prev; + struct cert_auth_info *next; + }; +@@ -140,6 +141,7 @@ static void free_cai(struct cert_auth_info *cai) + free(cai->cert); + free(cai->token_name); + free(cai->key_id); ++ free(cai->prompt_str); + free(cai); + } + } +@@ -921,9 +923,25 @@ static int parse_cert_info(struct pam_items *pi, uint8_t *buf, size_t len, + goto done; + } + +- D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s]", ++ offset += strlen(cai->key_id) + 1; ++ if (offset >= len) { ++ D(("Cert message size mismatch")); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ cai->prompt_str = strdup((char *) &buf[*p + offset]); ++ if (cai->prompt_str == NULL) { ++ D(("strdup failed")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ++ D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s] " ++ "prompt: [%s]", + cai->cert_user, cai->token_name, cai->module_name, +- cai->key_id)); ++ cai->key_id, cai->prompt_str)); + + DLIST_ADD(pi->cert_list, cai); + ret = 0; +@@ -1543,7 +1561,7 @@ done: + #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) + #endif + +-#define CERT_SEL_PROMPT_FMT "Certificate: %s" ++#define CERT_SEL_PROMPT_FMT "%s" + #define SEL_TITLE discard_const("Please select a certificate") + + static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi) +@@ -1588,7 +1606,7 @@ static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi) + + c = 0; + DLIST_FOR_EACH(cai, pi->cert_list) { +- ret = asprintf(&prompt, CERT_SEL_PROMPT_FMT, cai->key_id); ++ ret = asprintf(&prompt, CERT_SEL_PROMPT_FMT, cai->prompt_str); + if (ret == -1) { + ret = ENOMEM; + goto done; +@@ -1637,9 +1655,10 @@ done: + #endif + } + +-#define TEXT_CERT_SEL_PROMPT_FMT "%s[%zu] Certificate: %s\n" ++#define TEXT_CERT_SEL_PROMPT_FMT "%s\n[%zu]:\n%s\n" + #define TEXT_SEL_TITLE discard_const("Please select a certificate by typing " \ + "the corresponding number\n") ++ + static int prompt_multi_cert(pam_handle_t *pamh, struct pam_items *pi) + { + int ret; +@@ -1670,7 +1689,7 @@ static int prompt_multi_cert(pam_handle_t *pamh, struct pam_items *pi) + DLIST_FOR_EACH(cai, pi->cert_list) { + cert_count++; + ret = asprintf(&tmp, TEXT_CERT_SEL_PROMPT_FMT, prompt, cert_count, +- cai->key_id); ++ cai->prompt_str); + free(prompt); + if (ret == -1) { + return ENOMEM; +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 5c1f621ccead75717d1721714d953d7d4d415d7b..50d3ed005468375ff02c60bebd1c61047ca1c6d4 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -53,6 +53,7 @@ + #define TEST_TOKEN_NAME "SSSD Test Token" + #define TEST_MODULE_NAME "NSS-Internal" + #define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7" ++#define TEST_SUBJECT_DN "CN=ipa-devel.ipa.devel,O=IPA.DEVEL" + #define TEST_TOKEN_CERT \ + "MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ + "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ +@@ -78,6 +79,7 @@ + "XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g=" + + #define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C" ++#define TEST2_SUBJECT_DN "CN=IPA RA,O=IPA.DEVEL" + #define TEST_TOKEN_2ND_CERT \ + "MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ + "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ +@@ -831,7 +833,8 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) +- + sizeof(TEST_KEY_ID))); ++ + sizeof(TEST_KEY_ID) ++ + sizeof(TEST_SUBJECT_DN))); + + assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); + assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); +@@ -849,6 +852,10 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + ++ assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0); ++ assert_string_equal(body + rp, TEST_SUBJECT_DN); ++ rp += sizeof(TEST_SUBJECT_DN); ++ + assert_int_equal(rp, blen); + return EOK; + } +@@ -893,7 +900,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_int_equal(val, (strlen(name) + 1 + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) +- + sizeof(TEST_KEY_ID))); ++ + sizeof(TEST_KEY_ID) ++ + sizeof(TEST_SUBJECT_DN))); + + assert_int_equal(*(body + rp + strlen(name)), 0); + assert_string_equal(body + rp, name); +@@ -911,6 +919,10 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + ++ assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0); ++ assert_string_equal(body + rp, TEST_SUBJECT_DN); ++ rp += sizeof(TEST_SUBJECT_DN); ++ + if (name2 != NULL && *name2 != '\0') { + SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); + assert_int_equal(val, type); +@@ -919,7 +931,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_int_equal(val, (strlen(name) + 1 + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) +- + sizeof(TEST2_KEY_ID))); ++ + sizeof(TEST2_KEY_ID) ++ + sizeof(TEST2_SUBJECT_DN))); + + assert_int_equal(*(body + rp + strlen(name)), 0); + assert_string_equal(body + rp, name); +@@ -936,6 +949,10 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_int_equal(*(body + rp + sizeof(TEST2_KEY_ID) - 1), 0); + assert_string_equal(body + rp, TEST2_KEY_ID); + rp += sizeof(TEST2_KEY_ID); ++ ++ assert_int_equal(*(body + rp + sizeof(TEST2_SUBJECT_DN) - 1), 0); ++ assert_string_equal(body + rp, TEST2_SUBJECT_DN); ++ rp += sizeof(TEST2_SUBJECT_DN); + } + + assert_int_equal(rp, blen); +-- +2.13.6 + diff --git a/SOURCES/0041-PAM-allow-missing-logon_name-during-certificate-auth.patch b/SOURCES/0041-PAM-allow-missing-logon_name-during-certificate-auth.patch new file mode 100644 index 0000000..669c063 --- /dev/null +++ b/SOURCES/0041-PAM-allow-missing-logon_name-during-certificate-auth.patch @@ -0,0 +1,256 @@ +From f6e57537cbeaf6e3f313e700f08e0022a32a7d6c Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 30 Oct 2017 17:11:56 +0100 +Subject: [PATCH 41/46] PAM: allow missing logon_name during certificate + authentication +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If only one certificate is available and the logon_name is the user is +not given the PAM responder already tried to find the name during the +pre-auth step. With multiple certificates this might cause useless extra +effort and the name should be determined after the certificate is +selected in the authentication step. This might currently only happen +with GDM because all other PAM clients will prompt for the user name +unconditionally. + +New unit tests are added to cover this new case. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +(cherry picked from commit fd6f4047b58686bd4057c9859c3c804a77b136d8) +--- + src/responder/pam/pamsrv_cmd.c | 63 ++++++++++++++++++++++++++----- + src/tests/cmocka/test_pam_srv.c | 82 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 135 insertions(+), 10 deletions(-) + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index 8b2c086e206796ad4c977495be957c56b3255e7f..caf6c99489b8378d2e850473191223709920cd79 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1151,6 +1151,7 @@ static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *p + size_t blen; + errno_t ret; + uint32_t terminator; ++ const char *key_id; + + prctx = talloc_get_type(cctx->protocol_ctx, struct cli_protocol); + +@@ -1191,9 +1192,33 @@ static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *p + pd->logon_name, + &pd->domain, &pd->user); + } else { +- /* Only SSS_PAM_PREAUTH request may have a missing name, e.g. if the +- * name is determined with the help of a certificate */ +- if (pd->cmd == SSS_PAM_PREAUTH ++ /* SSS_PAM_PREAUTH request may have a missing name, e.g. if the ++ * name is determined with the help of a certificate. During ++ * SSS_PAM_AUTHENTICATE at least a key ID is needed to identify the ++ * selected certificate. */ ++ if (pd->cmd == SSS_PAM_AUTHENTICATE ++ && may_do_cert_auth(talloc_get_type(cctx->rctx->pvt_ctx, ++ struct pam_ctx), pd) ++ && (sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_SC_PIN ++ || sss_authtok_get_type(pd->authtok) ++ == SSS_AUTHTOK_TYPE_SC_KEYPAD)) { ++ ret = sss_authtok_get_sc(pd->authtok, NULL, NULL, NULL, NULL, NULL, ++ NULL, &key_id, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc failed.\n"); ++ goto done; ++ } ++ ++ if (key_id == NULL || *key_id == '\0') { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Missing logon and Smartcard key ID during " ++ "authentication.\n"); ++ ret = ERR_NO_CREDS; ++ goto done; ++ } ++ ++ ret = EOK; ++ } else if (pd->cmd == SSS_PAM_PREAUTH + && may_do_cert_auth(talloc_get_type(cctx->rctx->pvt_ctx, + struct pam_ctx), pd)) { + ret = EOK; +@@ -1375,9 +1400,12 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) + /* Determine what domain type to contact */ + preq->req_dom_type = get_domain_request_type(preq, pctx); + +- /* try backend first for authentication before doing local Smartcard +- * authentication */ +- if (pd->cmd != SSS_PAM_AUTHENTICATE && may_do_cert_auth(pctx, pd)) { ++ /* Try backend first for authentication before doing local Smartcard ++ * authentication if a logon name is available. Otherwise try to derive ++ * the logon name from the certificate first. */ ++ if ((pd->cmd != SSS_PAM_AUTHENTICATE ++ || (pd->cmd == SSS_PAM_AUTHENTICATE && pd->logon_name == NULL)) ++ && may_do_cert_auth(pctx, pd)) { + ret = check_cert(cctx, cctx->ev, pctx, preq, pd); + /* Finish here */ + goto done; +@@ -1577,9 +1605,10 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + } else { + + if (preq->pd->logon_name == NULL) { +- if (preq->pd->cmd != SSS_PAM_PREAUTH) { ++ if (preq->pd->cmd != SSS_PAM_PREAUTH ++ && preq->pd->cmd != SSS_PAM_AUTHENTICATE) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Missing logon name only allowed during pre-auth.\n"); ++ "Missing logon name only allowed during (pre-)auth.\n"); + ret = ENOENT; + goto done; + } +@@ -1641,7 +1670,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + } + } + +- if (preq->cctx->rctx->domains->user_name_hint) { ++ if (preq->cctx->rctx->domains->user_name_hint ++ && preq->pd->cmd == SSS_PAM_PREAUTH) { + ret = add_pam_cert_response(preq->pd, cert_user, + preq->cert_list, + SSS_PAM_CERT_INFO_WITH_HINT); +@@ -1664,6 +1694,20 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + goto done; + } + ++ /* If logon_name was not given during authentication add a ++ * SSS_PAM_CERT_INFO message to send the name to the caller. */ ++ if (preq->pd->cmd == SSS_PAM_AUTHENTICATE ++ && preq->pd->logon_name == NULL) { ++ ret = add_pam_cert_response(preq->pd, cert_user, ++ preq->cert_list, ++ SSS_PAM_CERT_INFO); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); ++ preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; ++ goto done; ++ } ++ } ++ + /* cert_user will be returned to the PAM client as user name, so + * we can use it here already e.g. to set in initgroups timeout */ + preq->pd->logon_name = talloc_strdup(preq->pd, cert_user); +@@ -2039,7 +2083,6 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) + "the backend.\n"); + } + +- /* FIXME: use the right cert info */ + ret = add_pam_cert_response(preq->pd, cert_user, + preq->current_cert, + SSS_PAM_CERT_INFO); +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 50d3ed005468375ff02c60bebd1c61047ca1c6d4..b6845320ca41d6933280aa2836a3d984dacfcc5e 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -967,6 +967,16 @@ static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) + NULL); + } + ++static int test_pam_cert_check_auth_success(uint32_t status, uint8_t *body, ++ size_t blen) ++{ ++ assert_int_equal(pam_test_ctx->exp_pam_status, PAM_BAD_ITEM); ++ pam_test_ctx->exp_pam_status = PAM_SUCCESS; ++ return test_pam_cert_check_ex(status, body, blen, ++ SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME, ++ NULL); ++} ++ + static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body, + size_t blen) + { +@@ -2265,6 +2275,74 @@ void test_pam_cert_auth(void **state) + assert_int_equal(ret, EOK); + } + ++void test_pam_cert_auth_no_logon_name(void **state) ++{ ++ int ret; ++ ++ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); ++ ++ /* Here the last option must be set to true because the backend is only ++ * connected once. During authentication the backend is connected first to ++ * see if it can handle Smartcard authentication, but before that the user ++ * is looked up. Since the first mocked reply already adds the certificate ++ * to the user entry the lookup by certificate will already find the user ++ * in the cache and no second request to the backend is needed. */ ++ mock_input_pam_cert(pam_test_ctx, NULL, "123456", "SSSD Test Token", ++ "NSS-Internal", ++ "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL, ++ test_lookup_by_cert_cb, TEST_TOKEN_CERT, true); ++ ++ mock_account_recv_simple(); ++ mock_parse_inp("pamuser", NULL, EOK); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ /* Assume backend cannot handle Smartcard credentials */ ++ pam_test_ctx->exp_pam_status = PAM_BAD_ITEM; ++ ++ set_cmd_cb(test_pam_cert_check_auth_success); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_pam_cert_auth_no_logon_name_no_key_id(void **state) ++{ ++ int ret; ++ ++ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); ++ ++ /* Here the last option must be set to true because the backend is only ++ * connected once. During authentication the backend is connected first to ++ * see if it can handle Smartcard authentication, but before that the user ++ * is looked up. Since the first mocked reply already adds the certificate ++ * to the user entry the lookup by certificate will already find the user ++ * in the cache and no second request to the backend is needed. */ ++ mock_input_pam_cert(pam_test_ctx, NULL, "123456", "SSSD Test Token", ++ "NSS-Internal", NULL, NULL, ++ NULL, NULL, false); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ /* Assume backend cannot handle Smartcard credentials */ ++ pam_test_ctx->exp_pam_status = PAM_BAD_ITEM; ++ ++ set_cmd_cb(test_pam_creds_insufficient_check); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ + void test_pam_cert_auth_double_cert(void **state) + { + int ret; +@@ -2770,6 +2848,10 @@ int main(int argc, const char *argv[]) + pam_test_setup, pam_test_teardown), + cmocka_unit_test_setup_teardown(test_pam_cert_preauth_2certs_two_mappings, + pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name, ++ pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name_no_key_id, ++ pam_test_setup, pam_test_teardown), + #endif /* HAVE_NSS */ + + cmocka_unit_test_setup_teardown(test_filter_response, +-- +2.13.6 + diff --git a/SOURCES/0041-SUBDOMAINS-Allow-use_fully_qualified_names-for-subdo.patch b/SOURCES/0041-SUBDOMAINS-Allow-use_fully_qualified_names-for-subdo.patch deleted file mode 100644 index f9a0fe3..0000000 --- a/SOURCES/0041-SUBDOMAINS-Allow-use_fully_qualified_names-for-subdo.patch +++ /dev/null @@ -1,531 +0,0 @@ -From 887b53d8833ab91835cb3afbdadcbf9d091dafcd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Thu, 23 Mar 2017 13:14:56 +0100 -Subject: [PATCH 41/54] SUBDOMAINS: Allow use_fully_qualified_names for - subdomains -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Allow option use_fully_qualified_names in subdomain section. -This option was recently added to subdomain_inherit. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3337 - -Reviewed-by: Fabiano Fidêncio ---- - src/db/sysdb.h | 3 +- - src/db/sysdb_private.h | 3 +- - src/db/sysdb_subdomains.c | 63 +++++++++++++++++++++++++-- - src/man/sssd.conf.5.xml | 3 +- - src/providers/ad/ad_subdomains.c | 3 +- - src/providers/ipa/ipa_subdomains.c | 10 +++-- - src/responder/common/responder_get_domains.c | 9 ++-- - src/tests/cmocka/test_fqnames.c | 2 +- - src/tests/cmocka/test_ipa_subdomains_server.c | 2 +- - src/tests/cmocka/test_nss_srv.c | 6 ++- - src/tests/cmocka/test_sysdb_subdomains.c | 25 ++++++----- - src/tests/sysdb-tests.c | 14 +++--- - src/tools/common/sss_tools.c | 2 +- - src/tools/sss_cache.c | 2 +- - 14 files changed, 107 insertions(+), 40 deletions(-) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 0cbb2c5c02355e9e9a4e73b075f92d16e4855045..6762b51bee02911fb97d5d393fad2495504ee5ad 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -494,7 +494,8 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, - uint32_t trust_direction, - struct ldb_message_element *upn_suffixes); - --errno_t sysdb_update_subdomains(struct sss_domain_info *domain); -+errno_t sysdb_update_subdomains(struct sss_domain_info *domain, -+ struct confdb_ctx *confdb); - - errno_t sysdb_master_domain_update(struct sss_domain_info *domain); - -diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h -index bfd24799950ab3b31d57df11b8f91c0b2572f13a..dfddd2dda9e593bd02d52dee7d06f520a11bbdf6 100644 ---- a/src/db/sysdb_private.h -+++ b/src/db/sysdb_private.h -@@ -191,7 +191,8 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, - bool enumerate, - const char *forest, - const char **upn_suffixes, -- uint32_t trust_direction); -+ uint32_t trust_direction, -+ struct confdb_ctx *confdb); - - /* Helper functions to deal with the timestamp cache should not be used - * outside the sysdb itself. The timestamp cache should be completely -diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c -index 01f49763b712769f4f74df47961526e5b1514cd4..916dbba153d8c08837425f6fd29a20f5a6aa9fc9 100644 ---- a/src/db/sysdb_subdomains.c -+++ b/src/db/sysdb_subdomains.c -@@ -23,6 +23,10 @@ - #include "util/util.h" - #include "db/sysdb_private.h" - -+static errno_t -+check_subdom_config_file(struct confdb_ctx *confdb, -+ struct sss_domain_info *subdomain); -+ - struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, - struct sss_domain_info *parent, - const char *name, -@@ -33,10 +37,12 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, - bool enumerate, - const char *forest, - const char **upn_suffixes, -- uint32_t trust_direction) -+ uint32_t trust_direction, -+ struct confdb_ctx *confdb) - { - struct sss_domain_info *dom; - bool inherit_option; -+ errno_t ret; - - DEBUG(SSSDBG_TRACE_FUNC, - "Creating [%s] as subdomain of [%s]!\n", name, parent->name); -@@ -160,6 +166,17 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, - } - dom->sysdb = parent->sysdb; - -+ if (confdb != NULL) { -+ /* If confdb was provided, also check for sssd.conf */ -+ ret = check_subdom_config_file(confdb, dom); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to read subdomain configuration [%d]: %s", -+ ret, sss_strerror(ret)); -+ goto fail; -+ } -+ } -+ - return dom; - - fail: -@@ -167,6 +184,45 @@ fail: - return NULL; - } - -+static errno_t -+check_subdom_config_file(struct confdb_ctx *confdb, -+ struct sss_domain_info *subdomain) -+{ -+ char *sd_conf_path; -+ TALLOC_CTX *tmp_ctx; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ sd_conf_path = subdomain_create_conf_path(tmp_ctx, subdomain); -+ if (sd_conf_path == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ /* use_fully_qualified_names */ -+ ret = confdb_get_bool(confdb, sd_conf_path, CONFDB_DOMAIN_FQ, -+ true, &subdomain->fqnames); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to get %s option for the subdomain: %s\n", -+ CONFDB_DOMAIN_FQ, subdomain->name); -+ goto done; -+ } -+ -+ DEBUG(SSSDBG_CONF_SETTINGS, "%s/%s has value %s\n", -+ sd_conf_path, CONFDB_DOMAIN_FQ, -+ subdomain->fqnames ? "TRUE" : "FALSE"); -+ -+ ret = EOK; -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ - static bool is_forest_root(struct sss_domain_info *d) - { - if (d->forest == NULL) { -@@ -232,7 +288,8 @@ static void link_forest_roots(struct sss_domain_info *domain) - } - } - --errno_t sysdb_update_subdomains(struct sss_domain_info *domain) -+errno_t sysdb_update_subdomains(struct sss_domain_info *domain, -+ struct confdb_ctx *confdb) - { - int i; - errno_t ret; -@@ -451,7 +508,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain) - if (dom == NULL) { - dom = new_subdomain(domain, domain, name, realm, - flat, id, mpg, enumerate, forest, -- upn_suffixes, trust_direction); -+ upn_suffixes, trust_direction, confdb); - if (dom == NULL) { - ret = ENOMEM; - goto done; -diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml -index 284402bc00d37c6c33bf195d2bd719300f265851..1c27742cf0c1b6ffad23ab5b044bf4a168ed8f69 100644 ---- a/src/man/sssd.conf.5.xml -+++ b/src/man/sssd.conf.5.xml -@@ -2780,7 +2780,8 @@ subdomain_inherit = ldap_purge_cache_timeout - ldap_service_search_base, - ad_server, - ad_backup_server, -- ad_site. -+ ad_site, -+ use_fully_qualified_names - - For more details about these options see their individual description - in the manual page. -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index eecae9c9ca82ad67874c13a3c7b7c617d6232d5c..bc659b2cb0a02723437d24d0021ec3592381e84c 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -656,7 +656,8 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx) - /* Just continue */ - } - -- ret = sysdb_update_subdomains(subdoms_ctx->be_ctx->domain); -+ ret = sysdb_update_subdomains(subdoms_ctx->be_ctx->domain, -+ subdoms_ctx->be_ctx->cdb); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n"); - return ret; -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index 7537550606ef09c0b87a80932c75aa4f93c0efab..a07b88fe2f499353293ba90345552413c9792f4b 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -126,7 +126,7 @@ ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx) - return ret; - } - -- ret = sysdb_update_subdomains(ctx->be_ctx->domain); -+ ret = sysdb_update_subdomains(ctx->be_ctx->domain, ctx->be_ctx->cdb); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n"); - return ret; -@@ -780,7 +780,8 @@ done: - static errno_t ipa_apply_view(struct sss_domain_info *domain, - struct ipa_id_ctx *ipa_id_ctx, - const char *view_name, -- bool read_at_init) -+ bool read_at_init, -+ struct confdb_ctx *confdb) - { - const char *current = ipa_id_ctx->view_name; - struct sysdb_ctx *sysdb = domain->sysdb; -@@ -876,7 +877,7 @@ static errno_t ipa_apply_view(struct sss_domain_info *domain, - goto done; - } - -- ret = sysdb_update_subdomains(domain); -+ ret = sysdb_update_subdomains(domain, confdb); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed " - "[%d]: %s\n", ret, sss_strerror(ret)); -@@ -1654,7 +1655,8 @@ static void ipa_subdomains_view_name_done(struct tevent_req *subreq) - - ret = ipa_apply_view(state->sd_ctx->be_ctx->domain, - state->sd_ctx->ipa_id_ctx, view_name, -- state->sd_ctx->view_read_at_init); -+ state->sd_ctx->view_read_at_init, -+ state->sd_ctx->be_ctx->cdb); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set view [%d]: %s\n", - ret, sss_strerror(ret)); -diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c -index 0f39d107dad6c458785b1b8d708e60d7c34e3901..0f9c01214631200f9687635f6302fa5c07e8a1fe 100644 ---- a/src/responder/common/responder_get_domains.c -+++ b/src/responder/common/responder_get_domains.c -@@ -126,7 +126,8 @@ get_next_domain_recv(TALLOC_CTX *mem_ctx, - } - - /* ====== Iterate over all domains, searching for their subdomains ======= */ --static errno_t process_subdomains(struct sss_domain_info *dom); -+static errno_t process_subdomains(struct sss_domain_info *dom, -+ struct confdb_ctx *confdb); - static void set_time_of_last_request(struct resp_ctx *rctx); - static errno_t check_last_request(struct resp_ctx *rctx, const char *hint); - -@@ -234,7 +235,7 @@ sss_dp_get_domains_process(struct tevent_req *subreq) - goto fail; - } - -- ret = process_subdomains(state->dom); -+ ret = process_subdomains(state->dom, state->rctx->cdb); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "process_subdomains failed, " - "trying next domain.\n"); -@@ -270,7 +271,7 @@ fail: - } - - static errno_t --process_subdomains(struct sss_domain_info *domain) -+process_subdomains(struct sss_domain_info *domain, struct confdb_ctx *confdb) - { - int ret; - -@@ -288,7 +289,7 @@ process_subdomains(struct sss_domain_info *domain) - /* Retrieve all subdomains of this domain from sysdb - * and create their struct sss_domain_info representations - */ -- ret = sysdb_update_subdomains(domain); -+ ret = sysdb_update_subdomains(domain, confdb); - if (ret != EOK) { - DEBUG(SSSDBG_FUNC_DATA, "sysdb_update_subdomains failed.\n"); - goto done; -diff --git a/src/tests/cmocka/test_fqnames.c b/src/tests/cmocka/test_fqnames.c -index 19788248a39774bb4509363145ac4ce0815b7d28..0ed42a597b7787635c4971b4f1c3d9976949ccd2 100644 ---- a/src/tests/cmocka/test_fqnames.c -+++ b/src/tests/cmocka/test_fqnames.c -@@ -309,7 +309,7 @@ static int parse_name_test_setup(void **state) - * discovered - */ - test_ctx->subdom = new_subdomain(dom, dom, SUBDOMNAME, NULL, SUBFLATNAME, -- NULL, false, false, NULL, NULL, 0); -+ NULL, false, false, NULL, NULL, 0, NULL); - assert_non_null(test_ctx->subdom); - - check_leaks_push(test_ctx); -diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c -index 123cf11c01ef4687eecad31a9d73120a87c643e1..ca48425aca69e58358f5fd37e4b8238bfa9efe15 100644 ---- a/src/tests/cmocka/test_ipa_subdomains_server.c -+++ b/src/tests/cmocka/test_ipa_subdomains_server.c -@@ -263,7 +263,7 @@ static void add_test_subdomains(struct trust_test_ctx *test_ctx, - direction, NULL); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(test_ctx->tctx->dom); -+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - } -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 50714715cc80338640f2a77ecbe17bd5e0d6e911..3d7e0382197401cb2264671712152fe0709296b6 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -3206,7 +3206,8 @@ static int nss_subdom_test_setup(void **state) - - subdomain = new_subdomain(nss_test_ctx, nss_test_ctx->tctx->dom, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, NULL, 0); -+ false, false, NULL, NULL, 0, -+ nss_test_ctx->tctx->confdb); - assert_non_null(subdomain); - - ret = sysdb_subdomain_store(nss_test_ctx->tctx->sysdb, -@@ -3214,7 +3215,8 @@ static int nss_subdom_test_setup(void **state) - false, false, NULL, 0, NULL); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(nss_test_ctx->tctx->dom); -+ ret = sysdb_update_subdomains(nss_test_ctx->tctx->dom, -+ nss_test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - nss_test_ctx->subdom = subdomain; -diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c -index 49f44998a06740d1df70ac354ee741824acd8f50..84bcdc17b39dbc8822097c2006f157a09ea5e466 100644 ---- a/src/tests/cmocka/test_sysdb_subdomains.c -+++ b/src/tests/cmocka/test_sysdb_subdomains.c -@@ -103,7 +103,7 @@ static void test_sysdb_subdomain_create(void **state) - false, false, NULL, 0, NULL); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(test_ctx->tctx->dom); -+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - assert_non_null(test_ctx->tctx->dom->subdomains); -@@ -115,7 +115,7 @@ static void test_sysdb_subdomain_create(void **state) - false, false, NULL, 1, NULL); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(test_ctx->tctx->dom); -+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - assert_non_null(test_ctx->tctx->dom->subdomains->next); -@@ -133,7 +133,7 @@ static void test_sysdb_subdomain_create(void **state) - false, false, NULL, 0, NULL); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(test_ctx->tctx->dom); -+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - assert_int_equal(test_ctx->tctx->dom->subdomains->trust_direction, 1); -@@ -145,7 +145,7 @@ static void test_sysdb_subdomain_create(void **state) - ret = sysdb_subdomain_delete(test_ctx->tctx->sysdb, dom1[0]); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(test_ctx->tctx->dom); -+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - assert_int_equal(sss_domain_get_state(test_ctx->tctx->dom->subdomains), -@@ -235,11 +235,11 @@ static void test_sysdb_link_forest_root_ipa(void **state) - 0, NULL); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(test_ctx->tctx->dom); -+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - /* Also update dom2 */ -- ret = sysdb_update_subdomains(test_ctx->tctx->dom->next); -+ ret = sysdb_update_subdomains(test_ctx->tctx->dom->next, test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - sub = find_domain_by_name(test_ctx->tctx->dom, dom1[0], true); -@@ -315,11 +315,11 @@ static void test_sysdb_link_forest_root_ad(void **state) - 0, NULL); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(test_ctx->tctx->dom); -+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - /* Also update dom2 */ -- ret = sysdb_update_subdomains(test_ctx->tctx->dom->next); -+ ret = sysdb_update_subdomains(test_ctx->tctx->dom->next, test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - assert_non_null(test_ctx->tctx->dom->forest_root); -@@ -395,14 +395,15 @@ static void test_sysdb_link_forest_member_ad(void **state) - ret = sysdb_master_domain_update(test_ctx->tctx->dom); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(test_ctx->tctx->dom); -+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - /* Also update dom2 */ - ret = sysdb_master_domain_update(test_ctx->tctx->dom->next); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(test_ctx->tctx->dom->next); -+ ret = sysdb_update_subdomains(test_ctx->tctx->dom->next, -+ test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - - /* Checks */ -@@ -472,7 +473,7 @@ static void test_sysdb_link_ad_multidom(void **state) - ret = sysdb_master_domain_update(main_dom1); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(main_dom1); -+ ret = sysdb_update_subdomains(main_dom1, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_master_domain_add_info(main_dom2, -@@ -492,7 +493,7 @@ static void test_sysdb_link_ad_multidom(void **state) - ret = sysdb_master_domain_update(main_dom2); - assert_int_equal(ret, EOK); - -- ret = sysdb_update_subdomains(main_dom2); -+ ret = sysdb_update_subdomains(main_dom2, NULL); - assert_int_equal(ret, EOK); - - main_dom1 = find_domain_by_name(test_ctx->tctx->dom, TEST_DOM1_NAME, true); -diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c -index 5bdd631fbfa1b4463fb169e5f07b65fb2c784096..1767dc3c734c6b2e5f74564debd603e2442f491b 100644 ---- a/src/tests/sysdb-tests.c -+++ b/src/tests/sysdb-tests.c -@@ -1395,7 +1395,7 @@ START_TEST (test_sysdb_get_user_attr_subdomain) - /* Create subdomain */ - subdomain = new_subdomain(test_ctx, test_ctx->domain, - "test.sub", "TEST.SUB", "test", "S-3", -- false, false, NULL, NULL, 0); -+ false, false, NULL, NULL, 0, NULL); - fail_if(subdomain == NULL, "Failed to create new subdomain."); - - ret = sss_names_init_from_args(test_ctx, -@@ -5821,14 +5821,14 @@ START_TEST(test_sysdb_subdomain_store_user) - - subdomain = new_subdomain(test_ctx, test_ctx->domain, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, NULL, 0); -+ false, false, NULL, NULL, 0, NULL); - fail_unless(subdomain != NULL, "Failed to create new subdomin."); - ret = sysdb_subdomain_store(test_ctx->sysdb, - testdom[0], testdom[1], testdom[2], testdom[3], - false, false, NULL, 0, NULL); - fail_if(ret != EOK, "Could not set up the test (test subdom)"); - -- ret = sysdb_update_subdomains(test_ctx->domain); -+ ret = sysdb_update_subdomains(test_ctx->domain, NULL); - fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]", - ret, strerror(ret)); - -@@ -5900,14 +5900,14 @@ START_TEST(test_sysdb_subdomain_user_ops) - - subdomain = new_subdomain(test_ctx, test_ctx->domain, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, NULL, 0); -+ false, false, NULL, NULL, 0, NULL); - fail_unless(subdomain != NULL, "Failed to create new subdomin."); - ret = sysdb_subdomain_store(test_ctx->sysdb, - testdom[0], testdom[1], testdom[2], testdom[3], - false, false, NULL, 0, NULL); - fail_if(ret != EOK, "Could not set up the test (test subdom)"); - -- ret = sysdb_update_subdomains(test_ctx->domain); -+ ret = sysdb_update_subdomains(test_ctx->domain, NULL); - fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]", - ret, strerror(ret)); - -@@ -5973,14 +5973,14 @@ START_TEST(test_sysdb_subdomain_group_ops) - - subdomain = new_subdomain(test_ctx, test_ctx->domain, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, NULL, 0); -+ false, false, NULL, NULL, 0, NULL); - fail_unless(subdomain != NULL, "Failed to create new subdomin."); - ret = sysdb_subdomain_store(test_ctx->sysdb, - testdom[0], testdom[1], testdom[2], testdom[3], - false, false, NULL, 0, NULL); - fail_if(ret != EOK, "Could not set up the test (test subdom)"); - -- ret = sysdb_update_subdomains(test_ctx->domain); -+ ret = sysdb_update_subdomains(test_ctx->domain, NULL); - fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]", - ret, strerror(ret)); - -diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c -index 0f4f46894130daf722641f25a4cdfaae220252cc..97a3caab3bec88c5727eea2f08b200f1d3b23f0c 100644 ---- a/src/tools/common/sss_tools.c -+++ b/src/tools/common/sss_tools.c -@@ -154,7 +154,7 @@ static errno_t sss_tool_domains_init(TALLOC_CTX *mem_ctx, - } - - /* Update list of subdomains for this domain */ -- ret = sysdb_update_subdomains(dom); -+ ret = sysdb_update_subdomains(dom, confdb); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Failed to update subdomains for domain %s.\n", -diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c -index 59e49a8aa92e3a08ec80e0597304f1a4af0a02be..8a40b38c07f7e76cde5b98e5916816581fea7973 100644 ---- a/src/tools/sss_cache.c -+++ b/src/tools/sss_cache.c -@@ -158,7 +158,7 @@ int main(int argc, const char *argv[]) - dinfo = get_next_domain(dinfo, SSS_GND_DESCEND)) { - if (!IS_SUBDOMAIN(dinfo)) { - /* Update list of subdomains for this domain */ -- ret = sysdb_update_subdomains(dinfo); -+ ret = sysdb_update_subdomains(dinfo, tctx->confdb); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Failed to update subdomains for domain %s.\n", dinfo->name); --- -2.9.3 - diff --git a/SOURCES/0042-CACHE_REQ-Descend-into-subdomains-on-lookups.patch b/SOURCES/0042-CACHE_REQ-Descend-into-subdomains-on-lookups.patch deleted file mode 100644 index 583b606..0000000 --- a/SOURCES/0042-CACHE_REQ-Descend-into-subdomains-on-lookups.patch +++ /dev/null @@ -1,172 +0,0 @@ -From 73b3b167e86a87263563aa8aac2b45cdf3668765 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 1 Mar 2017 08:34:57 +0000 -Subject: [PATCH 42/54] CACHE_REQ: Descend into subdomains on lookups -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Let's make all plugins, but the "host_by_name", to descend into the -subdomains on lookups. - -This patch basically prepares the field for the coming up patches that -will allow group/user resolution in all domains (or a subset of the -domains) to be possible by only using the short names without the domain -component. - -The "host_by_name" plugin was not changed as it's a specific IPA plugin -and won't find anything on its subdomains. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Pavel Březina -Reviewed-by: Sumit Bose ---- - src/responder/common/cache_req/plugins/cache_req_enum_svc.c | 2 +- - src/responder/common/cache_req/plugins/cache_req_group_by_filter.c | 2 +- - src/responder/common/cache_req/plugins/cache_req_group_by_name.c | 2 +- - src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c | 2 +- - src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c | 2 +- - src/responder/common/cache_req/plugins/cache_req_object_by_name.c | 2 +- - src/responder/common/cache_req/plugins/cache_req_svc_by_name.c | 2 +- - src/responder/common/cache_req/plugins/cache_req_svc_by_port.c | 2 +- - src/responder/common/cache_req/plugins/cache_req_user_by_filter.c | 2 +- - src/responder/common/cache_req/plugins/cache_req_user_by_name.c | 2 +- - 10 files changed, 10 insertions(+), 10 deletions(-) - -diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c -index 2c4917cde750c9063d898c16d3a58ca8c179bc70..28dea33c601f500b9c7af0de3eb9e1c342f03522 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c -+++ b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c -@@ -68,7 +68,7 @@ const struct cache_req_plugin cache_req_enum_svc = { - .allow_missing_fqn = true, - .allow_switch_to_upn = false, - .upn_equivalent = CACHE_REQ_SENTINEL, -- .get_next_domain_flags = 0, -+ .get_next_domain_flags = SSS_GND_DESCEND, - - .is_well_known_fn = NULL, - .prepare_domain_data_fn = NULL, -diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c -index 88e1137a3976308aaf404b684c6d88cc43708bca..6ce6ae0d63967ac50b813a47ac938251619948da 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c -+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c -@@ -123,7 +123,7 @@ const struct cache_req_plugin cache_req_group_by_filter = { - .allow_missing_fqn = false, - .allow_switch_to_upn = false, - .upn_equivalent = CACHE_REQ_SENTINEL, -- .get_next_domain_flags = 0, -+ .get_next_domain_flags = SSS_GND_DESCEND, - - .is_well_known_fn = NULL, - .prepare_domain_data_fn = cache_req_group_by_filter_prepare_domain_data, -diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c -index be1eb9bd8552156d777e934b0be397b0e66df7cc..af6f23ccfd68f952027462ba3e74ed7219d04651 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c -@@ -186,7 +186,7 @@ const struct cache_req_plugin cache_req_group_by_name = { - .allow_missing_fqn = false, - .allow_switch_to_upn = false, - .upn_equivalent = CACHE_REQ_SENTINEL, -- .get_next_domain_flags = 0, -+ .get_next_domain_flags = SSS_GND_DESCEND, - - .is_well_known_fn = NULL, - .prepare_domain_data_fn = cache_req_group_by_name_prepare_domain_data, -diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c -index 10fb67cbf6e78cfae33bc7208585cb80ea6a9bc4..307b65a24282838b99c472b50a71f06865aed3f0 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c -@@ -201,7 +201,7 @@ const struct cache_req_plugin cache_req_initgroups_by_name = { - .allow_missing_fqn = false, - .allow_switch_to_upn = true, - .upn_equivalent = CACHE_REQ_INITGROUPS_BY_UPN, -- .get_next_domain_flags = 0, -+ .get_next_domain_flags = SSS_GND_DESCEND, - - .is_well_known_fn = NULL, - .prepare_domain_data_fn = cache_req_initgroups_by_name_prepare_domain_data, -diff --git a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -index bc6fc9a8f476f97cc4bc5004bc19ba35258a2b6d..e49d6d84a41ce8dabf18c87373826f8e7b684bda 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -@@ -120,7 +120,7 @@ const struct cache_req_plugin cache_req_netgroup_by_name = { - .allow_missing_fqn = true, - .allow_switch_to_upn = false, - .upn_equivalent = CACHE_REQ_SENTINEL, -- .get_next_domain_flags = 0, -+ .get_next_domain_flags = SSS_GND_DESCEND, - - .is_well_known_fn = NULL, - .prepare_domain_data_fn = cache_req_netgroup_by_name_prepare_domain_data, -diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c -index 2b2caeea172b23b1b1b226def5d926e26c5c0090..74d2b3dea287e890b38e4d5bb176ad2dc6337b7e 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c -@@ -196,7 +196,7 @@ const struct cache_req_plugin cache_req_object_by_name = { - .allow_missing_fqn = false, - .allow_switch_to_upn = true, - .upn_equivalent = CACHE_REQ_USER_BY_UPN, -- .get_next_domain_flags = 0, -+ .get_next_domain_flags = SSS_GND_DESCEND, - - .is_well_known_fn = cache_req_object_by_name_well_known, - .prepare_domain_data_fn = cache_req_object_by_name_prepare_domain_data, -diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c -index cbb186df04c7ca7c02dceb98bd5700c984285a4d..ef13f097a8ae78ec9db5b7f6e14924b511578b34 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c -@@ -144,7 +144,7 @@ const struct cache_req_plugin cache_req_svc_by_name = { - .allow_missing_fqn = false, - .allow_switch_to_upn = false, - .upn_equivalent = CACHE_REQ_SENTINEL, -- .get_next_domain_flags = 0, -+ .get_next_domain_flags = SSS_GND_DESCEND, - - .is_well_known_fn = NULL, - .prepare_domain_data_fn = cache_req_svc_by_name_prepare_domain_data, -diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c -index 1da23d4505a1dad3b2425a996134f8298c03518a..afa2eeeda12794de26e798aee4b88900bc87ed93 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c -+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c -@@ -117,7 +117,7 @@ const struct cache_req_plugin cache_req_svc_by_port = { - .allow_missing_fqn = false, - .allow_switch_to_upn = false, - .upn_equivalent = CACHE_REQ_SENTINEL, -- .get_next_domain_flags = 0, -+ .get_next_domain_flags = SSS_GND_DESCEND, - - .is_well_known_fn = NULL, - .prepare_domain_data_fn = cache_req_svc_by_port_prepare_domain_data, -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c -index ee7e69399e318b9835f1623bddc635bf09aa7a1c..eb71b42dad3a805298df0c8425409d571befb31b 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c -@@ -123,7 +123,7 @@ const struct cache_req_plugin cache_req_user_by_filter = { - .allow_missing_fqn = false, - .allow_switch_to_upn = false, - .upn_equivalent = CACHE_REQ_SENTINEL, -- .get_next_domain_flags = 0, -+ .get_next_domain_flags = SSS_GND_DESCEND, - - .is_well_known_fn = NULL, - .prepare_domain_data_fn = cache_req_user_by_filter_prepare_domain_data, -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c -index 4289f5fd4c79f0e512f0249abe4422589fa800a0..0670febdce2d51e0373045570dd07f56255db7bc 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c -@@ -191,7 +191,7 @@ const struct cache_req_plugin cache_req_user_by_name = { - .allow_missing_fqn = false, - .allow_switch_to_upn = true, - .upn_equivalent = CACHE_REQ_USER_BY_UPN, -- .get_next_domain_flags = 0, -+ .get_next_domain_flags = SSS_GND_DESCEND, - - .is_well_known_fn = NULL, - .prepare_domain_data_fn = cache_req_user_by_name_prepare_domain_data, --- -2.9.3 - diff --git a/SOURCES/0042-p11_child-add-descriptions-for-error-codes-to-debug-.patch b/SOURCES/0042-p11_child-add-descriptions-for-error-codes-to-debug-.patch new file mode 100644 index 0000000..37350b5 --- /dev/null +++ b/SOURCES/0042-p11_child-add-descriptions-for-error-codes-to-debug-.patch @@ -0,0 +1,276 @@ +From aa476a78b67a60d4ca2433091268a7790b4d62f7 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 30 Oct 2017 10:22:33 +0100 +Subject: [PATCH 42/46] p11_child: add descriptions for error codes to debug + messages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Additionally to the NSS erro code a text message describing the error is +added. This will help to see why p11_child ignores specific +certificates. For example it would be more obvious why the certificate +is not valid (expired, missing CA cert, failed OCSP etc). + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +(cherry picked from commit 08d1f8c0d6eece6a48201d7f8824b282eac3458d) +--- + src/p11_child/p11_child_nss.c | 91 ++++++++++++++++++++++++------------------- + 1 file changed, 50 insertions(+), 41 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index c676375cf7f6677a1d7f38f09b9bb5fd820d60c5..5f289688e41f4ea610292b907036e05cf95eb29d 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -75,15 +75,16 @@ static char *get_key_id_str(PK11SlotInfo *slot, CERTCertificate *cert) + key_id = PK11_GetLowLevelKeyIDForCert(slot, cert, NULL); + if (key_id == NULL) { + DEBUG(SSSDBG_OP_FAILURE, +- "PK11_GetLowLevelKeyIDForCert failed [%d].\n", +- PR_GetError()); ++ "PK11_GetLowLevelKeyIDForCert failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return NULL; + } + + key_id_str = CERT_Hexify(key_id, PR_FALSE); + SECITEM_FreeItem(key_id, PR_TRUE); + if (key_id_str == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return NULL; + } + +@@ -138,8 +139,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + + nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, ¶meters, flags); + if (nss_ctx == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + +@@ -232,8 +233,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + if (pin != NULL) { + rv = PK11_Authenticate(slot, PR_FALSE, discard_const(pin)); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "PK11_Authenticate failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "PK11_Authenticate failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + } else { +@@ -246,8 +247,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + + cert_list = PK11_ListCertsInSlot(slot); + if (cert_list == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "PK11_ListCertsInSlot failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "PK11_ListCertsInSlot failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + +@@ -265,31 +266,33 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + + rv = CERT_FilterCertListByUsage(cert_list, certUsageSSLClient, PR_FALSE); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + + rv = CERT_FilterCertListForUserCerts(cert_list); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListForUserCerts failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, ++ "CERT_FilterCertListForUserCerts failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + + + handle = CERT_GetDefaultCertDB(); + if (handle == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + + if (cert_verify_opts->do_ocsp) { + rv = CERT_EnableOCSPChecking(handle); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_EnableOCSPChecking failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, ++ "CERT_EnableOCSPChecking failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + +@@ -300,16 +303,16 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + cert_verify_opts->ocsp_default_responder_signing_cert); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "CERT_SetOCSPDefaultResponder failed: [%d].\n", +- PR_GetError()); ++ "CERT_SetOCSPDefaultResponder failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + + rv = CERT_EnableOCSPDefaultResponder(handle); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "CERT_EnableOCSPDefaultResponder failed: [%d].\n", +- PR_GetError()); ++ "CERT_EnableOCSPDefaultResponder failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + } +@@ -318,8 +321,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + found_cert = NULL; + valid_certs = CERT_NewCertList(); + if (valid_certs == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_NewCertList failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_NewCertList failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = ENOMEM; + goto done; + } +@@ -345,9 +348,10 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + NULL, NULL); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "Certificate [%s][%s] not valid [%d], skipping.\n", ++ "Certificate [%s][%s] not valid [%d][%s], skipping.\n", + cert_list_node->cert->nickname, +- cert_list_node->cert->subjectName, PR_GetError()); ++ cert_list_node->cert->subjectName, ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + continue; + } + } +@@ -386,7 +390,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + rv = CERT_AddCertToListTail(valid_certs, cert_list_node->cert); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "CERT_AddCertToListTail failed [%d].\n", PR_GetError()); ++ "CERT_AddCertToListTail failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EIO; + goto done; + } +@@ -400,8 +405,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + rv = CERT_DisableOCSPDefaultResponder(handle); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "CERT_DisableOCSPDefaultResponder failed: [%d].\n", +- PR_GetError()); ++ "CERT_DisableOCSPDefaultResponder failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + } + } + +@@ -433,15 +438,17 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + rv = PK11_GenerateRandom(random_value, sizeof(random_value)); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "PK11_GenerateRandom failed [%d].\n", PR_GetError()); ++ "PK11_GenerateRandom failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + + priv_key = PK11_FindPrivateKeyFromCert(slot, found_cert, NULL); + if (priv_key == NULL) { + DEBUG(SSSDBG_OP_FAILURE, +- "PK11_FindPrivateKeyFromCert failed [%d]." \ +- "Maybe pin is missing.\n", PR_GetError()); ++ "PK11_FindPrivateKeyFromCert failed [%d][%s]." ++ "Maybe pin is missing.\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EIO; + goto done; + } +@@ -451,8 +458,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + if (algtag == SEC_OID_UNKNOWN) { + SECKEY_DestroyPrivateKey(priv_key); + DEBUG(SSSDBG_OP_FAILURE, +- "SEC_GetSignatureAlgorithmOidTag failed [%d].\n", +- PR_GetError()); ++ "SEC_GetSignatureAlgorithmOidTag failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EIO; + goto done; + } +@@ -462,8 +469,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + priv_key, algtag); + SECKEY_DestroyPrivateKey(priv_key); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "SEC_SignData failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "SEC_SignData failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EIO; + goto done; + } +@@ -471,7 +478,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + pub_key = CERT_ExtractPublicKey(found_cert); + if (pub_key == NULL) { + DEBUG(SSSDBG_OP_FAILURE, +- "CERT_ExtractPublicKey failed [%d].\n", PR_GetError()); ++ "CERT_ExtractPublicKey failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EIO; + goto done; + } +@@ -481,8 +489,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + NULL); + SECKEY_DestroyPublicKey(pub_key); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "VFY_VerifyData failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "VFY_VerifyData failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EACCES; + goto done; + } +@@ -507,7 +515,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + PORT_Free(key_id_str); + key_id_str = get_key_id_str(slot, found_cert); + if (key_id_str == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "get_key_id_str [%d].\n", PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "get_key_id_str [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = ENOMEM; + goto done; + } +@@ -562,8 +571,8 @@ done: + + rv = NSS_ShutdownContext(nss_ctx); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + } + + return ret; +-- +2.13.6 + diff --git a/SOURCES/0043-NSS-TESTS-Fix-subdomains-attribution.patch b/SOURCES/0043-NSS-TESTS-Fix-subdomains-attribution.patch deleted file mode 100644 index e142203..0000000 --- a/SOURCES/0043-NSS-TESTS-Fix-subdomains-attribution.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 5e3ea50bba1fee75cc0788bcd77ae4991828608e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Wed, 1 Mar 2017 13:21:19 +0000 -Subject: [PATCH 43/54] NSS/TESTS: Fix subdomains attribution -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Reviewed-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/tests/cmocka/test_nss_srv.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 3d7e0382197401cb2264671712152fe0709296b6..cbe0dccdc1d883eae1a9621f12997ef43d05178e 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -3219,7 +3219,7 @@ static int nss_subdom_test_setup(void **state) - nss_test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - -- nss_test_ctx->subdom = subdomain; -+ nss_test_ctx->subdom = nss_test_ctx->tctx->dom->subdomains; - return 0; - } - --- -2.9.3 - diff --git a/SOURCES/0043-pam-filter-certificates-in-the-responder-not-in-the-.patch b/SOURCES/0043-pam-filter-certificates-in-the-responder-not-in-the-.patch new file mode 100644 index 0000000..ac52d99 --- /dev/null +++ b/SOURCES/0043-pam-filter-certificates-in-the-responder-not-in-the-.patch @@ -0,0 +1,357 @@ +From 69c820abacd963a3699fc9ea84a17bb99f9eaf3a Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 6 Nov 2017 15:26:38 +0100 +Subject: [PATCH 43/46] pam: filter certificates in the responder not in the + child +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With the new selection option and the handling of multiple certificates +in the PAM responder it is not needed anymore to filter the certificates +in p11_child but the matching rules can be applied by the PAM responder +directly. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +(cherry picked from commit 177ab84f0e336b75289a3ac0b2df25bd5ab5198b) +--- + src/p11_child/p11_child_nss.c | 18 +----- + src/responder/pam/pamsrv.h | 6 ++ + src/responder/pam/pamsrv_cmd.c | 10 ++- + src/responder/pam/pamsrv_p11.c | 135 +++++++++++++++++++++++++++++++++++++++- + src/tests/cmocka/test_pam_srv.c | 3 + + 5 files changed, 152 insertions(+), 20 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index 5f289688e41f4ea610292b907036e05cf95eb29d..e59aba0d1561f58206252f7251ecd88315836b1b 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -264,22 +264,6 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + } + } + +- rv = CERT_FilterCertListByUsage(cert_list, certUsageSSLClient, PR_FALSE); +- if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d][%s].\n", +- PR_GetError(), PORT_ErrorToString(PR_GetError())); +- return EIO; +- } +- +- rv = CERT_FilterCertListForUserCerts(cert_list); +- if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, +- "CERT_FilterCertListForUserCerts failed: [%d][%s].\n", +- PR_GetError(), PORT_ErrorToString(PR_GetError())); +- return EIO; +- } +- +- + handle = CERT_GetDefaultCertDB(); + if (handle == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d][%s].\n", +@@ -344,7 +328,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + if (cert_verify_opts->do_verification) { + rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert, + PR_TRUE, +- certificateUsageSSLClient, ++ certificateUsageCheckAllUsages, + NULL, NULL); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index f15f7f19f1f38626288416c9f2038371c6f58b47..0bc229212844602ed461d1c7db48bf51ac2e2194 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -27,6 +27,7 @@ + #include "sbus/sssd_dbus.h" + #include "responder/common/responder.h" + #include "responder/common/cache_req/cache_req.h" ++#include "lib/certmap/sss_certmap.h" + + struct pam_auth_req; + +@@ -49,6 +50,7 @@ struct pam_ctx { + bool cert_auth; + int p11_child_debug_fd; + char *nss_db; ++ struct sss_certmap_ctx *sss_certmap_ctx; + }; + + struct pam_auth_dp_req { +@@ -104,6 +106,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + const char *nss_db, + time_t timeout, + const char *verify_opts, ++ struct sss_certmap_ctx *sss_certmap_ctx, + struct pam_data *pd); + errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct cert_auth_info **cert_list); +@@ -114,6 +117,9 @@ 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); ++ + errno_t + pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain, + const char *username, +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index caf6c99489b8378d2e850473191223709920cd79..0e76c9e772f1775635677f35b870e9613b2faf64 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1336,7 +1336,8 @@ static errno_t check_cert(TALLOC_CTX *mctx, + + req = pam_check_cert_send(mctx, ev, pctx->p11_child_debug_fd, + pctx->nss_db, p11_child_timeout, +- cert_verification_opts, pd); ++ cert_verification_opts, pctx->sss_certmap_ctx, ++ pd); + if (req == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n"); + return ENOMEM; +@@ -1749,6 +1750,13 @@ static void pam_forwarder_cb(struct tevent_req *req) + goto done; + } + ++ ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains->certmaps); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "p11_refresh_certmap_ctx failed, " ++ "certificate matching might not work as expected"); ++ } ++ + pd = preq->pd; + + ret = pam_forwarder_parse_data(cctx, pd); +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index 5a3eeff0ec977829a9ad8c80b4fc6b2e06857097..ec52c5ae7163d41144fe082643a201b766a1e201 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -36,6 +36,7 @@ + + #define P11_CHILD_LOG_FILE "p11_child" + #define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child" ++#define CERT_AUTH_DEFAULT_MATCHING_RULE "KRB5:clientAuth" + + struct cert_auth_info { + char *cert; +@@ -116,8 +117,110 @@ void sss_cai_check_users(struct cert_auth_info **list, size_t *_cert_count, + return; + } + ++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 p11_refresh_certmap_ctx(struct pam_ctx *pctx, ++ struct certmap_info **certmap_list) ++{ ++ int ret; ++ struct sss_certmap_ctx *sss_certmap_ctx = NULL; ++ size_t c; ++ ++ ret = sss_certmap_init(pctx, ext_debug, NULL, &sss_certmap_ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n"); ++ goto done; ++ } ++ ++ if (certmap_list == NULL || *certmap_list == NULL) { ++ /* 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); ++ if (ret != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to add default matching rule.\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(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: ++ if (ret == EOK) { ++ sss_certmap_free_ctx(pctx->sss_certmap_ctx); ++ pctx->sss_certmap_ctx = sss_certmap_ctx; ++ } else { ++ sss_certmap_free_ctx(sss_certmap_ctx); ++ } ++ ++ return ret; ++} ++ + 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; ++ ++ 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; ++ ++ ret = p11_refresh_certmap_ctx(pctx, dom->certmaps); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "p11_refresh_certmap_ctx failed.\n"); ++ return ret; ++ } ++ + return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd); + } + +@@ -214,6 +317,7 @@ static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx, + + static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, + ssize_t buf_len, ++ struct sss_certmap_ctx *sss_certmap_ctx, + struct cert_auth_info **_cert_list) + { + int ret; +@@ -222,6 +326,8 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, + uint8_t *pn; + struct cert_auth_info *cert_list = NULL; + struct cert_auth_info *cert_auth_info; ++ unsigned char *der = NULL; ++ size_t der_size; + + if (buf_len < 0) { + DEBUG(SSSDBG_CRIT_FAILURE, +@@ -347,7 +453,22 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, + } + DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert_auth_info->cert); + +- DLIST_ADD(cert_list, cert_auth_info); ++ der = sss_base64_decode(tmp_ctx, cert_auth_info->cert, &der_size); ++ if (der == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n"); ++ ret = EIO; ++ goto done; ++ } ++ ++ ret = sss_certmap_match_cert(sss_certmap_ctx, der, der_size); ++ if (ret == 0) { ++ DLIST_ADD(cert_list, cert_auth_info); ++ } else { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Cert [%s] does not match matching rules and is ignored.\n", ++ cert_auth_info->cert); ++ talloc_free(cert_auth_info); ++ } + + p = ++pn; + } while ((pn - buf) < buf_len); +@@ -373,6 +494,7 @@ struct pam_check_cert_state { + struct sss_child_ctx_old *child_ctx; + struct tevent_timer *timeout_handler; + struct tevent_context *ev; ++ struct sss_certmap_ctx *sss_certmap_ctx; + + struct child_io_fds *io; + +@@ -391,6 +513,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + const char *nss_db, + time_t timeout, + const char *verify_opts, ++ struct sss_certmap_ctx *sss_certmap_ctx, + struct pam_data *pd) + { + errno_t ret; +@@ -420,6 +543,12 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + goto done; + } + ++ if (sss_certmap_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Missing certificate matching context.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ + /* extra_args are added in revers order */ + arg_c = 0; + extra_args[arg_c++] = nss_db; +@@ -476,6 +605,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + } + + state->ev = ev; ++ state->sss_certmap_ctx = sss_certmap_ctx; + state->child_status = EFAULT; + state->io = talloc(state, struct child_io_fds); + if (state->io == NULL) { +@@ -639,7 +769,8 @@ static void p11_child_done(struct tevent_req *subreq) + + PIPE_FD_CLOSE(state->io->read_from_child_fd); + +- ret = parse_p11_child_response(state, buf, buf_len, &state->cert_list); ++ ret = parse_p11_child_response(state, buf, buf_len, state->sss_certmap_ctx, ++ &state->cert_list); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_response failed.\n"); + tevent_req_error(req, ret); +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index b6845320ca41d6933280aa2836a3d984dacfcc5e..bccf9972dacbb414076904a783772198620fd73c 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -287,6 +287,9 @@ struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx) + return NULL; + } + ++ ret = p11_refresh_certmap_ctx(pctx, NULL); ++ assert_int_equal(ret, 0); ++ + return pctx; + } + +-- +2.13.6 + diff --git a/SOURCES/0044-NSS-TESTS-Improve-setup-teardown-for-subdomains-test.patch b/SOURCES/0044-NSS-TESTS-Improve-setup-teardown-for-subdomains-test.patch deleted file mode 100644 index 9eb42a4..0000000 --- a/SOURCES/0044-NSS-TESTS-Improve-setup-teardown-for-subdomains-test.patch +++ /dev/null @@ -1,274 +0,0 @@ -From f318eff5277d783972ef0d585ff05c473db44714 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 1 Mar 2017 20:46:10 +0000 -Subject: [PATCH 44/54] NSS/TESTS: Improve setup/teardown for subdomains tests -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch basically makes the getgrnam_members_subdom(), -getgrnam_mix_dom(), getgrnam_mix_dom_fqdn() and getgrnam_mix_subdom() -more independent of each other. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/tests/cmocka/test_nss_srv.c | 182 +++++++++++++++++++++++++++++++++------- - 1 file changed, 150 insertions(+), 32 deletions(-) - -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index cbe0dccdc1d883eae1a9621f12997ef43d05178e..b468204fb1729618830513322f0d901c4c801e94 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -418,6 +418,26 @@ static errno_t store_user(struct nss_test_ctx *ctx, - return ret; - } - -+static errno_t delete_user(struct nss_test_ctx *ctx, -+ struct sss_domain_info *dom, -+ struct passwd *user) -+{ -+ errno_t ret; -+ char *fqname; -+ -+ fqname = sss_create_internal_fqname(ctx, -+ user->pw_name, -+ dom->name); -+ if (fqname == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = sysdb_delete_user(dom, fqname, user->pw_uid); -+ -+ talloc_free(fqname); -+ return ret; -+} -+ - static errno_t set_user_attr(struct nss_test_ctx *ctx, - struct sss_domain_info *dom, - struct passwd *user, -@@ -491,6 +511,27 @@ static errno_t store_group(struct nss_test_ctx *ctx, - return ret; - } - -+static errno_t delete_group(struct nss_test_ctx *ctx, -+ struct sss_domain_info *dom, -+ struct group *group) -+{ -+ errno_t ret; -+ char *fqname; -+ -+ fqname = sss_create_internal_fqname(ctx, -+ group->gr_name, -+ dom->name); -+ -+ if (fqname == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = sysdb_delete_group(dom, fqname, group->gr_gid); -+ -+ talloc_free(fqname); -+ return ret; -+} -+ - static void assert_groups_equal(struct group *expected, - struct group *gr, const int nmem) - { -@@ -540,6 +581,42 @@ static errno_t store_group_member(struct nss_test_ctx *ctx, - return ret; - } - -+static errno_t remove_group_member(struct nss_test_ctx *ctx, -+ const char *shortname_group, -+ struct sss_domain_info *group_dom, -+ const char *shortname_member, -+ struct sss_domain_info *member_dom, -+ enum sysdb_member_type type) -+{ -+ errno_t ret; -+ char *group_fqname = NULL; -+ char *member_fqname = NULL; -+ -+ group_fqname = sss_create_internal_fqname(ctx, -+ shortname_group, -+ group_dom->name); -+ if (group_fqname == NULL) { -+ return ENOMEM; -+ } -+ -+ member_fqname = sss_create_internal_fqname(ctx, -+ shortname_member, -+ member_dom->name); -+ if (member_fqname == NULL) { -+ talloc_free(group_fqname); -+ return ENOMEM; -+ } -+ -+ ret = sysdb_remove_group_member(group_dom, -+ group_fqname, -+ member_fqname, -+ type, -+ false); -+ -+ talloc_free(group_fqname); -+ talloc_free(member_fqname); -+ return ret; -+} - - /* ====================== The tests =============================== */ - struct passwd getpwnam_usr = { -@@ -1599,34 +1676,6 @@ void test_nss_getgrnam_members_subdom(void **state) - { - errno_t ret; - -- ret = store_group(nss_test_ctx, nss_test_ctx->subdom, -- &testsubdomgroup, 0); -- assert_int_equal(ret, EOK); -- -- ret = store_user(nss_test_ctx, nss_test_ctx->subdom, -- &submember1, NULL, 0); -- assert_int_equal(ret, EOK); -- -- ret = store_user(nss_test_ctx, nss_test_ctx->subdom, -- &submember2, NULL, 0); -- assert_int_equal(ret, EOK); -- -- ret = store_group_member(nss_test_ctx, -- testsubdomgroup.gr_name, -- nss_test_ctx->subdom, -- submember1.pw_name, -- nss_test_ctx->subdom, -- SYSDB_MEMBER_USER); -- assert_int_equal(ret, EOK); -- -- ret = store_group_member(nss_test_ctx, -- testsubdomgroup.gr_name, -- nss_test_ctx->subdom, -- submember2.pw_name, -- nss_test_ctx->subdom, -- SYSDB_MEMBER_USER); -- assert_int_equal(ret, EOK); -- - mock_input_user_or_group("testsubdomgroup@"TEST_SUBDOM_NAME); - will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); - will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -@@ -1757,6 +1806,14 @@ void test_nss_getgrnam_mix_dom_fqdn(void **state) - { - errno_t ret; - -+ ret = store_group_member(nss_test_ctx, -+ testgroup_members.gr_name, -+ nss_test_ctx->tctx->dom, -+ submember1.pw_name, -+ nss_test_ctx->subdom, -+ SYSDB_MEMBER_USER); -+ assert_int_equal(ret, EOK); -+ - nss_test_ctx->tctx->dom->fqnames = true; - - mock_input_user_or_group("testgroup_members@"TEST_DOM_NAME); -@@ -3220,6 +3277,35 @@ static int nss_subdom_test_setup(void **state) - assert_int_equal(ret, EOK); - - nss_test_ctx->subdom = nss_test_ctx->tctx->dom->subdomains; -+ -+ ret = store_group(nss_test_ctx, nss_test_ctx->subdom, -+ &testsubdomgroup, 0); -+ assert_int_equal(ret, EOK); -+ -+ ret = store_user(nss_test_ctx, nss_test_ctx->subdom, -+ &submember1, NULL, 0); -+ assert_int_equal(ret, EOK); -+ -+ ret = store_user(nss_test_ctx, nss_test_ctx->subdom, -+ &submember2, NULL, 0); -+ assert_int_equal(ret, EOK); -+ -+ ret = store_group_member(nss_test_ctx, -+ testsubdomgroup.gr_name, -+ nss_test_ctx->subdom, -+ submember1.pw_name, -+ nss_test_ctx->subdom, -+ SYSDB_MEMBER_USER); -+ assert_int_equal(ret, EOK); -+ -+ ret = store_group_member(nss_test_ctx, -+ testsubdomgroup.gr_name, -+ nss_test_ctx->subdom, -+ submember2.pw_name, -+ nss_test_ctx->subdom, -+ SYSDB_MEMBER_USER); -+ assert_int_equal(ret, EOK); -+ - return 0; - } - -@@ -3241,6 +3327,38 @@ static int nss_test_teardown(void **state) - return 0; - } - -+static int nss_subdom_test_teardown(void **state) -+{ -+ errno_t ret; -+ -+ ret = remove_group_member(nss_test_ctx, -+ testsubdomgroup.gr_name, -+ nss_test_ctx->subdom, -+ submember2.pw_name, -+ nss_test_ctx->subdom, -+ SYSDB_MEMBER_USER); -+ assert_int_equal(ret, EOK); -+ -+ ret = remove_group_member(nss_test_ctx, -+ testsubdomgroup.gr_name, -+ nss_test_ctx->subdom, -+ submember1.pw_name, -+ nss_test_ctx->subdom, -+ SYSDB_MEMBER_USER); -+ assert_int_equal(ret, EOK); -+ -+ ret = delete_user(nss_test_ctx, nss_test_ctx->subdom, &submember2); -+ assert_int_equal(ret, EOK); -+ -+ ret = delete_user(nss_test_ctx, nss_test_ctx->subdom, &submember1); -+ assert_int_equal(ret, EOK); -+ -+ ret = delete_group(nss_test_ctx, nss_test_ctx->subdom, &testsubdomgroup); -+ assert_int_equal(ret, EOK); -+ -+ return nss_test_teardown(state); -+} -+ - struct passwd testbysid = { - .pw_name = discard_const("testsiduser"), - .pw_uid = 12345, -@@ -3904,16 +4022,16 @@ int main(int argc, const char *argv[]) - nss_fqdn_test_setup, nss_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_subdom, - nss_subdom_test_setup, -- nss_test_teardown), -+ nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom, - nss_subdom_test_setup, -- nss_test_teardown), -+ nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn, - nss_subdom_test_setup, -- nss_test_teardown), -+ nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom, - nss_subdom_test_setup, -- nss_test_teardown), -+ nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_space, - nss_test_setup, nss_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_space_sub, --- -2.9.3 - diff --git a/SOURCES/0044-PAM-add-certificate-s-label-to-the-selection-prompt.patch b/SOURCES/0044-PAM-add-certificate-s-label-to-the-selection-prompt.patch new file mode 100644 index 0000000..4ec3f7b --- /dev/null +++ b/SOURCES/0044-PAM-add-certificate-s-label-to-the-selection-prompt.patch @@ -0,0 +1,274 @@ +From 35790511fd43b0c33f3b410b20a31e007b3e5d20 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 7 Nov 2017 09:52:56 +0100 +Subject: [PATCH 44/46] PAM: add certificate's label to the selection prompt +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some types of Smartcards contain multiple certificate with the same +subject-DN for different usages. To make it easier to choose between +them in case the matching rules allow more than one of them for +authentication the label assigned to the certificate on the Smartcard is +shown in the selection prompt as well. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +(cherry picked from commit 57cefea8305a57c1c0491afb739813b7f17d5a25) +--- + src/p11_child/p11_child_nss.c | 18 ++++++++++++++---- + src/responder/pam/pamsrv.h | 1 + + src/responder/pam/pamsrv_p11.c | 41 +++++++++++++++++++++++++++++++++++++---- + src/tests/cmocka/test_pam_srv.c | 28 ++++++++++++++-------------- + 4 files changed, 66 insertions(+), 22 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index e59aba0d1561f58206252f7251ecd88315836b1b..21c508eb1b1b68b3606d0a5eed36573b01f27a19 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -130,7 +130,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + CERTCertificate *found_cert = NULL; + PK11SlotList *list = NULL; + PK11SlotListElement *le; +- SECItem *key_id = NULL; ++ const char *label; + char *key_id_str = NULL; + CERTCertList *valid_certs = NULL; + char *cert_b64 = NULL; +@@ -505,6 +505,17 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + goto done; + } + ++ /* The NSS nickname is typically token_name:label, so the label starts ++ * after the ':'. */ ++ if (found_cert->nickname != NULL) { ++ if ((label = strchr(found_cert->nickname, ':')) == NULL) { ++ label = found_cert->nickname; ++ } else { ++ label++; ++ } ++ } else { ++ label = "- no label found -"; ++ } + talloc_free(cert_b64); + cert_b64 = sss_base64_encode(mem_ctx, found_cert->derCert.data, + found_cert->derCert.len); +@@ -517,9 +528,9 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n", + key_id_str); + +- multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n", ++ multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n%s\n", + token_name, module_name, key_id_str, +- cert_b64); ++ label, cert_b64); + } + *_multi = multi; + +@@ -546,7 +557,6 @@ done: + CERT_DestroyCertList(cert_list); + } + +- SECITEM_FreeItem(key_id, PR_TRUE); + PORT_Free(key_id_str); + + PORT_Free(signed_random_value.data); +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index 0bc229212844602ed461d1c7db48bf51ac2e2194..dfd982178446d6327e09afc652018886c08fd88a 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -93,6 +93,7 @@ const char *sss_cai_get_cert(struct cert_auth_info *i); + const char *sss_cai_get_token_name(struct cert_auth_info *i); + const char *sss_cai_get_module_name(struct cert_auth_info *i); + const char *sss_cai_get_key_id(struct cert_auth_info *i); ++const char *sss_cai_get_label(struct cert_auth_info *i); + struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i); + struct ldb_result *sss_cai_get_cert_user_objs(struct cert_auth_info *i); + void sss_cai_set_cert_user_objs(struct cert_auth_info *i, +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index ec52c5ae7163d41144fe082643a201b766a1e201..fa2435543ea305f7cdb1e18753525beb373eaf4c 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -43,6 +43,7 @@ struct cert_auth_info { + char *token_name; + char *module_name; + char *key_id; ++ char *label; + struct ldb_result *cert_user_objs; + struct cert_auth_info *prev; + struct cert_auth_info *next; +@@ -68,6 +69,11 @@ const char *sss_cai_get_key_id(struct cert_auth_info *i) + return i != NULL ? i->key_id : NULL; + } + ++const char *sss_cai_get_label(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->label : NULL; ++} ++ + struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i) + { + return i != NULL ? i->next : NULL; +@@ -439,6 +445,31 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, + } + + if (pn == p) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing label in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ cert_auth_info->label = talloc_strndup(cert_auth_info, (char *) p, ++ (pn - p)); ++ if (cert_auth_info->label == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "Found label [%s].\n", cert_auth_info->label); ++ ++ p = ++pn; ++ pn = memchr(p, '\n', buf_len - (p - buf)); ++ if (pn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing new-line in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ if (pn == p) { + DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n"); + ret = EINVAL; + goto done; +@@ -816,7 +847,8 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + return EOK; + } + +-static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert) ++static char *get_cert_prompt(TALLOC_CTX *mem_ctx, ++ struct cert_auth_info *cert_info) + { + int ret; + struct sss_certmap_ctx *ctx = NULL; +@@ -839,7 +871,7 @@ static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert) + goto done; + } + +- der = sss_base64_decode(mem_ctx, cert, &der_size); ++ der = sss_base64_decode(mem_ctx, sss_cai_get_cert(cert_info), &der_size); + if (der == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n"); + goto done; +@@ -851,7 +883,8 @@ static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert) + goto done; + } + +- prompt = talloc_strdup(mem_ctx, filter); ++ prompt = talloc_asprintf(mem_ctx, "%s\n%s", sss_cai_get_label(cert_info), ++ filter); + if (prompt == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + } +@@ -885,7 +918,7 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + username = sysdb_username; + } + +- prompt = get_cert_prompt(mem_ctx, sss_cai_get_cert(cert_info)); ++ prompt = get_cert_prompt(mem_ctx, cert_info); + if (prompt == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "get_cert_prompt failed.\n"); + return EIO; +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index bccf9972dacbb414076904a783772198620fd73c..4752648796ab4c863706780a2f470853cddbcc11 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -53,7 +53,7 @@ + #define TEST_TOKEN_NAME "SSSD Test Token" + #define TEST_MODULE_NAME "NSS-Internal" + #define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7" +-#define TEST_SUBJECT_DN "CN=ipa-devel.ipa.devel,O=IPA.DEVEL" ++#define TEST_PROMPT "Server-Cert\nCN=ipa-devel.ipa.devel,O=IPA.DEVEL" + #define TEST_TOKEN_CERT \ + "MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ + "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ +@@ -79,7 +79,7 @@ + "XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g=" + + #define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C" +-#define TEST2_SUBJECT_DN "CN=IPA RA,O=IPA.DEVEL" ++#define TEST2_PROMPT "ipaCert\nCN=IPA RA,O=IPA.DEVEL" + #define TEST_TOKEN_2ND_CERT \ + "MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ + "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ +@@ -837,7 +837,7 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) + + sizeof(TEST_KEY_ID) +- + sizeof(TEST_SUBJECT_DN))); ++ + sizeof(TEST_PROMPT))); + + assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); + assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); +@@ -855,9 +855,9 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + +- assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0); +- assert_string_equal(body + rp, TEST_SUBJECT_DN); +- rp += sizeof(TEST_SUBJECT_DN); ++ assert_int_equal(*(body + rp + sizeof(TEST_PROMPT) - 1), 0); ++ assert_string_equal(body + rp, TEST_PROMPT); ++ rp += sizeof(TEST_PROMPT); + + assert_int_equal(rp, blen); + return EOK; +@@ -904,7 +904,7 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) + + sizeof(TEST_KEY_ID) +- + sizeof(TEST_SUBJECT_DN))); ++ + sizeof(TEST_PROMPT))); + + assert_int_equal(*(body + rp + strlen(name)), 0); + assert_string_equal(body + rp, name); +@@ -922,9 +922,9 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + +- assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0); +- assert_string_equal(body + rp, TEST_SUBJECT_DN); +- rp += sizeof(TEST_SUBJECT_DN); ++ assert_int_equal(*(body + rp + sizeof(TEST_PROMPT) - 1), 0); ++ assert_string_equal(body + rp, TEST_PROMPT); ++ rp += sizeof(TEST_PROMPT); + + if (name2 != NULL && *name2 != '\0') { + SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); +@@ -935,7 +935,7 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) + + sizeof(TEST2_KEY_ID) +- + sizeof(TEST2_SUBJECT_DN))); ++ + sizeof(TEST2_PROMPT))); + + assert_int_equal(*(body + rp + strlen(name)), 0); + assert_string_equal(body + rp, name); +@@ -953,9 +953,9 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_string_equal(body + rp, TEST2_KEY_ID); + rp += sizeof(TEST2_KEY_ID); + +- assert_int_equal(*(body + rp + sizeof(TEST2_SUBJECT_DN) - 1), 0); +- assert_string_equal(body + rp, TEST2_SUBJECT_DN); +- rp += sizeof(TEST2_SUBJECT_DN); ++ assert_int_equal(*(body + rp + sizeof(TEST2_PROMPT) - 1), 0); ++ assert_string_equal(body + rp, TEST2_PROMPT); ++ rp += sizeof(TEST2_PROMPT); + } + + assert_int_equal(rp, blen); +-- +2.13.6 + diff --git a/SOURCES/0045-NSS-TESTS-Include-searches-for-non-fqnames-members-o.patch b/SOURCES/0045-NSS-TESTS-Include-searches-for-non-fqnames-members-o.patch deleted file mode 100644 index 08acdce..0000000 --- a/SOURCES/0045-NSS-TESTS-Include-searches-for-non-fqnames-members-o.patch +++ /dev/null @@ -1,355 +0,0 @@ -From 510971d2abc3b76799048cd608511d693f5c3edc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 1 Mar 2017 08:33:06 +0000 -Subject: [PATCH 45/54] NSS/TESTS: Include searches for non-fqnames members of - a subdomain -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Let's extend the NSS tests in order to also test looking up users, from -a subdomain, by their short names (non fully qualified names). - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/tests/cmocka/test_nss_srv.c | 246 ++++++++++++++++++++++++++++++++++------ - 1 file changed, 211 insertions(+), 35 deletions(-) - -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index b468204fb1729618830513322f0d901c4c801e94..ede72b341b60842ad470df2794aa90ea9797e999 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -1648,16 +1648,29 @@ static int test_nss_getgrnam_members_check_subdom(uint32_t status, - tmp_ctx = talloc_new(nss_test_ctx); - assert_non_null(tmp_ctx); - -- exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, submember1.pw_name); -- assert_non_null(exp_members[0]); -- exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, submember2.pw_name); -- assert_non_null(exp_members[1]); -+ if (nss_test_ctx->subdom->fqnames) { -+ exp_members[0] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember1.pw_name); -+ assert_non_null(exp_members[0]); - -- expected.gr_name = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, testsubdomgroup.gr_name); -- assert_non_null(expected.gr_name); -+ exp_members[1] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember2.pw_name); -+ assert_non_null(exp_members[1]); -+ -+ expected.gr_name = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ testsubdomgroup.gr_name); -+ assert_non_null(expected.gr_name); -+ } else { -+ exp_members[0] = submember1.pw_name; -+ exp_members[1] = submember2.pw_name; -+ expected.gr_name = testsubdomgroup.gr_name; -+ } - - assert_int_equal(status, EOK); - -@@ -1692,6 +1705,29 @@ void test_nss_getgrnam_members_subdom(void **state) - assert_int_equal(ret, EOK); - } - -+void test_nss_getgrnam_members_subdom_nonfqnames(void **state) -+{ -+ errno_t ret; -+ -+ nss_test_ctx->subdom->fqnames = false; -+ -+ mock_input_user_or_group("testsubdomgroup"); -+ mock_account_recv_simple(); -+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); -+ will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ /* Query for that group, call a callback when command finishes */ -+ set_cmd_cb(test_nss_getgrnam_members_check_subdom); -+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, -+ nss_test_ctx->nss_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(nss_test_ctx->tctx); -+ -+ assert_int_equal(ret, EOK); -+} -+ - static int test_nss_getgrnam_check_mix_dom(uint32_t status, - uint8_t *body, size_t blen) - { -@@ -1710,9 +1746,15 @@ static int test_nss_getgrnam_check_mix_dom(uint32_t status, - tmp_ctx = talloc_new(nss_test_ctx); - assert_non_null(tmp_ctx); - -- exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, submember1.pw_name); -- assert_non_null(exp_members[0]); -+ if (nss_test_ctx->subdom->fqnames) { -+ exp_members[0] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember1.pw_name); -+ assert_non_null(exp_members[0]); -+ } else { -+ exp_members[0] = submember1.pw_name; -+ } - exp_members[1] = testmember1.pw_name; - exp_members[2] = testmember2.pw_name; - -@@ -1756,6 +1798,35 @@ void test_nss_getgrnam_mix_dom(void **state) - assert_int_equal(ret, EOK); - } - -+void test_nss_getgrnam_mix_dom_nonfqnames(void **state) -+{ -+ errno_t ret; -+ -+ nss_test_ctx->subdom->fqnames = false; -+ -+ ret = store_group_member(nss_test_ctx, -+ testgroup_members.gr_name, -+ nss_test_ctx->tctx->dom, -+ submember1.pw_name, -+ nss_test_ctx->subdom, -+ SYSDB_MEMBER_USER); -+ assert_int_equal(ret, EOK); -+ -+ mock_input_user_or_group("testgroup_members"); -+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); -+ will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ /* Query for that group, call a callback when command finishes */ -+ set_cmd_cb(test_nss_getgrnam_check_mix_dom); -+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, -+ nss_test_ctx->nss_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(nss_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ - static int test_nss_getgrnam_check_mix_dom_fqdn(uint32_t status, - uint8_t *body, size_t blen) - { -@@ -1773,21 +1844,33 @@ static int test_nss_getgrnam_check_mix_dom_fqdn(uint32_t status, - tmp_ctx = talloc_new(nss_test_ctx); - assert_non_null(tmp_ctx); - -- exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, submember1.pw_name); -- assert_non_null(exp_members[0]); -- exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, -- nss_test_ctx->tctx->dom, testmember1.pw_name); -- assert_non_null(exp_members[1]); -- exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, -- nss_test_ctx->tctx->dom, testmember2.pw_name); -- assert_non_null(exp_members[2]); -+ if (nss_test_ctx->subdom->fqnames) { -+ exp_members[0] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember1.pw_name); -+ assert_non_null(exp_members[0]); -+ } else { -+ exp_members[0] = submember1.pw_name; -+ } -+ if (nss_test_ctx->tctx->dom->fqnames) { -+ exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, -+ nss_test_ctx->tctx->dom, testmember1.pw_name); -+ assert_non_null(exp_members[1]); -+ exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, -+ nss_test_ctx->tctx->dom, testmember2.pw_name); -+ assert_non_null(exp_members[2]); - -- expected.gr_name = sss_tc_fqname(tmp_ctx, -- nss_test_ctx->tctx->dom->names, -- nss_test_ctx->tctx->dom, -- testgroup_members.gr_name); -- assert_non_null(expected.gr_name); -+ expected.gr_name = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->tctx->dom->names, -+ nss_test_ctx->tctx->dom, -+ testgroup_members.gr_name); -+ assert_non_null(expected.gr_name); -+ } else { -+ exp_members[1] = testmember1.pw_name; -+ exp_members[2] = testmember2.pw_name; -+ expected.gr_name = testgroup_members.gr_name; -+ } - - assert_int_equal(status, EOK); - -@@ -1834,6 +1917,40 @@ void test_nss_getgrnam_mix_dom_fqdn(void **state) - assert_int_equal(ret, EOK); - } - -+void test_nss_getgrnam_mix_dom_fqdn_nonfqnames(void **state) -+{ -+ errno_t ret; -+ -+ ret = store_group_member(nss_test_ctx, -+ testgroup_members.gr_name, -+ nss_test_ctx->tctx->dom, -+ submember1.pw_name, -+ nss_test_ctx->subdom, -+ SYSDB_MEMBER_USER); -+ assert_int_equal(ret, EOK); -+ -+ nss_test_ctx->tctx->dom->fqnames = false; -+ nss_test_ctx->subdom->fqnames = false; -+ -+ -+ mock_input_user_or_group("testgroup_members"); -+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); -+ will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ /* Query for that group, call a callback when command finishes */ -+ set_cmd_cb(test_nss_getgrnam_check_mix_dom_fqdn); -+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, -+ nss_test_ctx->nss_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(nss_test_ctx->tctx); -+ -+ /* Restore FQDN settings */ -+ nss_test_ctx->tctx->dom->fqnames = false; -+ assert_int_equal(ret, EOK); -+} -+ - static int test_nss_getgrnam_check_mix_subdom(uint32_t status, - uint8_t *body, size_t blen) - { -@@ -1851,20 +1968,37 @@ static int test_nss_getgrnam_check_mix_subdom(uint32_t status, - tmp_ctx = talloc_new(nss_test_ctx); - assert_non_null(tmp_ctx); - -- exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, submember1.pw_name); -- assert_non_null(exp_members[0]); -- exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, submember2.pw_name); -- assert_non_null(exp_members[1]); -+ if (nss_test_ctx->subdom->fqnames) { -+ exp_members[0] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember1.pw_name); -+ assert_non_null(exp_members[0]); -+ -+ exp_members[1] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember2.pw_name); -+ assert_non_null(exp_members[1]); -+ } else { -+ exp_members[0] = submember1.pw_name; -+ exp_members[1] = submember2.pw_name; -+ } -+ - /* Important: this member is from a non-qualified domain, so his name will - * not be qualified either - */ - exp_members[2] = testmember1.pw_name; - -- expected.gr_name = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, testsubdomgroup.gr_name); -- assert_non_null(expected.gr_name); -+ if (nss_test_ctx->subdom->fqnames) { -+ expected.gr_name = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ testsubdomgroup.gr_name); -+ assert_non_null(expected.gr_name); -+ } else { -+ expected.gr_name = testsubdomgroup.gr_name; -+ } - - assert_int_equal(status, EOK); - -@@ -1906,6 +2040,36 @@ void test_nss_getgrnam_mix_subdom(void **state) - assert_int_equal(ret, EOK); - } - -+void test_nss_getgrnam_mix_subdom_nonfqnames(void **state) -+{ -+ errno_t ret; -+ -+ nss_test_ctx->subdom->fqnames = false; -+ -+ ret = store_group_member(nss_test_ctx, -+ testsubdomgroup.gr_name, -+ nss_test_ctx->subdom, -+ testmember1.pw_name, -+ nss_test_ctx->tctx->dom, -+ SYSDB_MEMBER_USER); -+ assert_int_equal(ret, EOK); -+ -+ mock_input_user_or_group("testsubdomgroup"); -+ mock_account_recv_simple(); -+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); -+ will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ /* Query for that group, call a callback when command finishes */ -+ set_cmd_cb(test_nss_getgrnam_check_mix_subdom); -+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, -+ nss_test_ctx->nss_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(nss_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ - struct group space_group = { - .gr_gid = 2123, - .gr_name = discard_const("space group"), -@@ -4023,15 +4187,27 @@ int main(int argc, const char *argv[]) - cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_subdom, - nss_subdom_test_setup, - nss_subdom_test_teardown), -+ cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_subdom_nonfqnames, -+ nss_subdom_test_setup, -+ nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom, - nss_subdom_test_setup, - nss_subdom_test_teardown), -+ cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_nonfqnames, -+ nss_subdom_test_setup, -+ nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn, - nss_subdom_test_setup, - nss_subdom_test_teardown), -+ cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn_nonfqnames, -+ nss_subdom_test_setup, -+ nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom, - nss_subdom_test_setup, - nss_subdom_test_teardown), -+ cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom_nonfqnames, -+ nss_subdom_test_setup, -+ nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_space, - nss_test_setup, nss_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_space_sub, --- -2.9.3 - diff --git a/SOURCES/0045-SYSDB-Remove-code-causing-a-covscan-warning.patch b/SOURCES/0045-SYSDB-Remove-code-causing-a-covscan-warning.patch new file mode 100644 index 0000000..c2e1d8c --- /dev/null +++ b/SOURCES/0045-SYSDB-Remove-code-causing-a-covscan-warning.patch @@ -0,0 +1,128 @@ +From 075f45980ea004201b2d13a3ecfe3bfb1478046d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 13 Nov 2017 08:29:53 +0100 +Subject: [PATCH 45/46] SYSDB: Remove code causing a covscan warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There's no reason to check for both ret != EOK and sanitized == NULL, as +the second should never ever happen. + +This check is causing a clang warning in our code: + + Defect type: CLANG_WARNING + 1. sssd-1.16.0/src/db/sysdb_ops.c:4223:9: warning: Dereference of undefined pointer value + # if (res->count > 1) { + # ^~~~~~~~~~ + 4. sssd-1.16.0/src/db/sysdb_ops.c:4199:5: note: 'res' declared without an initial value + # struct ldb_result *res; + # ^~~~~~~~~~~~~~~~~~~~~~ + 7. sssd-1.16.0/src/db/sysdb_ops.c:4202:9: note: Assuming 'sid_str' is non-null + # if (!sid_str) return EINVAL; + # ^~~~~~~~ + 10. sssd-1.16.0/src/db/sysdb_ops.c:4202:5: note: Taking false branch + # if (!sid_str) return EINVAL; + # ^ + 13. sssd-1.16.0/src/db/sysdb_ops.c:4205:9: note: Assuming 'tmp_ctx' is non-null + # if (!tmp_ctx) { + # ^~~~~~~~ + 16. sssd-1.16.0/src/db/sysdb_ops.c:4205:5: note: Taking false branch + # if (!tmp_ctx) { + # ^ + 19. sssd-1.16.0/src/db/sysdb_ops.c:4209:11: note: Calling 'sysdb_search_object_by_sid' + # ret = sysdb_search_object_by_sid(tmp_ctx, domain, sid_str, NULL, &res); + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 22. sssd-1.16.0/src/db/sysdb_ops.c:4960:12: note: Calling 'sysdb_search_object_by_str_attr' + # return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_SID_FILTER, + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 25. sssd-1.16.0/src/db/sysdb_ops.c:4872:5: note: Taking false branch + # if (str == NULL) { + # ^ + 28. sssd-1.16.0/src/db/sysdb_ops.c:4877:9: note: Assuming 'ret' is equal to 0 + # if (ret != EOK || sanitized == NULL) { + # ^~~~~~~~~~ + 31. sssd-1.16.0/src/db/sysdb_ops.c:4877:9: note: Left side of '||' is false + 32. sssd-1.16.0/src/db/sysdb_ops.c:4877:23: note: Assuming 'sanitized' is equal to null + # if (ret != EOK || sanitized == NULL) { + # ^~~~~~~~~~~~~~~~~ + 35. sssd-1.16.0/src/db/sysdb_ops.c:4877:5: note: Taking true branch + # if (ret != EOK || sanitized == NULL) { + # ^ + 38. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Left side of '||' is false + # DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n"); + # ^ + 41. sssd-1.16.0/src/util/debug.h:123:9: note: expanded from macro 'DEBUG' + # if (DEBUG_IS_SET(__debug_macro_level)) { \ + # ^ + 44. sssd-1.16.0/src/util/debug.h:135:30: note: expanded from macro 'DEBUG_IS_SET' + # #define DEBUG_IS_SET(level) (debug_level & (level) || \ + # ^ + 47. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Assuming 'debug_level' is not equal to 0 + # DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n"); + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 50. sssd-1.16.0/src/util/debug.h:123:9: note: expanded from macro 'DEBUG' + # if (DEBUG_IS_SET(__debug_macro_level)) { \ + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 53. sssd-1.16.0/src/util/debug.h:136:30: note: expanded from macro 'DEBUG_IS_SET' + # (debug_level == SSSDBG_UNRESOLVED && \ + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 56. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Left side of '&&' is false + 57. sssd-1.16.0/src/util/debug.h:123:9: note: expanded from macro 'DEBUG' + # if (DEBUG_IS_SET(__debug_macro_level)) { \ + # ^ + 60. sssd-1.16.0/src/util/debug.h:136:63: note: expanded from macro 'DEBUG_IS_SET' + # (debug_level == SSSDBG_UNRESOLVED && \ + # ^ + 63. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Loop condition is false. Exiting loop + 64. sssd-1.16.0/src/util/debug.h:121:35: note: expanded from macro 'DEBUG' + # #define DEBUG(level, format, ...) do { \ + # ^ + 67. sssd-1.16.0/src/db/sysdb_ops.c:4879:9: note: Control jumps to line 4892 + # goto done; + # ^ + 70. sssd-1.16.0/src/db/sysdb_ops.c:4960:12: note: Returning from 'sysdb_search_object_by_str_attr' + # return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_SID_FILTER, + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 73. sssd-1.16.0/src/db/sysdb_ops.c:4209:11: note: Returning from 'sysdb_search_object_by_sid' + # ret = sysdb_search_object_by_sid(tmp_ctx, domain, sid_str, NULL, &res); + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 76. sssd-1.16.0/src/db/sysdb_ops.c:4211:5: note: Taking false branch + # if (ret == ENOENT) { + # ^ + 79. sssd-1.16.0/src/db/sysdb_ops.c:4217:12: note: Taking false branch + # } else if (ret != EOK) { + # ^ + 82. sssd-1.16.0/src/db/sysdb_ops.c:4223:9: note: Dereference of undefined pointer value + # if (res->count > 1) { + # ^~~~~~~~~~ + # 4221| } + # 4222| + # 4223|-> if (res->count > 1) { + # 4224| DEBUG(SSSDBG_FATAL_FAILURE, "getbysid call returned more than one " \ + # 4225| "result !?!\n"); + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit b739b3e767c053bb3a7e6651514896b30502d838) +--- + src/db/sysdb_ops.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 2f8e36c6c9a2c2cefe4af5fb78957763304d989a..635c7db51f516e2217c93016409499e49289004c 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -4874,7 +4874,7 @@ static errno_t sysdb_search_object_by_str_attr(TALLOC_CTX *mem_ctx, + } + + ret = sss_filter_sanitize(NULL, str, &sanitized); +- if (ret != EOK || sanitized == NULL) { ++ if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n"); + goto done; + } +-- +2.13.6 + diff --git a/SOURCES/0046-SYSDB-Add-methods-to-deal-with-the-domain-s-resoluti.patch b/SOURCES/0046-SYSDB-Add-methods-to-deal-with-the-domain-s-resoluti.patch deleted file mode 100644 index b2a6305..0000000 --- a/SOURCES/0046-SYSDB-Add-methods-to-deal-with-the-domain-s-resoluti.patch +++ /dev/null @@ -1,289 +0,0 @@ -From b601cae66c441163a00f73c64d00a29e0840d44e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Fri, 24 Mar 2017 15:29:23 +0100 -Subject: [PATCH 46/54] SYSDB: Add methods to deal with the domain's resolution - order -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In the following-up patches those newly introduced methods will be used -to deal with the domainResolutionOrder attribute. - -The sysdb_update_domain_resolution_order() method is purposely not -checking whether a value has changed or not before writing to sysdb and -while may not be optimal, the readability of the code has increased a -lot by keeping it as simple as possible. - -Tests for these new methods are part of the next commit. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - Makefile.am | 2 + - src/db/sysdb.h | 2 + - src/db/sysdb_domain_resolution_order.c | 169 +++++++++++++++++++++++++++++++++ - src/db/sysdb_domain_resolution_order.h | 37 ++++++++ - 4 files changed, 210 insertions(+) - create mode 100644 src/db/sysdb_domain_resolution_order.c - create mode 100644 src/db/sysdb_domain_resolution_order.h - -diff --git a/Makefile.am b/Makefile.am -index 359feddef298b0013c726409b7ba8b86504abf09..8052150be32d89813764e9bc436dfcb211a738d6 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -736,6 +736,7 @@ dist_noinst_HEADERS = \ - src/db/sysdb_private.h \ - src/db/sysdb_services.h \ - src/db/sysdb_ssh.h \ -+ src/db/sysdb_domain_resolution_order.h \ - src/confdb/confdb.h \ - src/confdb/confdb_private.h \ - src/confdb/confdb_setup.h \ -@@ -995,6 +996,7 @@ libsss_util_la_SOURCES = \ - src/db/sysdb_idmap.c \ - src/db/sysdb_gpo.c \ - src/db/sysdb_certmap.c \ -+ src/db/sysdb_domain_resolution_order.c \ - src/monitor/monitor_sbus.c \ - src/providers/dp_auth_util.c \ - src/providers/dp_pam_data_util.c \ -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 6762b51bee02911fb97d5d393fad2495504ee5ad..42d2857ed7765c17e7d84b0da93ed07758fbe012 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -184,6 +184,8 @@ - #define SYSDB_OVERRIDE_GROUP_CLASS "groupOverride" - #define SYSDB_OVERRIDE_DN "overrideDN" - #define SYSDB_OVERRIDE_OBJECT_DN "overrideObjectDN" -+#define SYSDB_USE_DOMAIN_RESOLUTION_ORDER "useDomainResolutionOrder" -+#define SYSDB_DOMAIN_RESOLUTION_ORDER "domainResolutionOrder" - - #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)" - -diff --git a/src/db/sysdb_domain_resolution_order.c b/src/db/sysdb_domain_resolution_order.c -new file mode 100644 -index 0000000000000000000000000000000000000000..63774461a1e9f3dc863220d418e29e06d6e6e6df ---- /dev/null -+++ b/src/db/sysdb_domain_resolution_order.c -@@ -0,0 +1,169 @@ -+/* -+ Authors: -+ Fabiano Fidêncio -+ -+ Copyright (C) 2017 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 "db/sysdb.h" -+#include "db/sysdb_private.h" -+ -+static errno_t -+sysdb_get_domain_resolution_order_string_attr(TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, -+ struct ldb_dn *dn, -+ const char *const *attrs, -+ const char **_attr) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct ldb_result *res; -+ const char *attr; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, -+ NULL); -+ if (ret != LDB_SUCCESS) { -+ ret = EIO; -+ goto done; -+ } -+ -+ if (res->count > 1) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Base search returned [%d] results, expected 1.\n", res->count); -+ ret = EINVAL; -+ goto done; -+ } else if (res->count == 0) { -+ ret = ENOENT; -+ goto done; -+ } else { -+ /* res->count == 1 */ -+ attr = ldb_msg_find_attr_as_string(res->msgs[0], attrs[0], NULL); -+ if (attr == NULL) { -+ ret = ENOENT; -+ goto done; -+ } -+ } -+ -+ *_attr = talloc_steal(mem_ctx, attr); -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ -+errno_t -+sysdb_get_domain_resolution_order(TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, -+ struct ldb_dn *dn, -+ const char **_domain_resolution_order) -+{ -+ TALLOC_CTX *tmp_ctx; -+ const char *domain_resolution_order = NULL; -+ const char *attrs[] = { SYSDB_DOMAIN_RESOLUTION_ORDER, NULL }; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = sysdb_get_domain_resolution_order_string_attr( -+ tmp_ctx, sysdb, dn, attrs, &domain_resolution_order); -+ if (ret != EOK && ret != ENOENT) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_get_domain_resolution_order_string_attr() failed " -+ "[%d]: [%s]", -+ ret, sss_strerror(ret)); -+ goto done; -+ } else if (ret == ENOENT) { -+ *_domain_resolution_order = NULL; -+ goto done; -+ } else { -+ /* ret == EOK */ -+ *_domain_resolution_order = talloc_steal(mem_ctx, -+ domain_resolution_order); -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ -+errno_t -+sysdb_update_domain_resolution_order(struct sysdb_ctx *sysdb, -+ struct ldb_dn *dn, -+ const char *domain_resolution_order) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct ldb_message *msg; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ msg = ldb_msg_new(tmp_ctx); -+ if (msg == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ msg->dn = dn; -+ -+ ret = ldb_msg_add_empty(msg, SYSDB_DOMAIN_RESOLUTION_ORDER, -+ LDB_FLAG_MOD_REPLACE, NULL); -+ if (ret != LDB_SUCCESS) { -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ -+ if (domain_resolution_order != NULL) { -+ ret = ldb_msg_add_string(msg, SYSDB_DOMAIN_RESOLUTION_ORDER, -+ domain_resolution_order); -+ if (ret != LDB_SUCCESS) { -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ } -+ -+ ret = ldb_modify(sysdb->ldb, msg); -+ if (ret != LDB_SUCCESS) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "ldb_modify()_failed: [%s][%d][%s]\n", -+ ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)); -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -diff --git a/src/db/sysdb_domain_resolution_order.h b/src/db/sysdb_domain_resolution_order.h -new file mode 100644 -index 0000000000000000000000000000000000000000..45d2ea63f6bc14cd3184994530846ee6f762d4d0 ---- /dev/null -+++ b/src/db/sysdb_domain_resolution_order.h -@@ -0,0 +1,37 @@ -+/* -+ Authors: -+ Fabiano Fidêncio -+ -+ Copyright (C) 2017 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 . -+*/ -+ -+#ifndef _SYSDB_DOMAIN_RESOLUTION_ORDER_H_ -+#define _SYSDB_DOMAIN_RESOLUTION_ORDER_H_ -+ -+#include "db/sysdb.h" -+ -+errno_t -+sysdb_get_domain_resolution_order(TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, -+ struct ldb_dn *dn, -+ const char **_domain_resolution_order); -+ -+errno_t -+sysdb_update_domain_resolution_order(struct sysdb_ctx *sysdb, -+ struct ldb_dn *dn, -+ const char *domain_resolution_order); -+ -+#endif /* _SYSDB_DOMAIN_RESOLUTION_ORDER_H_ */ --- -2.9.3 - diff --git a/SOURCES/0046-SYSDB-Better-debugging-for-email-conflicts.patch b/SOURCES/0046-SYSDB-Better-debugging-for-email-conflicts.patch new file mode 100644 index 0000000..283ef2a --- /dev/null +++ b/SOURCES/0046-SYSDB-Better-debugging-for-email-conflicts.patch @@ -0,0 +1,94 @@ +From de3b178ada423c10c8f14194a64c299ad96e7bf1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Thu, 26 Oct 2017 18:38:42 +0200 +Subject: [PATCH 46/46] SYSDB: Better debugging for email conflicts +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add DEBUG message when conflicts in FQ names or emails +are detected. + +Also improve man page to hint on how to work around issue +with conflicting emails. + +Note: We store emails in two different attributes in sysdb: +- SYSDB_USER_EMAIL +- SYSDB_NAME_ALIAS - this one is lowercased and used in getpwnam + searches. + +Resolves: +https://fedorahosted.org/sssd/ticket/3293 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 39d6a3be119b050b0690152b6b443117c8617b1c) +--- + src/db/sysdb_ops.c | 4 +++- + src/db/sysdb_search.c | 15 +++++++++++++++ + src/man/sssd-ldap.5.xml | 9 +++++++++ + 3 files changed, 27 insertions(+), 1 deletion(-) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 635c7db51f516e2217c93016409499e49289004c..1539c41c93e7d6ebd1e544abbb1707df5578cd72 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -640,7 +640,9 @@ int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx, + goto done; + } else if (res->count > 1) { + DEBUG(SSSDBG_OP_FAILURE, +- "Search for upn [%s] returns more than one result.\n", upn); ++ "Search for upn [%s] returns more than one result. One of the " ++ "possible reasons can be that several users share the same " ++ "email address.\n", upn); + ret = EINVAL; + goto done; + } +diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c +index f488442afcc6eef114437a7110722759f86fe19e..8083966900429b268a3b984f1cad3d47d1099198 100644 +--- a/src/db/sysdb_search.c ++++ b/src/db/sysdb_search.c +@@ -218,6 +218,21 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx, + goto done; + } + ++ if (res->count > 1) { ++ /* We expected either 0 or 1 result for search with ++ * SYSDB_PWNAM_FILTER, but we got more. This error ++ * is handled individually depending on what function ++ * called sysdb_getpwnam, so we just print a message ++ * here and let the caller decide what error code to ++ * propagate based on res->count > 1. */ ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Search for [%s] returned multiple results. It can be an email " ++ "address shared among multiple users or an email address of a " ++ "user that conflicts with another user's fully qualified name. " ++ "SSSD will not be able to handle those users properly.\n", ++ sanitized_name); ++ } ++ + /* Merge in the timestamps from the fast ts db */ + ret = sysdb_merge_res_ts_attrs(domain->sysdb, res, attrs); + if (ret != EOK) { +diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml +index d38bac3607d294c53ea692130a6b93ced9b0ab82..de596f0da62be9eb61b880b6e1d4a0f33689e25a 100644 +--- a/src/man/sssd-ldap.5.xml ++++ b/src/man/sssd-ldap.5.xml +@@ -878,6 +878,15 @@ + address of the user. + + ++ Note: If an email address of a user conflicts with ++ an email address or fully qualified name of another ++ user, then SSSD will not be able to serve those ++ users properly. If for some reason several users ++ need to share the same email address then set ++ this option to a nonexistent attribute name in ++ order to disable user lookup/login by email. ++ ++ + Default: mail + + +-- +2.13.6 + diff --git a/SOURCES/0047-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch b/SOURCES/0047-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch new file mode 100644 index 0000000..28b8715 --- /dev/null +++ b/SOURCES/0047-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch @@ -0,0 +1,39 @@ +From 3b4479b63ae812c1ef355c1c697caddd882b1b8f Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 6 Nov 2017 17:03:19 +0100 +Subject: [PATCH 47/47] NSS: Use enum_ctx as memory_context in + _setnetgrent_set_timeout() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We've noticed some crashes that happened because enum_ctx is already +freed, but the timeout handler is still called. In order to avoid that, +let's remove the timeout handler when enum_ctx is freed at other places. + +Resolves: https://pagure.io/SSSD/sssd/issue/3523 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit f6a1cef87abdd983d6b5349cd341c9a249826577) +--- + src/responder/nss/nss_enum.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/responder/nss/nss_enum.c b/src/responder/nss/nss_enum.c +index aa7d8428f37e943a6b5904495c40ad4b8011b767..da844fbced529f606a3e98669fb7b95e0696ce00 100644 +--- a/src/responder/nss/nss_enum.c ++++ b/src/responder/nss/nss_enum.c +@@ -283,7 +283,7 @@ nss_setnetgrent_set_timeout(struct tevent_context *ev, + timeout = enum_ctx->result[0]->domain->netgroup_timeout; + + tv = tevent_timeval_current_ofs(timeout, 0); +- te = tevent_add_timer(ev, nss_ctx, tv, nss_setnetgrent_timeout, enum_ctx); ++ te = tevent_add_timer(ev, enum_ctx, tv, nss_setnetgrent_timeout, enum_ctx); + if (te == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not set up life timer for enumeration object.\n"); +-- +2.13.6 + diff --git a/SOURCES/0047-SYSDB-TESTS-Add-tests-for-the-domain-s-resolution-or.patch b/SOURCES/0047-SYSDB-TESTS-Add-tests-for-the-domain-s-resolution-or.patch deleted file mode 100644 index 459a50f..0000000 --- a/SOURCES/0047-SYSDB-TESTS-Add-tests-for-the-domain-s-resolution-or.patch +++ /dev/null @@ -1,259 +0,0 @@ -From 22a10ea2b6b8a56fc040d852867040dce067548a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Fri, 24 Mar 2017 23:15:04 +0100 -Subject: [PATCH 47/54] SYSDB/TESTS: Add tests for the domain's resolution - order methods -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Introduce a new and small set of tests for these new helper methods that -are going to be used in different parts of the code in the follow-up -patches. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - Makefile.am | 16 ++ - .../cmocka/test_sysdb_domain_resolution_order.c | 190 +++++++++++++++++++++ - 2 files changed, 206 insertions(+) - create mode 100644 src/tests/cmocka/test_sysdb_domain_resolution_order.c - -diff --git a/Makefile.am b/Makefile.am -index 8052150be32d89813764e9bc436dfcb211a738d6..450785bf4c482cce1e1440f1336879150537888e 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -263,6 +263,7 @@ if HAVE_CMOCKA - test_sysdb_certmap \ - test_sysdb_sudo \ - test_sysdb_utils \ -+ test_sysdb_domain_resolution_order \ - test_wbc_calls \ - test_be_ptask \ - test_copy_ccache \ -@@ -2875,6 +2876,21 @@ test_sysdb_utils_LDADD = \ - libsss_test_common.la \ - $(NULL) - -+test_sysdb_domain_resolution_order_SOURCES = \ -+ src/tests/cmocka/test_sysdb_domain_resolution_order.c \ -+ $(NULL) -+test_sysdb_domain_resolution_order_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(NULL) -+test_sysdb_domain_resolution_order_LDADD = \ -+ $(CMOCKA_LIBS) \ -+ $(LDB_LIBS) \ -+ $(POPT_LIBS) \ -+ $(TALLOC_LIBS) \ -+ $(SSSD_INTERNAL_LTLIBS) \ -+ libsss_test_common.la \ -+ $(NULL) -+ - test_wbc_calls_SOURCES = \ - src/tests/cmocka/test_wbc_calls.c \ - src/sss_client/idmap/sss_nss_idmap.c \ -diff --git a/src/tests/cmocka/test_sysdb_domain_resolution_order.c b/src/tests/cmocka/test_sysdb_domain_resolution_order.c -new file mode 100644 -index 0000000000000000000000000000000000000000..59a85ce431be9ac27c1e8e6b5e4e5f8300af549e ---- /dev/null -+++ b/src/tests/cmocka/test_sysdb_domain_resolution_order.c -@@ -0,0 +1,190 @@ -+/* -+ SSSD -+ -+ sysdb_domain_resolution_order - Tests for domain resolution order calls -+ -+ Authors: -+ Fabiano Fidêncio -+ -+ Copyright (C) 2017 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 -+#include -+#include -+#include -+ -+#include "tests/cmocka/common_mock.h" -+#include "tests/common.h" -+#include "db/sysdb_domain_resolution_order.h" -+#include "db/sysdb_private.h" /* for sysdb->ldb member */ -+ -+#define TESTS_PATH "tp_" BASE_FILE_STEM -+#define TEST_CONF_DB "test_sysdb_domain_resolution_order.ldb" -+ -+#define TEST_DOM_NAME "test_sysdb_domain_resolution_order" -+ -+#define TEST_ID_PROVIDER "ldap" -+ -+struct domain_resolution_order_test_ctx { -+ struct sss_test_ctx *tctx; -+}; -+ -+static int test_sysdb_domain_resolution_order_setup(void **state) -+{ -+ struct domain_resolution_order_test_ctx *test_ctx; -+ -+ assert_true(leak_check_setup()); -+ -+ test_ctx = talloc_zero(global_talloc_context, -+ struct domain_resolution_order_test_ctx); -+ assert_non_null(test_ctx); -+ -+ test_dom_suite_setup(TESTS_PATH); -+ -+ test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, -+ TEST_CONF_DB, TEST_DOM_NAME, -+ TEST_ID_PROVIDER, NULL); -+ assert_non_null(test_ctx->tctx); -+ -+ *state = test_ctx; -+ return 0; -+} -+ -+static int test_sysdb_domain_resolution_order_teardown(void **state) -+{ -+ struct domain_resolution_order_test_ctx *test_ctx = -+ talloc_get_type(*state, struct domain_resolution_order_test_ctx); -+ -+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); -+ talloc_free(test_ctx); -+ assert_true(leak_check_teardown()); -+ return 0; -+} -+ -+static void test_sysdb_domain_resolution_order_ops(void **state) -+{ -+ errno_t ret; -+ struct domain_resolution_order_test_ctx *test_ctx = -+ talloc_get_type(*state, struct domain_resolution_order_test_ctx); -+ const char *domains_in = NULL; -+ const char *domains_out = NULL; -+ struct ldb_dn *dn; -+ -+ dn = ldb_dn_new_fmt(test_ctx, test_ctx->tctx->dom->sysdb->ldb, -+ SYSDB_DOM_BASE, test_ctx->tctx->dom->name); -+ -+ /* Adding domainResolutionOrder for the first time */ -+ domains_in = "foo:bar:foobar"; -+ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb, -+ dn, domains_in); -+ assert_int_equal(ret, EOK); -+ -+ ret = sysdb_get_domain_resolution_order(test_ctx, -+ test_ctx->tctx->dom->sysdb, dn, -+ &domains_out); -+ assert_int_equal(ret, EOK); -+ assert_true(strcmp(domains_in, domains_out) == 0); -+ -+ /* Setting the domainResolutionOrder to ":" ... -+ * -+ * It means, the domainResolutionOrder is set, but if there's another -+ * domainResolutionOrder with lower precedence those must be ignored. -+ */ -+ domains_in = ":"; -+ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb, -+ dn, domains_in); -+ assert_int_equal(ret, EOK); -+ -+ ret = sysdb_get_domain_resolution_order(test_ctx, -+ test_ctx->tctx->dom->sysdb, dn, -+ &domains_out); -+ assert_int_equal(ret, EOK); -+ assert_true(strcmp(domains_in, domains_out) == 0); -+ -+ /* Changing the domainResolutionOrder */ -+ domains_in = "bar:foobar:foo"; -+ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb, -+ dn, domains_in); -+ assert_int_equal(ret, EOK); -+ -+ ret = sysdb_get_domain_resolution_order(test_ctx, -+ test_ctx->tctx->dom->sysdb, dn, -+ &domains_out); -+ assert_int_equal(ret, EOK); -+ assert_true(strcmp(domains_out, domains_out) == 0); -+ -+ /* Removing the domainResolutionOrder attribute */ -+ domains_in = NULL; -+ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb, -+ dn, domains_in); -+ assert_int_equal(ret, EOK); -+ -+ ret = sysdb_get_domain_resolution_order(test_ctx, -+ test_ctx->tctx->dom->sysdb, dn, -+ &domains_out); -+ assert_int_equal(ret, ENOENT); -+ assert_true(domains_out == NULL); -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ int rv; -+ int no_cleanup = 0; -+ poptContext pc; -+ int opt; -+ struct poptOption long_options[] = { -+ POPT_AUTOHELP -+ SSSD_DEBUG_OPTS -+ {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0, -+ _("Do not delete the test database after a test run"), NULL }, -+ POPT_TABLEEND -+ }; -+ -+ const struct CMUnitTest tests[] = { -+ cmocka_unit_test_setup_teardown(test_sysdb_domain_resolution_order_ops, -+ test_sysdb_domain_resolution_order_setup, -+ test_sysdb_domain_resolution_order_teardown), -+ }; -+ -+ /* Set debug level to invalid value so we can deside if -d 0 was used. */ -+ debug_level = SSSDBG_INVALID; -+ -+ pc = poptGetContext(argv[0], argc, argv, long_options, 0); -+ while((opt = poptGetNextOpt(pc)) != -1) { -+ switch(opt) { -+ default: -+ fprintf(stderr, "\nInvalid option %s: %s\n\n", -+ poptBadOption(pc, 0), poptStrerror(opt)); -+ poptPrintUsage(pc, stderr, 0); -+ return 1; -+ } -+ } -+ poptFreeContext(pc); -+ -+ DEBUG_CLI_INIT(debug_level); -+ -+ tests_set_cwd(); -+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE); -+ test_dom_suite_setup(TESTS_PATH); -+ rv = cmocka_run_group_tests(tests, NULL, NULL); -+ -+ if (rv == 0 && no_cleanup == 0) { -+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE); -+ } -+ return rv; -+} --- -2.9.3 - diff --git a/SOURCES/0048-IPA-Get-ipaDomainsResolutionOrder-from-ipaConfig.patch b/SOURCES/0048-IPA-Get-ipaDomainsResolutionOrder-from-ipaConfig.patch deleted file mode 100644 index 3dcbc82..0000000 --- a/SOURCES/0048-IPA-Get-ipaDomainsResolutionOrder-from-ipaConfig.patch +++ /dev/null @@ -1,369 +0,0 @@ -From 4ff821a9a37cb43f9c34faef4b5ccbdc8dc6a7e8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 22 Mar 2017 13:40:20 +0100 -Subject: [PATCH 48/54] IPA: Get ipaDomainsResolutionOrder from ipaConfig -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -ipaDomainsResolutionOrder provides a list of domains that have to be -looked up firstly during cache_req searches. - -This commit only fetches this list from the server and stores its value -at sysdb so we can make use of it later on this patch series. - -There are no tests for newly introduced sysdb methods are those are -basically only calling sysdb_update_domain_resolution_order(), -sysdb_get_domain_resolution_order() and -sysdb_get_use_domain_resolution_order() which are have tests written -for. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/db/sysdb.h | 11 +++ - src/db/sysdb_subdomains.c | 67 +++++++++++++++ - src/providers/ipa/ipa_subdomains.c | 168 ++++++++++++++++++++++++++++++++++--- - 3 files changed, 234 insertions(+), 12 deletions(-) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 42d2857ed7765c17e7d84b0da93ed07758fbe012..75a07d4d2effb028ec654342113f8478e1eba10e 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -489,6 +489,17 @@ int sysdb_transaction_cancel(struct sysdb_ctx *sysdb); - /* functions related to subdomains */ - errno_t sysdb_domain_create(struct sysdb_ctx *sysdb, const char *domain_name); - -+errno_t sysdb_domain_get_domain_resolution_order( -+ TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, -+ const char *domain_name, -+ const char **_domain_resolution_order); -+ -+errno_t sysdb_domain_update_domain_resolution_order( -+ struct sysdb_ctx *sysdb, -+ const char *domain_name, -+ const char *domain_resolution_order); -+ - errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, - const char *name, const char *realm, - const char *flat_name, const char *domain_id, -diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c -index 916dbba153d8c08837425f6fd29a20f5a6aa9fc9..e2a4f7bb1fcdf20b6b7e04efc7f396d1c3d08f0f 100644 ---- a/src/db/sysdb_subdomains.c -+++ b/src/db/sysdb_subdomains.c -@@ -22,6 +22,7 @@ - - #include "util/util.h" - #include "db/sysdb_private.h" -+#include "db/sysdb_domain_resolution_order.h" - - static errno_t - check_subdom_config_file(struct confdb_ctx *confdb, -@@ -1210,3 +1211,69 @@ done: - talloc_free(tmp_ctx); - return ret; - } -+ -+errno_t -+sysdb_domain_get_domain_resolution_order(TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, -+ const char *domain_name, -+ const char **_domain_resolution_order) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct ldb_dn *dn; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, domain_name); -+ if (dn == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sysdb_get_domain_resolution_order(mem_ctx, sysdb, dn, -+ _domain_resolution_order); -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ -+errno_t -+sysdb_domain_update_domain_resolution_order(struct sysdb_ctx *sysdb, -+ const char *domain_name, -+ const char *domain_resolution_order) -+{ -+ -+ TALLOC_CTX *tmp_ctx; -+ struct ldb_dn *dn; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, domain_name); -+ if (dn == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sysdb_update_domain_resolution_order(sysdb, dn, -+ domain_resolution_order); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_update_domain_resolution_order() failed [%d]: [%s].\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index a07b88fe2f499353293ba90345552413c9792f4b..01a0ce812d861b24565d2f71f27d6b8ceb2965bc 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -29,6 +29,7 @@ - #include "providers/ipa/ipa_common.h" - #include "providers/ipa/ipa_id.h" - #include "providers/ipa/ipa_opts.h" -+#include "providers/ipa/ipa_config.h" - - #include - -@@ -51,6 +52,8 @@ - - #define IPA_ASSIGNED_ID_VIEW "ipaAssignedIDView" - -+#define IPA_DOMAIN_RESOLUTION_ORDER "ipaDomainResolutionOrder" -+ - /* do not refresh more often than every 5 seconds for now */ - #define IPA_SUBDOMAIN_REFRESH_LIMIT 5 - -@@ -1681,6 +1684,117 @@ static errno_t ipa_subdomains_view_name_recv(struct tevent_req *req) - return EOK; - } - -+struct ipa_domain_resolution_order_state { -+ struct sss_domain_info *domain; -+}; -+ -+static void ipa_domain_resolution_order_done(struct tevent_req *subreq); -+ -+static struct tevent_req * -+ipa_domain_resolution_order_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct ipa_subdomains_ctx *sd_ctx, -+ struct sdap_handle *sh) -+{ -+ struct ipa_domain_resolution_order_state *state; -+ struct tevent_req *subreq; -+ struct tevent_req *req; -+ const char *attrs[] = {IPA_DOMAIN_RESOLUTION_ORDER, NULL}; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, -+ struct ipa_domain_resolution_order_state); -+ if (req == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); -+ return NULL; -+ } -+ -+ state->domain = sd_ctx->be_ctx->domain; -+ -+ subreq = ipa_get_config_send(state, ev, sh, sd_ctx->sdap_id_ctx->opts, -+ state->domain->name, attrs); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediately; -+ } -+ -+ tevent_req_set_callback(subreq, ipa_domain_resolution_order_done, req); -+ -+ return req; -+ -+immediately: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ -+ return req; -+} -+ -+static void ipa_domain_resolution_order_done(struct tevent_req *subreq) -+{ -+ struct ipa_domain_resolution_order_state *state; -+ struct tevent_req *req; -+ struct sysdb_attrs *config = NULL; -+ const char *domain_resolution_order = NULL; -+ errno_t ret; -+ -+ req = tevent_req_callback_data(subreq, struct tevent_req); -+ state = tevent_req_data(req, struct ipa_domain_resolution_order_state); -+ -+ ret = ipa_get_config_recv(subreq, state, &config); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to get the domains' resolution order configuration " -+ "from the server [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ if (config != NULL) { -+ ret = sysdb_attrs_get_string(config, IPA_DOMAIN_RESOLUTION_ORDER, -+ &domain_resolution_order); -+ if (ret != EOK && ret != ENOENT) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to get the domains' resolution order configuration " -+ "value [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } else if (ret == ENOENT) { -+ domain_resolution_order = NULL; -+ } -+ } -+ -+ ret = sysdb_domain_update_domain_resolution_order( -+ state->domain->sysdb, state->domain->name, -+ domain_resolution_order); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_domain_update_resolution_order() [%d]: [%s].\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ ret = EOK; -+ -+done: -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+static errno_t ipa_domain_resolution_order_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ -+ return EOK; -+} - - struct ipa_subdomains_refresh_state { - struct tevent_context *ev; -@@ -1695,6 +1809,7 @@ static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq); -+static void ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq); - - static struct tevent_req * - ipa_subdomains_refresh_send(TALLOC_CTX *mem_ctx, -@@ -1916,7 +2031,6 @@ static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq) - { - struct ipa_subdomains_refresh_state *state; - struct tevent_req *req; -- int dp_error; - errno_t ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); -@@ -1924,24 +2038,55 @@ static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq) - - ret = ipa_subdomains_view_name_recv(subreq); - talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Unable to get view name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ subreq = ipa_domain_resolution_order_send(state, state->ev, state->sd_ctx, -+ sdap_id_op_handle(state->sdap_op)); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ -+ tevent_req_set_callback(subreq, -+ ipa_domain_refresh_resolution_order_done, -+ req); -+} -+ -+static void -+ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq) -+{ -+ struct ipa_subdomains_refresh_state *state; -+ struct tevent_req *req; -+ int dp_error; -+ errno_t ret; -+ -+ req = tevent_req_callback_data(subreq, struct tevent_req); -+ state = tevent_req_data(req, struct ipa_subdomains_refresh_state); -+ -+ ret = ipa_domain_resolution_order_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Unable to get the domains order resolution [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ - ret = sdap_id_op_done(state->sdap_op, ret, &dp_error); - if (dp_error == DP_ERR_OK && ret != EOK) { - /* retry */ - ret = ipa_subdomains_refresh_retry(req); -- if (ret != EOK) { -- goto done; -- } -- return; - } else if (dp_error == DP_ERR_OFFLINE) { - ret = ERR_OFFLINE; -- goto done; -- } else if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get view name " -- "[%d]: %s\n", ret, sss_strerror(ret)); -- goto done; - } - --done: - if (ret != EOK) { - DEBUG(SSSDBG_TRACE_FUNC, "Unable to refresh subdomains [%d]: %s\n", - ret, sss_strerror(ret)); -@@ -1949,7 +2094,6 @@ done: - return; - } - -- DEBUG(SSSDBG_TRACE_FUNC, "Subdomains refreshed.\n"); - tevent_req_done(req); - } - --- -2.9.3 - diff --git a/SOURCES/0048-TOOLS-Add-a-new-sssctl-command-access-report.patch b/SOURCES/0048-TOOLS-Add-a-new-sssctl-command-access-report.patch new file mode 100644 index 0000000..5788df9 --- /dev/null +++ b/SOURCES/0048-TOOLS-Add-a-new-sssctl-command-access-report.patch @@ -0,0 +1,504 @@ +From 73a04a5c53c0e7701aa7753fd459ffbea52e28b8 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 23 Oct 2017 18:08:12 +0200 +Subject: [PATCH 48/57] TOOLS: Add a new sssctl command access-report +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Pavel Březina +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 3ee8659bc6a77a78bc6c61b9650a36bd18ea95c8) +--- + Makefile.am | 1 + + src/tools/sssctl/sssctl.c | 1 + + src/tools/sssctl/sssctl.h | 5 + + src/tools/sssctl/sssctl_access_report.c | 435 ++++++++++++++++++++++++++++++++ + 4 files changed, 442 insertions(+) + create mode 100644 src/tools/sssctl/sssctl_access_report.c + +diff --git a/Makefile.am b/Makefile.am +index 16bcb4efc028b05c1196249245f4f3091b9366af..5917bd904054055a259eb69217282e4fb914c700 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1754,6 +1754,7 @@ sssctl_SOURCES = \ + src/tools/sssctl/sssctl_sifp.c \ + src/tools/sssctl/sssctl_config.c \ + src/tools/sssctl/sssctl_user_checks.c \ ++ src/tools/sssctl/sssctl_access_report.c \ + $(SSSD_TOOLS_OBJ) \ + $(NULL) + sssctl_LDADD = \ +diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c +index 1e061c00d2238bf34adff4183e560dc127dd62c7..eee2d613966a5dda81627d2e225bfdc9bade4041 100644 +--- a/src/tools/sssctl/sssctl.c ++++ b/src/tools/sssctl/sssctl.c +@@ -264,6 +264,7 @@ int main(int argc, const char **argv) + SSS_TOOL_COMMAND("domain-list", "List available domains", 0, sssctl_domain_list), + SSS_TOOL_COMMAND("domain-status", "Print information about domain", 0, sssctl_domain_status), + SSS_TOOL_COMMAND("user-checks", "Print information about a user and check authentication", 0, sssctl_user_checks), ++ SSS_TOOL_COMMAND("access-report", "Generate access report for a domain", 0, sssctl_access_report), + SSS_TOOL_DELIMITER("Information about cached content:"), + SSS_TOOL_COMMAND("user-show", "Information about cached user", 0, sssctl_user_show), + SSS_TOOL_COMMAND("group-show", "Information about cached group", 0, sssctl_group_show), +diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h +index 22ca5d41e2c084e64b58bc5aa066414b002e7e8b..70fc19eff07317c264978a1ecb9159ae3acdfced 100644 +--- a/src/tools/sssctl/sssctl.h ++++ b/src/tools/sssctl/sssctl.h +@@ -133,4 +133,9 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline, + errno_t sssctl_user_checks(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); ++ ++errno_t sssctl_access_report(struct sss_cmdline *cmdline, ++ struct sss_tool_ctx *tool_ctx, ++ void *pvt); ++ + #endif /* _SSSCTL_H_ */ +diff --git a/src/tools/sssctl/sssctl_access_report.c b/src/tools/sssctl/sssctl_access_report.c +new file mode 100644 +index 0000000000000000000000000000000000000000..11172329817b4dedaca480ab8a4537149853c330 +--- /dev/null ++++ b/src/tools/sssctl/sssctl_access_report.c +@@ -0,0 +1,435 @@ ++/* ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser 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 Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with this program. If not, see . ++*/ ++ ++#include ++ ++#include "util/util.h" ++#include "tools/common/sss_tools.h" ++#include "tools/sssctl/sssctl.h" ++ ++/* ++ * We're searching the cache directly.. ++ */ ++#include "providers/ipa/ipa_hbac_private.h" ++#include "providers/ipa/ipa_rules_common.h" ++ ++#ifdef HAVE_SECURITY_PAM_MISC_H ++# include ++#elif defined(HAVE_SECURITY_OPENPAM_H) ++# include ++#endif ++ ++#ifdef HAVE_SECURITY_PAM_MISC_H ++static struct pam_conv conv = { ++ misc_conv, ++ NULL ++}; ++#elif defined(HAVE_SECURITY_OPENPAM_H) ++static struct pam_conv conv = { ++ openpam_ttyconv, ++ NULL ++}; ++#else ++# error "Missing text based pam conversation function" ++#endif ++ ++#ifndef DEFAULT_SERVICE ++#define DEFAULT_SERVICE "system-auth" ++#endif /* DEFAULT_SERVICE */ ++ ++#ifndef DEFAULT_USER ++#define DEFAULT_USER "admin" ++#endif /* DEFAULT_USER */ ++ ++typedef errno_t (*sssctl_dom_access_reporter_fn)(struct sss_tool_ctx *tool_ctx, ++ const char *user, ++ const char *service, ++ struct sss_domain_info *domain); ++ ++static errno_t run_pam_acct(struct sss_tool_ctx *tool_ctx, ++ const char *user, ++ const char *service, ++ struct sss_domain_info *domain) ++{ ++ errno_t ret; ++ pam_handle_t *pamh; ++ ++ ret = pam_start(service, user, &conv, &pamh); ++ if (ret != PAM_SUCCESS) { ++ ERROR("pam_start failed: %s\n", pam_strerror(pamh, ret)); ++ return EIO; ++ } ++ ++ ret = pam_acct_mgmt(pamh, 0); ++ pam_end(pamh, ret); ++ return ret; ++} ++ ++static errno_t get_rdn_value(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *dom, ++ const char *dn_attr, ++ const char **_rdn_value) ++{ ++ errno_t ret; ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_dn *dn = NULL; ++ const struct ldb_val *rdn_val; ++ const char *rdn_str; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(dom->sysdb), dn_attr); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ rdn_val = ldb_dn_get_rdn_val(dn); ++ if (rdn_val == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "No RDN value?\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ rdn_str = talloc_strndup(tmp_ctx, ++ (const char *)rdn_val->data, ++ rdn_val->length); ++ if (rdn_str == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = EOK; ++ *_rdn_value = talloc_steal(mem_ctx, rdn_str); ++done: ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ ++static errno_t is_member_group(struct sss_domain_info *dom, ++ const char *dn_attr, ++ const char *group_rdn, ++ bool *_is_group) ++{ ++ const char *comp_name; ++ const struct ldb_val *comp_val; ++ TALLOC_CTX *tmp_ctx; ++ bool is_group = false; ++ errno_t ret; ++ struct ldb_dn *dn = NULL; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(dom->sysdb), dn_attr); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ comp_name = ldb_dn_get_component_name(dn, 1); ++ comp_val = ldb_dn_get_component_val(dn, 1); ++ if (strcasecmp("cn", comp_name) == 0 ++ && strncasecmp(group_rdn, ++ (const char *) comp_val->data, ++ comp_val->length) == 0) { ++ is_group = true; ++ } ++ ++ ret = EOK; ++done: ++ *_is_group = is_group; ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ ++static void print_category(struct sss_domain_info *domain, ++ struct ldb_message *rule_msg, ++ const char *category_attr_name, ++ const char *category_label) ++{ ++ struct ldb_message_element *category_attr; ++ ++ category_attr = ldb_msg_find_element(rule_msg, category_attr_name); ++ if (category_attr == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot find %s\n", category_attr_name); ++ return; ++ } ++ ++ if (category_attr->num_values > 0) { ++ PRINT("\t%s: ", category_label); ++ for (unsigned i = 0; i < category_attr->num_values; i++) { ++ PRINT("%s%s", ++ i > 0 ? ", " : "", ++ (const char *) category_attr->values[i].data); ++ } ++ PRINT("\n"); ++ } ++} ++ ++static void print_member_attr(struct sss_domain_info *domain, ++ struct ldb_message *rule_msg, ++ const char *member_attr_name, ++ const char *group_rdn, ++ const char *object_label, ++ const char *group_label) ++{ ++ errno_t ret; ++ TALLOC_CTX *tmp_ctx = NULL; ++ const char **member_names = NULL; ++ size_t name_count = 0; ++ const char **member_group_names = NULL; ++ size_t group_count = 0; ++ struct ldb_message_element *member_attr = NULL; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return; ++ } ++ ++ member_attr = ldb_msg_find_element(rule_msg, member_attr_name); ++ if (member_attr == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot find %s\n", member_attr_name); ++ goto done; ++ } ++ ++ member_names = talloc_zero_array(tmp_ctx, ++ const char *, ++ member_attr->num_values + 1); ++ member_group_names = talloc_zero_array(tmp_ctx, ++ const char *, ++ member_attr->num_values + 1); ++ if (member_names == NULL || member_group_names == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "OOM?\n"); ++ goto done; ++ } ++ ++ for (size_t i = 0; i < member_attr->num_values; i++) { ++ bool is_group; ++ const char *rdn_string; ++ const char *dn_attr; ++ ++ dn_attr = (const char *) member_attr->values[i].data; ++ ++ ret = is_member_group(domain, dn_attr, group_rdn, &is_group); ++ if (ret != EOK) { ++ continue; ++ } ++ ++ ret = get_rdn_value(tmp_ctx, domain, dn_attr, &rdn_string); ++ if (ret != EOK) { ++ continue; ++ } ++ ++ if (is_group == false) { ++ member_names[name_count] = talloc_steal(member_names, ++ rdn_string); ++ if (member_names[name_count] == NULL) { ++ goto done; ++ } ++ name_count++; ++ } else { ++ member_group_names[group_count] = talloc_strdup(member_group_names, ++ rdn_string); ++ if (member_group_names[group_count] == NULL) { ++ goto done; ++ } ++ group_count++; ++ } ++ } ++ ++ if (member_names[0] != NULL) { ++ PRINT("\t%s: ", object_label); ++ for (int i = 0; member_names[i]; i++) { ++ PRINT("%s%s", i > 0 ? ", " : "", member_names[i]); ++ } ++ PRINT("\n"); ++ } ++ ++ if (member_group_names[0] != NULL) { ++ PRINT("\t%s: ", group_label); ++ for (int i = 0; member_group_names[i]; i++) { ++ PRINT("%s%s", i > 0 ? ", " : "", member_group_names[i]); ++ } ++ PRINT("\n"); ++ } ++ ++done: ++ talloc_free(tmp_ctx); ++} ++ ++static void print_ipa_hbac_rule(struct sss_domain_info *domain, ++ struct ldb_message *rule_msg) ++{ ++ struct ldb_message_element *el; ++ ++ el = ldb_msg_find_element(rule_msg, IPA_CN); ++ if (el == NULL || el->num_values < 1) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "A rule with no name\n"); ++ return; ++ } ++ ++ PRINT("Rule name: %1$s\n", el->values[0].data); ++ ++ print_member_attr(domain, ++ rule_msg, ++ IPA_MEMBER_USER, ++ "groups", ++ _("Member users"), ++ _("Member groups")); ++ print_category(domain, ++ rule_msg, ++ IPA_USER_CATEGORY, ++ _("User category")); ++ ++ print_member_attr(domain, ++ rule_msg, ++ IPA_MEMBER_SERVICE, ++ "hbacservicegroups", ++ _("Member services"), ++ _("Member service groups")); ++ print_category(domain, ++ rule_msg, ++ IPA_SERVICE_CATEGORY, ++ _("Service category")); ++ ++ PRINT("\n"); ++} ++ ++static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx, ++ const char *user, ++ const char *service, ++ struct sss_domain_info *domain) ++{ ++ TALLOC_CTX *tmp_ctx = NULL; ++ const char *filter = NULL; ++ errno_t ret; ++ const char *attrs[] = { ++ OBJECTCLASS, ++ IPA_CN, ++ IPA_MEMBER_USER, ++ IPA_USER_CATEGORY, ++ IPA_MEMBER_SERVICE, ++ IPA_SERVICE_CATEGORY, ++ IPA_MEMBER_HOST, ++ IPA_HOST_CATEGORY, ++ NULL, ++ }; ++ size_t rule_count; ++ struct ldb_message **msgs = NULL; ++ ++ /* Run the pam account phase to make sure the rules are fetched by SSSD */ ++ ret = run_pam_acct(tool_ctx, user, service, domain); ++ if (ret != PAM_SUCCESS && ret != PAM_PERM_DENIED) { ++ ERROR("Cannot run the PAM account phase, reporting stale rules\n"); ++ /* Non-fatal */ ++ } ++ ++ tmp_ctx = talloc_new(tool_ctx); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ filter = talloc_asprintf(tmp_ctx, "(objectClass=%s)", IPA_HBAC_RULE); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_search_custom(tmp_ctx, domain, filter, ++ HBAC_RULES_SUBDIR, attrs, ++ &rule_count, &msgs); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up HBAC rules\n"); ++ goto done; ++ } ++ ++ if (ret == ENOENT) { ++ PRINT("No cached rules. All users will be denied access\n"); ++ ret = EOK; ++ goto done; ++ } ++ ++ PRINT("%1$zu rules cached\n\n", rule_count); ++ ++ for (size_t i = 0; i < rule_count; i++) { ++ print_ipa_hbac_rule(domain, msgs[i]); ++ } ++ ++ ret = EOK; ++done: ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ ++sssctl_dom_access_reporter_fn get_report_fn(const char *provider) ++{ ++ if (strcmp(provider, "ipa") == 0) { ++ return sssctl_ipa_access_report; ++ } ++ ++ return NULL; ++} ++ ++errno_t sssctl_access_report(struct sss_cmdline *cmdline, ++ struct sss_tool_ctx *tool_ctx, ++ void *pvt) ++{ ++ errno_t ret; ++ const char *domname = NULL; ++ sssctl_dom_access_reporter_fn reporter; ++ struct sss_domain_info *dom; ++ const char *user = DEFAULT_USER; ++ const char *service = DEFAULT_SERVICE; ++ ++ /* Parse command line. */ ++ struct poptOption options[] = { ++ { "user", 'u', POPT_ARG_STRING, &user, 0, ++ _("PAM user, default: " DEFAULT_USER), NULL }, ++ { "service", 's', POPT_ARG_STRING, &service, 0, ++ _("PAM service, default: " DEFAULT_SERVICE), NULL }, ++ POPT_TABLEEND ++ }; ++ ++ ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL, ++ NULL, NULL, "DOMAIN", _("Specify domain name."), ++ &domname, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); ++ return ret; ++ } ++ ++ dom = find_domain_by_name(tool_ctx->domains, domname, true); ++ if (dom == NULL) { ++ ERROR("Cannot find domain %1$s\n", domname); ++ return ERR_DOMAIN_NOT_FOUND; ++ } ++ ++ reporter = get_report_fn(dom->provider); ++ if (reporter == NULL) { ++ ERROR("Access report not implemented for domains of type %1$s\n", ++ dom->provider); ++ return ret; ++ } ++ ++ return reporter(tool_ctx, user, service, dom); ++} +-- +2.14.3 + diff --git a/SOURCES/0049-IPA_SUBDOMAINS-Rename-_refresh_view-to-_refresh_view.patch b/SOURCES/0049-IPA_SUBDOMAINS-Rename-_refresh_view-to-_refresh_view.patch deleted file mode 100644 index 71624c8..0000000 --- a/SOURCES/0049-IPA_SUBDOMAINS-Rename-_refresh_view-to-_refresh_view.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 33190863b66f90cac410b7a9b9cc95e4f9891013 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Fri, 24 Mar 2017 08:08:58 +0100 -Subject: [PATCH 49/54] IPA_SUBDOMAINS: Rename _refresh_view() to - _refresh_view_name() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This method got renamed in order to match better with what it does -currently. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/providers/ipa/ipa_subdomains.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index 01a0ce812d861b24565d2f71f27d6b8ceb2965bc..bf6f6ab1fa8bfff7ea102dd219c9ddbbab065b2b 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -1808,7 +1808,7 @@ static void ipa_subdomains_refresh_ranges_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq); --static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq); -+static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq); - static void ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq); - - static struct tevent_req * -@@ -2023,11 +2023,12 @@ static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq) - return; - } - -- tevent_req_set_callback(subreq, ipa_subdomains_refresh_view_done, req); -+ tevent_req_set_callback(subreq, ipa_subdomains_refresh_view_name_done, -+ req); - return; - } - --static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq) -+static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq) - { - struct ipa_subdomains_refresh_state *state; - struct tevent_req *req; --- -2.9.3 - diff --git a/SOURCES/0049-dp-use-void-to-express-empty-output-argument-list.patch b/SOURCES/0049-dp-use-void-to-express-empty-output-argument-list.patch new file mode 100644 index 0000000..8d23c72 --- /dev/null +++ b/SOURCES/0049-dp-use-void-to-express-empty-output-argument-list.patch @@ -0,0 +1,50 @@ +From ae4435d84bae06c592d7bed16ce7aa2b07823be9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 2 Nov 2017 14:58:05 +0100 +Subject: [PATCH 49/57] dp: use void * to express empty output argument list +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since we cannot use plain void type is function definition. + +Related: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 6211a202301e6f61d46cdb2bf0be332a70c7fdea) +--- + src/providers/data_provider/dp_private.h | 2 +- + src/providers/data_provider/dp_request_reply.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/providers/data_provider/dp_private.h b/src/providers/data_provider/dp_private.h +index 2e71a373fdc8886fccb23bfb8283dc5bc341b1b0..028070f7f1866854c145a148e44c2cb108d2fc58 100644 +--- a/src/providers/data_provider/dp_private.h ++++ b/src/providers/data_provider/dp_private.h +@@ -136,7 +136,7 @@ typedef void (*dp_req_reply_fn)(const char *req_name, + + void dp_req_reply_default(const char *req_name, + struct sbus_request *sbus_req, +- void *data); ++ void **data); + + /* Data provider request table. */ + +diff --git a/src/providers/data_provider/dp_request_reply.c b/src/providers/data_provider/dp_request_reply.c +index 27d9654bad76a099b004846463f035bf2e6d1243..34440fda7f28f0026d63af1af9958dcea3c6aaec 100644 +--- a/src/providers/data_provider/dp_request_reply.c ++++ b/src/providers/data_provider/dp_request_reply.c +@@ -31,7 +31,7 @@ + + void dp_req_reply_default(const char *req_name, + struct sbus_request *sbus_req, +- void *data) ++ void **data) + { + DP_REQ_DEBUG(SSSDBG_TRACE_FUNC, req_name, "Replying with empty message"); + +-- +2.14.3 + diff --git a/SOURCES/0050-IPA-Get-ipaDomainsResolutionOrder-from-IPA-ID-View.patch b/SOURCES/0050-IPA-Get-ipaDomainsResolutionOrder-from-IPA-ID-View.patch deleted file mode 100644 index a1da431..0000000 --- a/SOURCES/0050-IPA-Get-ipaDomainsResolutionOrder-from-IPA-ID-View.patch +++ /dev/null @@ -1,347 +0,0 @@ -From d36c2acde1f29865c2cefedebc214ba48bb227e7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Fri, 24 Mar 2017 17:46:04 +0100 -Subject: [PATCH 50/54] IPA: Get ipaDomainsResolutionOrder from IPA ID View -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -ipaDomainsResolutionOrder provides a list of domains that have to be -looked up firstly during cache_req searches. - -This commit only fetches this list from the server and stores its value -at sysdb so we can make use of it later on this patch series. - -There are no tests for newly introduced sysdb methods are those are -basically only calling sysdb_update_domain_resolution_order(), -sysdb_get_domain_resolution_order() and -sysdb_get_use_domain_resolution_order() which are have tests written -for. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/db/sysdb.h | 9 ++ - src/db/sysdb_views.c | 66 ++++++++++++++ - src/providers/ipa/ipa_subdomains.c | 182 +++++++++++++++++++++++++++++++++++++ - 3 files changed, 257 insertions(+) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 75a07d4d2effb028ec654342113f8478e1eba10e..62c561be9452a284a8ddf8ebb45720265852c8b0 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -533,6 +533,15 @@ errno_t sysdb_update_view_name(struct sysdb_ctx *sysdb, const char *view_name); - errno_t sysdb_get_view_name(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, - char **view_name); - -+errno_t sysdb_update_view_domain_resolution_order( -+ struct sysdb_ctx *sysdb, -+ const char *domain_resolution_order); -+ -+errno_t sysdb_get_view_domain_resolution_order( -+ TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, -+ const char **_domain_resolution_order); -+ - static inline bool is_default_view(const char *view_name) - { - /* NULL is treated as default */ -diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c -index 1c416dd14049237e9f35d52f154035e3ff861469..20db9b06183d68b33bb19f498513d7f5cf84b1cf 100644 ---- a/src/db/sysdb_views.c -+++ b/src/db/sysdb_views.c -@@ -22,6 +22,9 @@ - #include "util/util.h" - #include "util/cert.h" - #include "db/sysdb_private.h" -+#include "db/sysdb_domain_resolution_order.h" -+ -+#define SYSDB_VIEWS_BASE "cn=views,cn=sysdb" - - /* In general is should not be possible that there is a view container without - * a view name set. But to be on the safe side we return both information -@@ -179,6 +182,69 @@ done: - return ret; - } - -+errno_t -+sysdb_get_view_domain_resolution_order(TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, -+ const char **_domain_resolution_order) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct ldb_dn *dn; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_VIEWS_BASE); -+ if (dn == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sysdb_get_domain_resolution_order(mem_ctx, sysdb, dn, -+ _domain_resolution_order); -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ -+errno_t -+sysdb_update_view_domain_resolution_order(struct sysdb_ctx *sysdb, -+ const char *domain_resolution_order) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct ldb_dn *dn; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_VIEWS_BASE); -+ if (dn == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sysdb_update_domain_resolution_order(sysdb, dn, -+ domain_resolution_order); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_update_domain_resolution_order() failed [%d]: [%s].\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ - errno_t sysdb_delete_view_tree(struct sysdb_ctx *sysdb, const char *view_name) - { - struct ldb_dn *dn; -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index bf6f6ab1fa8bfff7ea102dd219c9ddbbab065b2b..ef348adf4a36e870f44387bd700f5c2beea3bfd6 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -1684,6 +1684,151 @@ static errno_t ipa_subdomains_view_name_recv(struct tevent_req *req) - return EOK; - } - -+struct ipa_subdomains_view_domain_resolution_order_state { -+ struct sss_domain_info *domain; -+ const char *view_name; -+}; -+ -+static void -+ipa_subdomains_view_domain_resolution_order_done(struct tevent_req *subreq); -+ -+static struct tevent_req * -+ipa_subdomains_view_domain_resolution_order_send( -+ TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct ipa_subdomains_ctx *sd_ctx, -+ struct sdap_handle *sh) -+{ -+ struct ipa_subdomains_view_domain_resolution_order_state *state; -+ struct tevent_req *subreq; -+ struct tevent_req *req; -+ const char *attrs[] = { IPA_DOMAIN_RESOLUTION_ORDER, NULL }; -+ char *ldap_basedn; -+ char *base; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, -+ struct ipa_subdomains_view_domain_resolution_order_state); -+ if (req == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); -+ return NULL; -+ } -+ -+ state->domain = sd_ctx->be_ctx->domain; -+ state->view_name = sd_ctx->ipa_id_ctx->view_name; -+ -+ ret = domain_to_basedn(state, sd_ctx->be_ctx->domain->name, &ldap_basedn); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n"); -+ goto immediately; -+ } -+ -+ base = talloc_asprintf(state, "cn=%s,cn=views,cn=accounts,%s", -+ sd_ctx->ipa_id_ctx->view_name, ldap_basedn); -+ if (base == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -+ ret = ENOMEM; -+ goto immediately; -+ } -+ -+ subreq = sdap_get_generic_send( -+ state, ev, sd_ctx->sdap_id_ctx->opts, sh, -+ base, LDAP_SCOPE_BASE, NULL, attrs, NULL, 0, -+ dp_opt_get_int(sd_ctx->sdap_id_ctx->opts->basic, -+ SDAP_ENUM_SEARCH_TIMEOUT), -+ false); -+ if (subreq == NULL) { -+ ret = ENOMEM; -+ goto immediately; -+ } -+ -+ tevent_req_set_callback(subreq, ipa_subdomains_view_domain_resolution_order_done, -+ req); -+ -+ return req; -+ -+immediately: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ -+ return req; -+} -+ -+static void -+ipa_subdomains_view_domain_resolution_order_done(struct tevent_req *subreq) -+{ -+ struct ipa_subdomains_view_domain_resolution_order_state *state; -+ struct tevent_req *req; -+ size_t reply_count; -+ struct sysdb_attrs **reply; -+ const char *domain_resolution_order; -+ errno_t ret; -+ -+ req = tevent_req_callback_data(subreq, struct tevent_req); -+ state = tevent_req_data(req, -+ struct ipa_subdomains_view_domain_resolution_order_state); -+ -+ ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "Unable to get view name [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ if (reply_count > 1) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "More than one object returned.\n"); -+ ret = EINVAL; -+ goto done; -+ } else if (reply_count == 0) { -+ domain_resolution_order = NULL; -+ } else { -+ /* reply_count == 1 */ -+ ret = sysdb_attrs_get_string(reply[0], IPA_DOMAIN_RESOLUTION_ORDER, -+ &domain_resolution_order); -+ if (ret != EOK && ret != ENOENT) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to get the view domains' resolution order " -+ "configuration value for view [%s] [%d]: %s\n", -+ state->view_name, ret, sss_strerror(ret)); -+ goto done; -+ } else if (ret == ENOENT) { -+ domain_resolution_order = NULL; -+ } -+ } -+ -+ ret = sysdb_update_view_domain_resolution_order(state->domain->sysdb, -+ domain_resolution_order); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_update_view_domain_resolution_order() [%d]: [%s].\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ ret = EOK; -+ -+done: -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+} -+ -+static errno_t -+ipa_subdomains_view_domain_resolution_order_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ -+ return EOK; -+} -+ - struct ipa_domain_resolution_order_state { - struct sss_domain_info *domain; - }; -@@ -1809,6 +1954,8 @@ static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq); - static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq); -+static void ipa_subdomains_refresh_view_domain_resolution_order_done( -+ struct tevent_req *subreq); - static void ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq); - - static struct tevent_req * -@@ -2047,6 +2194,41 @@ static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq) - return; - } - -+ subreq = ipa_subdomains_view_domain_resolution_order_send( -+ state, -+ state->ev, -+ state->sd_ctx, -+ sdap_id_op_handle(state->sdap_op)); -+ if (subreq == NULL) { -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ -+ tevent_req_set_callback(subreq, -+ ipa_subdomains_refresh_view_domain_resolution_order_done, -+ req); -+} -+ -+static void -+ipa_subdomains_refresh_view_domain_resolution_order_done(struct tevent_req *subreq) -+{ -+ struct ipa_subdomains_refresh_state *state; -+ struct tevent_req *req; -+ errno_t ret; -+ -+ req = tevent_req_callback_data(subreq, struct tevent_req); -+ state = tevent_req_data(req, struct ipa_subdomains_refresh_state); -+ -+ ret = ipa_subdomains_view_domain_resolution_order_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Unable to get view domain_resolution order [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ tevent_req_error(req, ret); -+ return; -+ } -+ - subreq = ipa_domain_resolution_order_send(state, state->ev, state->sd_ctx, - sdap_id_op_handle(state->sdap_op)); - if (subreq == NULL) { --- -2.9.3 - diff --git a/SOURCES/0050-dp-add-method-to-refresh-access-control-rules.patch b/SOURCES/0050-dp-add-method-to-refresh-access-control-rules.patch new file mode 100644 index 0000000..cb7b567 --- /dev/null +++ b/SOURCES/0050-dp-add-method-to-refresh-access-control-rules.patch @@ -0,0 +1,192 @@ +From 7de7fd7a9378461ce57f9b5174938af9440381ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 2 Nov 2017 14:58:38 +0100 +Subject: [PATCH 50/57] dp: add method to refresh access control rules +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit e737cdfa225e0d455c0e574bcb82c2cc16a17d9d) +--- + src/providers/data_provider/dp.h | 2 ++ + src/providers/data_provider/dp_iface.c | 6 ++++++ + src/providers/data_provider/dp_iface.h | 4 ++++ + src/providers/data_provider/dp_iface.xml | 6 ++++++ + src/providers/data_provider/dp_iface_generated.c | 27 ++++++++++++++++++++++++ + src/providers/data_provider/dp_iface_generated.h | 16 ++++++++++++++ + src/providers/data_provider/dp_target_auth.c | 14 ++++++++++++ + 7 files changed, 75 insertions(+) + +diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h +index 9cdbe5b3a56ba159f9a10df6e010e616e4aefcac..aa5b781158c54545b26034602bb25db46b189e87 100644 +--- a/src/providers/data_provider/dp.h ++++ b/src/providers/data_provider/dp.h +@@ -83,6 +83,8 @@ enum dp_methods { + DPM_DOMAINS_HANDLER, + DPM_SESSION_HANDLER, + ++ DPM_REFRESH_ACCESS_RULES, ++ + DP_METHOD_SENTINEL + }; + +diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c +index 4b2b0ddca68be8899f7285b4d881a91444b99362..28d70e686f63a3572ac595f493aa1d59436c563f 100644 +--- a/src/providers/data_provider/dp_iface.c ++++ b/src/providers/data_provider/dp_iface.c +@@ -48,10 +48,16 @@ struct iface_dp_failover iface_dp_failover = { + .ListServers = dp_failover_list_servers + }; + ++struct iface_dp_access_control iface_dp_access_control = { ++ { &iface_dp_access_control_meta, 0 }, ++ .RefreshRules = dp_access_control_refresh_rules_handler ++}; ++ + static struct sbus_iface_map dp_map[] = { + { DP_PATH, &iface_dp.vtable }, + { DP_PATH, &iface_dp_backend.vtable }, + { DP_PATH, &iface_dp_failover.vtable }, ++ { DP_PATH, &iface_dp_access_control.vtable }, + { NULL, NULL } + }; + +diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h +index 8ae7a2ad7a61f82b000493f3309926cd932211f6..759b9e6c9eb7f53836ae0b641b34e6c31e65779f 100644 +--- a/src/providers/data_provider/dp_iface.h ++++ b/src/providers/data_provider/dp_iface.h +@@ -76,4 +76,8 @@ errno_t dp_failover_list_servers(struct sbus_request *sbus_req, + void *dp_cli, + const char *service_name); + ++/* org.freedesktop.sssd.DataProvider.AccessControl */ ++errno_t dp_access_control_refresh_rules_handler(struct sbus_request *sbus_req, ++ void *dp_cli); ++ + #endif /* DP_IFACE_H_ */ +diff --git a/src/providers/data_provider/dp_iface.xml b/src/providers/data_provider/dp_iface.xml +index a3969873ad1660c71ebdcae7a951757f5254c865..2bfa9dfa7e9d02d2d12c3358967f6969438a97a2 100644 +--- a/src/providers/data_provider/dp_iface.xml ++++ b/src/providers/data_provider/dp_iface.xml +@@ -32,6 +32,12 @@ + + + ++ ++ ++ ++ ++ ++ + + + +diff --git a/src/providers/data_provider/dp_iface_generated.c b/src/providers/data_provider/dp_iface_generated.c +index e2e0216bd98c498b2b34c524ba615b70564420a2..11ee2e24a69cc8d4d19fdbeed613e76081aef15d 100644 +--- a/src/providers/data_provider/dp_iface_generated.c ++++ b/src/providers/data_provider/dp_iface_generated.c +@@ -187,6 +187,33 @@ const struct sbus_interface_meta iface_dp_failover_meta = { + sbus_invoke_get_all, /* GetAll invoker */ + }; + ++int iface_dp_access_control_RefreshRules_finish(struct sbus_request *req) ++{ ++ return sbus_request_return_and_finish(req, ++ DBUS_TYPE_INVALID); ++} ++ ++/* methods for org.freedesktop.sssd.DataProvider.AccessControl */ ++const struct sbus_method_meta iface_dp_access_control__methods[] = { ++ { ++ "RefreshRules", /* name */ ++ NULL, /* no in_args */ ++ NULL, /* no out_args */ ++ offsetof(struct iface_dp_access_control, RefreshRules), ++ NULL, /* no invoker */ ++ }, ++ { NULL, } ++}; ++ ++/* interface info for org.freedesktop.sssd.DataProvider.AccessControl */ ++const struct sbus_interface_meta iface_dp_access_control_meta = { ++ "org.freedesktop.sssd.DataProvider.AccessControl", /* name */ ++ iface_dp_access_control__methods, ++ NULL, /* no signals */ ++ NULL, /* no properties */ ++ sbus_invoke_get_all, /* GetAll invoker */ ++}; ++ + /* arguments for org.freedesktop.sssd.dataprovider.autofsHandler */ + const struct sbus_arg_meta iface_dp_autofsHandler__in[] = { + { "dp_flags", "u" }, +diff --git a/src/providers/data_provider/dp_iface_generated.h b/src/providers/data_provider/dp_iface_generated.h +index b7f63fb438d7b3024a0f66de0a5d15cc3d426f44..541a90b0b5a5bc0a346cbd04974d33c8bb0983c5 100644 +--- a/src/providers/data_provider/dp_iface_generated.h ++++ b/src/providers/data_provider/dp_iface_generated.h +@@ -26,6 +26,10 @@ + #define IFACE_DP_FAILOVER_ACTIVESERVER "ActiveServer" + #define IFACE_DP_FAILOVER_LISTSERVERS "ListServers" + ++/* constants for org.freedesktop.sssd.DataProvider.AccessControl */ ++#define IFACE_DP_ACCESS_CONTROL "org.freedesktop.sssd.DataProvider.AccessControl" ++#define IFACE_DP_ACCESS_CONTROL_REFRESHRULES "RefreshRules" ++ + /* constants for org.freedesktop.sssd.dataprovider */ + #define IFACE_DP "org.freedesktop.sssd.dataprovider" + #define IFACE_DP_PAMHANDLER "pamHandler" +@@ -88,6 +92,15 @@ int iface_dp_failover_ActiveServer_finish(struct sbus_request *req, const char * + /* finish function for ListServers */ + int iface_dp_failover_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers); + ++/* vtable for org.freedesktop.sssd.DataProvider.AccessControl */ ++struct iface_dp_access_control { ++ struct sbus_vtable vtable; /* derive from sbus_vtable */ ++ int (*RefreshRules)(struct sbus_request *req, void *data); ++}; ++ ++/* finish function for RefreshRules */ ++int iface_dp_access_control_RefreshRules_finish(struct sbus_request *req); ++ + /* vtable for org.freedesktop.sssd.dataprovider */ + struct iface_dp { + struct sbus_vtable vtable; /* derive from sbus_vtable */ +@@ -130,6 +143,9 @@ extern const struct sbus_interface_meta iface_dp_backend_meta; + /* interface info for org.freedesktop.sssd.DataProvider.Failover */ + extern const struct sbus_interface_meta iface_dp_failover_meta; + ++/* interface info for org.freedesktop.sssd.DataProvider.AccessControl */ ++extern const struct sbus_interface_meta iface_dp_access_control_meta; ++ + /* interface info for org.freedesktop.sssd.dataprovider */ + extern const struct sbus_interface_meta iface_dp_meta; + +diff --git a/src/providers/data_provider/dp_target_auth.c b/src/providers/data_provider/dp_target_auth.c +index 6bb3313b2de002466e5ca84464c962acd2412bfa..4b47975569a04a4d79aef4c16fcacf92c295de25 100644 +--- a/src/providers/data_provider/dp_target_auth.c ++++ b/src/providers/data_provider/dp_target_auth.c +@@ -306,3 +306,17 @@ void dp_pam_handler_selinux_done(struct tevent_req *req) + dp_pam_reply(state->sbus_req, state->request_name, pd); + return; + } ++ ++errno_t dp_access_control_refresh_rules_handler(struct sbus_request *sbus_req, ++ void *dp_cli) ++{ ++ const char *key; ++ ++ key = "RefreshRules"; ++ ++ dp_req_with_reply(dp_cli, NULL, "Refresh Access Control Rules", key, ++ sbus_req, DPT_ACCESS, DPM_REFRESH_ACCESS_RULES, 0, NULL, ++ dp_req_reply_default, void *); ++ ++ return EOK; ++} +-- +2.14.3 + diff --git a/SOURCES/0051-DLINKLIST-Add-DLIST_FOR_EACH_SAFE-macro.patch b/SOURCES/0051-DLINKLIST-Add-DLIST_FOR_EACH_SAFE-macro.patch deleted file mode 100644 index b75b73d..0000000 --- a/SOURCES/0051-DLINKLIST-Add-DLIST_FOR_EACH_SAFE-macro.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 8c7c97d1b3af8c99af43dcaff7ae1d9315a03835 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Tue, 21 Mar 2017 20:56:38 +0100 -Subject: [PATCH 51/54] DLINKLIST: Add DLIST_FOR_EACH_SAFE macro -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This macro, as DLIST_FOR_EACH, iterates over the whole list. The main -difference between both is that in the _SAFE version the pointer to the -next list node is stored, allowing us to delete the current node safely. - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/util/dlinklist.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/src/util/dlinklist.h b/src/util/dlinklist.h -index 4f6aef830e914c22654970081263d43461c1750f..017c60468e66dbec15724d5f4832da412f42136b 100644 ---- a/src/util/dlinklist.h -+++ b/src/util/dlinklist.h -@@ -147,4 +147,9 @@ do { \ - #define DLIST_FOR_EACH(p, list) \ - for ((p) = (list); (p) != NULL; (p) = (p)->next) - -+#define DLIST_FOR_EACH_SAFE(p, q, list) \ -+ for ((p) = (list), (q) = (p) != NULL ? (p)->next : NULL; \ -+ (p) != NULL; \ -+ (p) = (q), (q) = (p) != NULL ? (p)->next : NULL) -+ - #endif /* _DLINKLIST_H */ --- -2.9.3 - diff --git a/SOURCES/0051-ipa-implement-method-to-refresh-HBAC-rules.patch b/SOURCES/0051-ipa-implement-method-to-refresh-HBAC-rules.patch new file mode 100644 index 0000000..5ccb7fd --- /dev/null +++ b/SOURCES/0051-ipa-implement-method-to-refresh-HBAC-rules.patch @@ -0,0 +1,140 @@ +From 42f16ffa434de2efcdb9010df39dfe7cc619dfb0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 2 Nov 2017 14:59:19 +0100 +Subject: [PATCH 51/57] ipa: implement method to refresh HBAC rules +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit 2754a8dcfa937d45b024a2e57419248bfd4c4919) +--- + src/providers/ipa/ipa_access.c | 68 ++++++++++++++++++++++++++++++++++++++++-- + src/providers/ipa/ipa_access.h | 10 +++++++ + src/providers/ipa/ipa_init.c | 4 +++ + 3 files changed, 80 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c +index 32ccf541c9436b633e7724b2c44ee545810a7fb8..de9f68170b6e9c38fd8b6d23f1d565250bbf78d2 100644 +--- a/src/providers/ipa/ipa_access.c ++++ b/src/providers/ipa/ipa_access.c +@@ -682,8 +682,8 @@ done: + + errno_t + ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx, +- struct tevent_req *req, +- struct pam_data **_data) ++ struct tevent_req *req, ++ struct pam_data **_data) + { + struct ipa_pam_access_handler_state *state = NULL; + +@@ -695,3 +695,67 @@ ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx, + + return EOK; + } ++ ++struct ipa_refresh_access_rules_state { ++ int dummy; ++}; ++ ++static void ipa_refresh_access_rules_done(struct tevent_req *subreq); ++ ++struct tevent_req * ++ipa_refresh_access_rules_send(TALLOC_CTX *mem_ctx, ++ struct ipa_access_ctx *access_ctx, ++ void *no_input_data, ++ struct dp_req_params *params) ++{ ++ struct ipa_refresh_access_rules_state *state; ++ struct tevent_req *subreq; ++ struct tevent_req *req; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Refreshing HBAC rules\n"); ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ipa_refresh_access_rules_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ return NULL; ++ } ++ ++ subreq = ipa_fetch_hbac_send(state, params->ev, params->be_ctx, access_ctx); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ tevent_req_post(req, params->ev); ++ return req; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_refresh_access_rules_done, req); ++ ++ return req; ++} ++ ++static void ipa_refresh_access_rules_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ ++ ret = ipa_fetch_hbac_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++ return; ++} ++ ++errno_t ipa_refresh_access_rules_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ void **_no_output_data) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} +diff --git a/src/providers/ipa/ipa_access.h b/src/providers/ipa/ipa_access.h +index de690350218bd47165a2b48c10059b8de96b718a..9cec0d1063fd39380a77093526e3240523752075 100644 +--- a/src/providers/ipa/ipa_access.h ++++ b/src/providers/ipa/ipa_access.h +@@ -63,4 +63,14 @@ ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct pam_data **_data); + ++struct tevent_req * ++ipa_refresh_access_rules_send(TALLOC_CTX *mem_ctx, ++ struct ipa_access_ctx *access_ctx, ++ void *no_input_data, ++ struct dp_req_params *params); ++ ++errno_t ipa_refresh_access_rules_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ void **_no_output_data); ++ + #endif /* _IPA_ACCESS_H_ */ +diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c +index 5b7c8e1348f561901782c872078a0e7391d4ff75..f335d51fd65959d256c54a5d92c594a24e895b7c 100644 +--- a/src/providers/ipa/ipa_init.c ++++ b/src/providers/ipa/ipa_init.c +@@ -831,6 +831,10 @@ errno_t sssm_ipa_access_init(TALLOC_CTX *mem_ctx, + ipa_pam_access_handler_send, ipa_pam_access_handler_recv, access_ctx, + struct ipa_access_ctx, struct pam_data, struct pam_data *); + ++ dp_set_method(dp_methods, DPM_REFRESH_ACCESS_RULES, ++ ipa_refresh_access_rules_send, ipa_refresh_access_rules_recv, access_ctx, ++ struct ipa_access_ctx, void, void *); ++ + ret = EOK; + + done: +-- +2.14.3 + diff --git a/SOURCES/0052-CACHE_REQ-Make-use-of-domainResolutionOrder.patch b/SOURCES/0052-CACHE_REQ-Make-use-of-domainResolutionOrder.patch deleted file mode 100644 index 4086ace..0000000 --- a/SOURCES/0052-CACHE_REQ-Make-use-of-domainResolutionOrder.patch +++ /dev/null @@ -1,795 +0,0 @@ -From 5091507c13dfdbde29aa75d6e90eda9ddaa89cff Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Sun, 26 Mar 2017 00:27:50 +0100 -Subject: [PATCH 52/54] CACHE_REQ: Make use of domainResolutionOrder -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -domainResolutionOrder has been introduced in the previous commits and -allows the admin to set up a specific order which the domains will be -resolved during a lookup and with this patch we can take advantage of -this. - -In order to have it working a new structure has been added -(struct domain_resolution_order) to the responder context and will be -used by the cache_req to perform the lookups based on this list. - -As the ipaDomainResolutionOrder may be set globally on IPA or per View, -SSSD does respect the following precedence order: View > Globally. - -The way the list is built is quite simple, basically having the domains -present on ipaDomainResolutionOrder as the first domains (in that -specific order) and then appending the remaining domains to this list. -The final result is a completely flat list with all the domains -respecting the specified order (it's important to remember that the -domains not specified won't follow any specific order, they're just -"random" based on the domains list present in the responder context. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - Makefile.am | 3 + - src/responder/common/cache_req/cache_req.c | 89 +++++++----- - src/responder/common/cache_req/cache_req_domain.c | 166 ++++++++++++++++++++++ - src/responder/common/cache_req/cache_req_domain.h | 46 ++++++ - src/responder/common/responder.h | 5 + - src/responder/common/responder_common.c | 153 ++++++++++++++++++++ - src/responder/common/responder_get_domains.c | 14 ++ - src/tests/cmocka/common_mock_resp.c | 6 + - src/tests/cmocka/common_mock_resp_dp.c | 7 + - src/tests/cmocka/test_nss_srv.c | 4 + - src/tests/cwrap/Makefile.am | 1 + - 11 files changed, 457 insertions(+), 37 deletions(-) - create mode 100644 src/responder/common/cache_req/cache_req_domain.c - create mode 100644 src/responder/common/cache_req/cache_req_domain.h - -diff --git a/Makefile.am b/Makefile.am -index 450785bf4c482cce1e1440f1336879150537888e..573b37c52fdeab1add4ea057e1e1844ea4d348a5 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -528,6 +528,7 @@ SSSD_CACHE_REQ_OBJ = \ - src/responder/common/cache_req/cache_req_result.c \ - src/responder/common/cache_req/cache_req_search.c \ - src/responder/common/cache_req/cache_req_data.c \ -+ src/responder/common/cache_req/cache_req_domain.c \ - src/responder/common/cache_req/plugins/cache_req_common.c \ - src/responder/common/cache_req/plugins/cache_req_enum_users.c \ - src/responder/common/cache_req/plugins/cache_req_enum_groups.c \ -@@ -689,6 +690,7 @@ dist_noinst_HEADERS = \ - src/responder/common/iface/responder_iface.h \ - src/responder/common/iface/responder_iface_generated.h \ - src/responder/common/cache_req/cache_req.h \ -+ src/responder/common/cache_req/cache_req_domain.h \ - src/responder/common/cache_req/cache_req_plugin.h \ - src/responder/common/cache_req/cache_req_private.h \ - src/responder/common/data_provider/rdp.h \ -@@ -2199,6 +2201,7 @@ responder_socket_access_tests_SOURCES = \ - src/responder/common/responder_common.c \ - src/responder/common/responder_packet.c \ - src/responder/common/responder_cmd.c \ -+ src/responder/common/cache_req/cache_req_domain.c \ - src/responder/common/data_provider/rdp_message.c \ - src/responder/common/data_provider/rdp_client.c \ - $(SSSD_RESPONDER_IFACE_OBJ) \ -diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c -index aca150d69b398ceb1a52e5cd6a87d35dbc87020b..483126396f8addbad744ae03bfc739801cd0c18b 100644 ---- a/src/responder/common/cache_req/cache_req.c -+++ b/src/responder/common/cache_req/cache_req.c -@@ -24,6 +24,7 @@ - #include - - #include "util/util.h" -+#include "responder/common/responder.h" - #include "responder/common/cache_req/cache_req_private.h" - #include "responder/common/cache_req/cache_req_plugin.h" - -@@ -316,7 +317,7 @@ struct cache_req_search_domains_state { - struct cache_req *cr; - - /* work data */ -- struct sss_domain_info *domain; -+ struct cache_req_domain *cr_domain; - struct sss_domain_info *selected_domain; - struct cache_req_result **results; - size_t num_results; -@@ -330,13 +331,14 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req); - - static void cache_req_search_domains_done(struct tevent_req *subreq); - --struct tevent_req *cache_req_search_domains_send(TALLOC_CTX *mem_ctx, -- struct tevent_context *ev, -- struct cache_req *cr, -- struct sss_domain_info *domain, -- bool check_next, -- bool bypass_cache, -- bool bypass_dp) -+struct tevent_req * -+cache_req_search_domains_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct cache_req *cr, -+ struct cache_req_domain *cr_domain, -+ bool check_next, -+ bool bypass_cache, -+ bool bypass_dp) - { - struct tevent_req *req; - struct cache_req_search_domains_state *state = NULL; -@@ -352,7 +354,7 @@ struct tevent_req *cache_req_search_domains_send(TALLOC_CTX *mem_ctx, - state->ev = ev; - state->cr = cr; - -- state->domain = domain; -+ state->cr_domain = cr_domain; - state->check_next = check_next; - state->dp_success = true; - state->bypass_cache = bypass_cache; -@@ -378,6 +380,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) - struct cache_req_search_domains_state *state; - struct tevent_req *subreq; - struct cache_req *cr; -+ struct sss_domain_info *domain; - uint32_t next_domain_flag; - bool is_domain_valid; - bool allow_no_fqn; -@@ -389,11 +392,21 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) - next_domain_flag = cr->plugin->get_next_domain_flags; - allow_no_fqn = cr->plugin->allow_missing_fqn; - -- while (state->domain != NULL) { -+ while (state->cr_domain != NULL) { -+ domain = state->cr_domain->domain; -+ /* As the cr_domain list is a flatten version of the domains -+ * list, we have to ensure to only go through the subdomains in -+ * case it's specified in the plugin to do so. -+ */ -+ if (next_domain_flag == 0 && IS_SUBDOMAIN(domain)) { -+ state->cr_domain = state->cr_domain->next; -+ continue; -+ } -+ - /* Check if this domain is valid for this request. */ -- is_domain_valid = cache_req_validate_domain(cr, state->domain); -+ is_domain_valid = cache_req_validate_domain(cr, domain); - if (!is_domain_valid) { -- state->domain = get_next_domain(state->domain, next_domain_flag); -+ state->cr_domain = state->cr_domain->next; - continue; - } - -@@ -401,18 +414,18 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) - * qualified names on domain less search. We do not descend into - * subdomains here since those are implicitly qualified. - */ -- if (state->check_next && !allow_no_fqn && state->domain->fqnames) { -- state->domain = get_next_domain(state->domain, 0); -+ if (state->check_next && !allow_no_fqn && domain->fqnames) { -+ state->cr_domain = state->cr_domain->next; - continue; - } - -- state->selected_domain = state->domain; -+ state->selected_domain = domain; - -- if (state->domain == NULL) { -+ if (domain == NULL) { - break; - } - -- ret = cache_req_set_domain(cr, state->domain); -+ ret = cache_req_set_domain(cr, domain); - if (ret != EOK) { - return ret; - } -@@ -427,8 +440,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) - - /* we will continue with the following domain the next time */ - if (state->check_next) { -- state->domain = get_next_domain(state->domain, -- cr->plugin->get_next_domain_flags); -+ state->cr_domain = state->cr_domain->next; - } - - return EAGAIN; -@@ -625,11 +637,12 @@ static void cache_req_input_parsed(struct tevent_req *subreq); - static errno_t cache_req_select_domains(struct tevent_req *req, - const char *domain_name); - --static errno_t cache_req_search_domains(struct tevent_req *req, -- struct sss_domain_info *domain, -- bool check_next, -- bool bypass_cache, -- bool bypass_dp); -+static errno_t -+cache_req_search_domains(struct tevent_req *req, -+ struct cache_req_domain *oredered_domain, -+ bool check_next, -+ bool bypass_cache, -+ bool bypass_dp); - - static void cache_req_done(struct tevent_req *subreq); - -@@ -778,7 +791,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req, - const char *domain_name) - { - struct cache_req_state *state = NULL; -- struct sss_domain_info *domain; -+ struct cache_req_domain *cr_domain; - bool check_next; - bool bypass_cache; - bool bypass_dp; -@@ -798,29 +811,30 @@ static errno_t cache_req_select_domains(struct tevent_req *req, - CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, - "Performing a single domain search\n"); - -- domain = responder_get_domain(state->cr->rctx, domain_name); -- if (domain == NULL) { -+ cr_domain = cache_req_domain_get_domain_by_name( -+ state->cr->rctx->cr_domains, domain_name); -+ if (cr_domain == NULL) { - return ERR_DOMAIN_NOT_FOUND; - } -- - check_next = false; - } else { - CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, - "Performing a multi-domain search\n"); - -- domain = state->cr->rctx->domains; -+ cr_domain = state->cr->rctx->cr_domains; - check_next = true; - } - -- return cache_req_search_domains(req, domain, check_next, -+ return cache_req_search_domains(req, cr_domain, check_next, - bypass_cache, bypass_dp); - } - --static errno_t cache_req_search_domains(struct tevent_req *req, -- struct sss_domain_info *domain, -- bool check_next, -- bool bypass_cache, -- bool bypass_dp) -+static errno_t -+cache_req_search_domains(struct tevent_req *req, -+ struct cache_req_domain *cr_domain, -+ bool check_next, -+ bool bypass_cache, -+ bool bypass_dp) - { - struct tevent_req *subreq; - struct cache_req_state *state = NULL; -@@ -832,8 +846,9 @@ static errno_t cache_req_search_domains(struct tevent_req *req, - bypass_cache ? "bypass" : "check", - bypass_dp ? "bypass" : "check"); - -- subreq = cache_req_search_domains_send(state, state->ev, state->cr, domain, -- check_next, bypass_cache, bypass_dp); -+ subreq = cache_req_search_domains_send(state, state->ev, state->cr, -+ cr_domain, check_next, -+ bypass_cache, bypass_dp); - if (subreq == NULL) { - return ENOMEM; - } -diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c -new file mode 100644 -index 0000000000000000000000000000000000000000..bbabd695f1c6b6c29b7e61f571382ab9adfb0ea2 ---- /dev/null -+++ b/src/responder/common/cache_req/cache_req_domain.c -@@ -0,0 +1,166 @@ -+/* -+ Authors: -+ Fabiano Fidêncio -+ -+ Copyright (C) 2017 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 "responder/common/cache_req/cache_req_domain.h" -+ -+struct cache_req_domain * -+cache_req_domain_get_domain_by_name(struct cache_req_domain *domains, -+ const char *name) -+{ -+ struct cache_req_domain *dom; -+ struct cache_req_domain *ret = NULL; -+ -+ DLIST_FOR_EACH(dom, domains) { -+ if (sss_domain_get_state(dom->domain) == DOM_DISABLED) { -+ continue; -+ } -+ -+ if (strcasecmp(dom->domain->name, name) == 0 || -+ (dom->domain->flat_name != NULL && -+ strcasecmp(dom->domain->flat_name, name) == 0)) { -+ ret = dom; -+ break; -+ } -+ } -+ -+ if (ret == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Unknown domains [%s].\n", name); -+ } -+ -+ return ret; -+} -+ -+void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains) -+{ -+ struct cache_req_domain *p, *q, *r; -+ -+ DLIST_FOR_EACH_SAFE(p, q, *cr_domains) { -+ r = p; -+ DLIST_REMOVE(*cr_domains, p); -+ talloc_zfree(r); -+ } -+ -+ *cr_domains = NULL; -+} -+ -+static struct cache_req_domain * -+cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domains, -+ char **resolution_order) -+{ -+ struct cache_req_domain *cr_domains = NULL; -+ struct cache_req_domain *cr_domain; -+ struct sss_domain_info *dom; -+ char *name; -+ int flag = SSS_GND_ALL_DOMAINS; -+ int i; -+ errno_t ret; -+ -+ if (resolution_order != NULL) { -+ for (i = 0; resolution_order[i] != NULL; i++) { -+ name = resolution_order[i]; -+ for (dom = domains; dom; dom = get_next_domain(dom, flag)) { -+ if (strcasecmp(name, dom->name) != 0) { -+ continue; -+ } -+ -+ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain); -+ if (cr_domain == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ cr_domain->domain = dom; -+ -+ DLIST_ADD_END(cr_domains, cr_domain, -+ struct cache_req_domain *); -+ break; -+ } -+ } -+ } -+ -+ for (dom = domains; dom; dom = get_next_domain(dom, flag)) { -+ if (string_in_list(dom->name, resolution_order, false)) { -+ continue; -+ } -+ -+ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain); -+ if (cr_domain == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ cr_domain->domain = dom; -+ -+ DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *); -+ } -+ -+ ret = EOK; -+ -+done: -+ if (ret != EOK) { -+ cache_req_domain_list_zfree(&cr_domains); -+ } -+ -+ return cr_domains; -+} -+ -+struct cache_req_domain * -+cache_req_domain_new_list_from_domain_resolution_order( -+ TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domains, -+ const char *domain_resolution_order) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct cache_req_domain *cr_domains = NULL; -+ char **list = NULL; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return NULL; -+ } -+ -+ if (domain_resolution_order != NULL) { -+ if (strcmp(domain_resolution_order, ":") != 0) { -+ ret = split_on_separator(tmp_ctx, domain_resolution_order, ':', -+ true, true, &list, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "split_on_separator() failed [%d]: [%s].\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ } -+ } -+ -+ cr_domains = cache_req_domain_new_list_from_string_list(mem_ctx, domains, -+ list); -+ if (cr_domains == NULL) { -+ ret = ENOMEM; -+ DEBUG(SSSDBG_OP_FAILURE, -+ "cache_req_domain_new_list_from_domain_resolution_order() " -+ "failed [%d]: [%s].\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+done: -+ talloc_free(tmp_ctx); -+ return cr_domains; -+} -diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h -new file mode 100644 -index 0000000000000000000000000000000000000000..41c50e8c293d7b032cb2f05482c40e93e4f723dc ---- /dev/null -+++ b/src/responder/common/cache_req/cache_req_domain.h -@@ -0,0 +1,46 @@ -+/* -+ Authors: -+ Fabiano Fidêncio -+ -+ Copyright (C) 2017 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 . -+*/ -+ -+#ifndef _CACHE_REQ_DOMAIN_H_ -+#define _CACHE_REQ_DOMAIN_H_ -+ -+#include "responder/common/responder.h" -+ -+struct cache_req_domain { -+ struct sss_domain_info *domain; -+ -+ struct cache_req_domain *prev; -+ struct cache_req_domain *next; -+}; -+ -+struct cache_req_domain * -+cache_req_domain_get_domain_by_name(struct cache_req_domain *domains, -+ const char *name); -+ -+struct cache_req_domain * -+cache_req_domain_new_list_from_domain_resolution_order( -+ TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domains, -+ const char *domain_resolution_order); -+ -+void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains); -+ -+ -+#endif /* _CACHE_REQ_DOMAIN_H_ */ -diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h -index 4d1048a1e0c9be2cad91317d51baf670ecb3307e..29e3f95caf484f43307c9c28d4abd3f50f360a95 100644 ---- a/src/responder/common/responder.h -+++ b/src/responder/common/responder.h -@@ -37,6 +37,7 @@ - #include "sbus/sssd_dbus.h" - #include "responder/common/negcache.h" - #include "sss_client/sss_cli.h" -+#include "responder/common/cache_req/cache_req_domain.h" - - extern hash_table_t *dp_requests; - -@@ -113,6 +114,8 @@ struct resp_ctx { - int domains_timeout; - int client_idle_timeout; - -+ struct cache_req_domain *cr_domains; -+ - time_t last_request_time; - int idle_timeout; - struct tevent_timer *idle; -@@ -387,4 +390,6 @@ char *sss_resp_create_fqname(TALLOC_CTX *mem_ctx, - bool name_is_upn, - const char *orig_name); - -+errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx); -+ - #endif /* __SSS_RESPONDER_H__ */ -diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c -index 76f43609651217e537ffa515aaf5b5caa98a2e90..1792a4c3771fa326c7cca31e1981dce315c03758 100644 ---- a/src/responder/common/responder_common.c -+++ b/src/responder/common/responder_common.c -@@ -1453,3 +1453,156 @@ fail: - return ret; - - } -+ -+/* ====== Helper functions for the domain resolution order ======= */ -+static struct cache_req_domain * -+sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domains, -+ struct sysdb_ctx *sysdb) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct cache_req_domain *cr_domains = NULL; -+ const char *domain_resolution_order = NULL; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return NULL; -+ } -+ -+ ret = sysdb_get_view_domain_resolution_order(tmp_ctx, sysdb, -+ &domain_resolution_order); -+ if (ret != EOK && ret != ENOENT) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "sysdb_get_view_cache_req_domain() failed [%d]: [%s].\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ /* Using mem_ctx (which is rctx) directly here to avoid copying -+ * this memory around. */ -+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order( -+ mem_ctx, domains, domain_resolution_order); -+ if (cr_domains == NULL) { -+ ret = ENOMEM; -+ DEBUG(SSSDBG_DEFAULT, -+ "cache_req_domain_new_list_from_domain_resolution_order() " -+ "failed [%d]: [%s].\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+done: -+ talloc_free(tmp_ctx); -+ return cr_domains; -+} -+ -+static struct cache_req_domain * -+sss_resp_new_cr_domains_from_ipa_config(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domains, -+ struct sysdb_ctx *sysdb, -+ const char *domain) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct cache_req_domain *cr_domains = NULL; -+ const char *domain_resolution_order = NULL; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return NULL; -+ } -+ -+ ret = sysdb_domain_get_domain_resolution_order(tmp_ctx, sysdb, domain, -+ &domain_resolution_order); -+ -+ if (ret != EOK && ret != ENOENT) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "sysdb_domain_get_cache_req_domain() failed [%d]: [%s].\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ /* Using mem_ctx (which is rctx) directly here to avoid copying -+ * this memory around. */ -+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order( -+ mem_ctx, domains, domain_resolution_order); -+ if (cr_domains == NULL) { -+ DEBUG(SSSDBG_DEFAULT, -+ "cache_req_domain_new_list_from_domain_resolution_order() " -+ "failed [%d]: [%s].\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+done: -+ talloc_free(tmp_ctx); -+ return cr_domains; -+} -+ -+errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) -+{ -+ struct cache_req_domain *cr_domains = NULL; -+ struct sss_domain_info *dom; -+ errno_t ret; -+ -+ for (dom = rctx->domains; dom != NULL; dom = dom->next) { -+ if (dom->provider != NULL && strcmp(dom->provider, "ipa") == 0) { -+ break; -+ } -+ } -+ -+ if (dom == NULL) { -+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order( -+ rctx, rctx->domains, NULL); -+ if (cr_domains == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to flatten the list of domains.\n"); -+ } -+ goto done; -+ } -+ -+ if (dom->has_views) { -+ cr_domains = sss_resp_new_cr_domains_from_ipa_id_view(rctx, -+ rctx->domains, -+ dom->sysdb); -+ if (cr_domains == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Failed to use ipaDomainResolutionOrder set for the " -+ "view \"%s\".\n" -+ "Trying to fallback to use ipaDomainOrderResolution " -+ "set in ipaConfig for the domain: %s.\n", -+ dom->view_name, dom->name); -+ } else { -+ goto done; -+ } -+ } -+ -+ cr_domains = sss_resp_new_cr_domains_from_ipa_config(rctx, rctx->domains, -+ dom->sysdb, -+ dom->name); -+ if (cr_domains == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Failed to use ipaDomainResolutionOrder set in ipaConfig " -+ "for the domain: \"%s\".\n" -+ "No ipaDomainResolutionOrder will be followed.\n", -+ dom->name); -+ } else { -+ goto done; -+ } -+ -+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order( -+ rctx, rctx->domains, NULL); -+ if (cr_domains == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to flatten the list of domains.\n"); -+ goto done; -+ } -+ -+done: -+ ret = cr_domains != NULL ? EOK : ENOMEM; -+ -+ cache_req_domain_list_zfree(&rctx->cr_domains); -+ rctx->cr_domains = cr_domains; -+ -+ return ret; -+} -diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c -index 0f9c01214631200f9687635f6302fa5c07e8a1fe..8c90b7773e248e1dd6d846c5050e1931fc50c786 100644 ---- a/src/responder/common/responder_get_domains.c -+++ b/src/responder/common/responder_get_domains.c -@@ -192,6 +192,13 @@ struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx, - - if (state->dom == NULL) { - /* All domains were local */ -+ ret = sss_resp_populate_cr_domains(state->rctx); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "sss_resp_populate_cr_domains() failed [%d]: [%s]\n", -+ ret, sss_strerror(ret)); -+ goto immediately; -+ } - ret = EOK; - goto immediately; - } -@@ -253,6 +260,13 @@ sss_dp_get_domains_process(struct tevent_req *subreq) - if (state->dom == NULL) { - /* All domains were local */ - set_time_of_last_request(state->rctx); -+ ret = sss_resp_populate_cr_domains(state->rctx); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "sss_resp_populate_cr_domains() failed [%d]: [%s]\n", -+ ret, sss_strerror(ret)); -+ goto fail; -+ } - tevent_req_done(req); - return; - } -diff --git a/src/tests/cmocka/common_mock_resp.c b/src/tests/cmocka/common_mock_resp.c -index 88808b1b9394b7a9ee7e58b30b4fbd9d467493d3..175101fc51fd395d792b1fccaecdb327caef2b64 100644 ---- a/src/tests/cmocka/common_mock_resp.c -+++ b/src/tests/cmocka/common_mock_resp.c -@@ -51,6 +51,12 @@ mock_rctx(TALLOC_CTX *mem_ctx, - rctx->ev = ev; - rctx->domains = domains; - rctx->pvt_ctx = pvt_ctx; -+ if (domains != NULL) { -+ ret = sss_resp_populate_cr_domains(rctx); -+ if (ret != EOK) { -+ return NULL; -+ } -+ } - return rctx; - } - -diff --git a/src/tests/cmocka/common_mock_resp_dp.c b/src/tests/cmocka/common_mock_resp_dp.c -index 5db5255ab61231870982c4b78a39504ae8954bcd..4b38a38e6f53499132f9fe14a0ec0af157cf85ca 100644 ---- a/src/tests/cmocka/common_mock_resp_dp.c -+++ b/src/tests/cmocka/common_mock_resp_dp.c -@@ -21,6 +21,7 @@ - */ - - #include "util/util.h" -+#include "responder/common/responder.h" - #include "tests/cmocka/common_mock_resp.h" - - /* Mock DP requests that finish immediatelly and return -@@ -165,6 +166,12 @@ sss_dp_get_domains_send(TALLOC_CTX *mem_ctx, - bool force, - const char *hint) - { -+ errno_t ret; -+ ret = sss_resp_populate_cr_domains(rctx); -+ if (ret != EOK) { -+ return NULL; -+ } -+ - return test_req_succeed_send(mem_ctx, rctx->ev); - } - -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index ede72b341b60842ad470df2794aa90ea9797e999..2f526660cbbbf2443dbae4e213c1336feb6c661e 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -3440,6 +3440,10 @@ static int nss_subdom_test_setup(void **state) - nss_test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - -+ ret = sss_resp_populate_cr_domains(nss_test_ctx->rctx); -+ assert_int_equal(ret, EOK); -+ assert_non_null(nss_test_ctx->rctx->cr_domains); -+ - nss_test_ctx->subdom = nss_test_ctx->tctx->dom->subdomains; - - ret = store_group(nss_test_ctx, nss_test_ctx->subdom, -diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am -index 4a4090df9296aadde308249f533e7ba246e92f93..c99ebde5f0fc18d1283392cbb307434579d5d811 100644 ---- a/src/tests/cwrap/Makefile.am -+++ b/src/tests/cwrap/Makefile.am -@@ -41,6 +41,7 @@ SSSD_CACHE_REQ_OBJ = \ - ../../../src/responder/common/cache_req/cache_req_result.c \ - ../../../src/responder/common/cache_req/cache_req_search.c \ - ../../../src/responder/common/cache_req/cache_req_data.c \ -+ ../../../src/responder/common/cache_req/cache_req_domain.c \ - ../../../src/responder/common/cache_req/plugins/cache_req_common.c \ - ../../../src/responder/common/cache_req/plugins/cache_req_enum_users.c \ - ../../../src/responder/common/cache_req/plugins/cache_req_enum_groups.c \ --- -2.9.3 - diff --git a/SOURCES/0052-ifp-add-method-to-refresh-access-control-rules-in-do.patch b/SOURCES/0052-ifp-add-method-to-refresh-access-control-rules-in-do.patch new file mode 100644 index 0000000..55e224d --- /dev/null +++ b/SOURCES/0052-ifp-add-method-to-refresh-access-control-rules-in-do.patch @@ -0,0 +1,158 @@ +From c6e02c84a567127b37b1c036abf7952f1d36783a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 2 Nov 2017 14:59:57 +0100 +Subject: [PATCH 52/57] ifp: add method to refresh access control rules in + domain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit c6cf752337f5977ce3753b7113dc1a2342c86319) +--- + src/responder/ifp/ifp_domains.c | 22 ++++++++++++++++++++++ + src/responder/ifp/ifp_domains.h | 3 +++ + src/responder/ifp/ifp_iface.c | 3 ++- + src/responder/ifp/ifp_iface.xml | 3 +++ + src/responder/ifp/ifp_iface_generated.c | 13 +++++++++++++ + src/responder/ifp/ifp_iface_generated.h | 5 +++++ + 6 files changed, 48 insertions(+), 1 deletion(-) + +diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c +index 977bbfcbe818f08873ce072d34fdcf900cabf52f..cd7e2fc7aeff5467514269e5b078b0da88ab4f50 100644 +--- a/src/responder/ifp/ifp_domains.c ++++ b/src/responder/ifp/ifp_domains.c +@@ -630,3 +630,25 @@ int ifp_domains_domain_list_servers(struct sbus_request *sbus_req, + + return EOK; + } ++ ++int ifp_domains_domain_refresh_access_rules(struct sbus_request *sbus_req, ++ void *data) ++{ ++ struct ifp_ctx *ifp_ctx; ++ struct sss_domain_info *dom; ++ ++ ifp_ctx = talloc_get_type(data, struct ifp_ctx); ++ ++ dom = get_domain_info_from_req(sbus_req, data); ++ if (dom == NULL) { ++ sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN, ++ "Unknown domain"); ++ return EOK; ++ } ++ ++ rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH, ++ IFACE_DP_ACCESS_CONTROL, ++ IFACE_DP_ACCESS_CONTROL_REFRESHRULES); ++ ++ return EOK; ++} +diff --git a/src/responder/ifp/ifp_domains.h b/src/responder/ifp/ifp_domains.h +index 621ba6158e285911cb8298cef212219dfd3afec8..d8cc9d34c92cd04b6db432c1fc0e179a717001da 100644 +--- a/src/responder/ifp/ifp_domains.h ++++ b/src/responder/ifp/ifp_domains.h +@@ -108,4 +108,7 @@ int ifp_domains_domain_list_servers(struct sbus_request *sbus_req, + void *data, + const char *service); + ++int ifp_domains_domain_refresh_access_rules(struct sbus_request *sbus_req, ++ void *data); ++ + #endif /* IFP_DOMAINS_H_ */ +diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c +index 3293b92d750d33b2ecf77a03098c5169d052c924..f995e28f99f9489ca17fbc51fa6894d458f9e21f 100644 +--- a/src/responder/ifp/ifp_iface.c ++++ b/src/responder/ifp/ifp_iface.c +@@ -79,7 +79,8 @@ struct iface_ifp_domains_domain iface_ifp_domains_domain = { + .IsOnline = ifp_domains_domain_is_online, + .ListServices = ifp_domains_domain_list_services, + .ActiveServer = ifp_domains_domain_active_server, +- .ListServers = ifp_domains_domain_list_servers ++ .ListServers = ifp_domains_domain_list_servers, ++ .RefreshAccessRules = ifp_domains_domain_refresh_access_rules + }; + + struct iface_ifp_users iface_ifp_users = { +diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml +index 39385e866f31131c7860001ae4d6e6b51105aa52..1aa7eac03f0a3dc86f1d25883ac37f2fabf6b9e8 100644 +--- a/src/responder/ifp/ifp_iface.xml ++++ b/src/responder/ifp/ifp_iface.xml +@@ -112,6 +112,9 @@ + + + ++ ++ ++ + + + +diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c +index 6943e38e3b6d2fc9e09ade1a863905c8d81a39ba..c2cdbf5b0ef3d59068aeed7a8f45099c14c4a94a 100644 +--- a/src/responder/ifp/ifp_iface_generated.c ++++ b/src/responder/ifp/ifp_iface_generated.c +@@ -552,6 +552,12 @@ int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const + DBUS_TYPE_INVALID); + } + ++int iface_ifp_domains_domain_RefreshAccessRules_finish(struct sbus_request *req) ++{ ++ return sbus_request_return_and_finish(req, ++ DBUS_TYPE_INVALID); ++} ++ + /* methods for org.freedesktop.sssd.infopipe.Domains.Domain */ + const struct sbus_method_meta iface_ifp_domains_domain__methods[] = { + { +@@ -582,6 +588,13 @@ const struct sbus_method_meta iface_ifp_domains_domain__methods[] = { + offsetof(struct iface_ifp_domains_domain, ListServers), + invoke_s_method, + }, ++ { ++ "RefreshAccessRules", /* name */ ++ NULL, /* no in_args */ ++ NULL, /* no out_args */ ++ offsetof(struct iface_ifp_domains_domain, RefreshAccessRules), ++ NULL, /* no invoker */ ++ }, + { NULL, } + }; + +diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h +index 30752bf063de1f2530c7451f01cc22ad3e863185..f1e6c80bab27d0ed581abc566a178e6857794805 100644 +--- a/src/responder/ifp/ifp_iface_generated.h ++++ b/src/responder/ifp/ifp_iface_generated.h +@@ -57,6 +57,7 @@ + #define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES "ListServices" + #define IFACE_IFP_DOMAINS_DOMAIN_ACTIVESERVER "ActiveServer" + #define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVERS "ListServers" ++#define IFACE_IFP_DOMAINS_DOMAIN_REFRESHACCESSRULES "RefreshAccessRules" + + /* constants for org.freedesktop.sssd.infopipe.Cache */ + #define IFACE_IFP_CACHE "org.freedesktop.sssd.infopipe.Cache" +@@ -209,6 +210,7 @@ struct iface_ifp_domains_domain { + int (*ListServices)(struct sbus_request *req, void *data); + int (*ActiveServer)(struct sbus_request *req, void *data, const char *arg_service); + int (*ListServers)(struct sbus_request *req, void *data, const char *arg_service_name); ++ int (*RefreshAccessRules)(struct sbus_request *req, void *data); + }; + + /* finish function for IsOnline */ +@@ -223,6 +225,9 @@ int iface_ifp_domains_domain_ActiveServer_finish(struct sbus_request *req, const + /* finish function for ListServers */ + int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers); + ++/* finish function for RefreshAccessRules */ ++int iface_ifp_domains_domain_RefreshAccessRules_finish(struct sbus_request *req); ++ + /* vtable for org.freedesktop.sssd.infopipe.Cache */ + struct iface_ifp_cache { + struct sbus_vtable vtable; /* derive from sbus_vtable */ +-- +2.14.3 + diff --git a/SOURCES/0053-UTIL-Expose-replace_char-as-sss_replace_char.patch b/SOURCES/0053-UTIL-Expose-replace_char-as-sss_replace_char.patch deleted file mode 100644 index 0db08c7..0000000 --- a/SOURCES/0053-UTIL-Expose-replace_char-as-sss_replace_char.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 3a3b761bc89aa860ca7e6af323c3e0425306014c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Sun, 26 Mar 2017 01:49:53 +0100 -Subject: [PATCH 53/54] UTIL: Expose replace_char() as sss_replace_char() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This method is going to be used in the follow-up patch for replacing ',' -by ':' so we can keep the domain resolution order option consitent with -the way it's set on IPA side and still keep consistent with the way -lists are represented on sssd.conf file. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/util/string_utils.c | 12 ++++++------ - src/util/util.h | 5 +++++ - 2 files changed, 11 insertions(+), 6 deletions(-) - -diff --git a/src/util/string_utils.c b/src/util/string_utils.c -index 872b7e29e55e8628085affd07f3363019aae5ee9..1215ec96a57089a13f455812adf5a0b0812afa6d 100644 ---- a/src/util/string_utils.c -+++ b/src/util/string_utils.c -@@ -22,10 +22,10 @@ - - #include "util/util.h" - --static char *replace_char(TALLOC_CTX *mem_ctx, -- const char *in, -- const char match, -- const char sub) -+char *sss_replace_char(TALLOC_CTX *mem_ctx, -+ const char *in, -+ const char match, -+ const char sub) - { - char *p; - char *out; -@@ -63,7 +63,7 @@ char * sss_replace_space(TALLOC_CTX *mem_ctx, - return talloc_strdup(mem_ctx, orig_name); - } - -- return replace_char(mem_ctx, orig_name, ' ', subst); -+ return sss_replace_char(mem_ctx, orig_name, ' ', subst); - } - - char * sss_reverse_replace_space(TALLOC_CTX *mem_ctx, -@@ -81,7 +81,7 @@ char * sss_reverse_replace_space(TALLOC_CTX *mem_ctx, - return talloc_strdup(mem_ctx, orig_name); - } - -- return replace_char(mem_ctx, orig_name, subst, ' '); -+ return sss_replace_char(mem_ctx, orig_name, subst, ' '); - } - - errno_t guid_blob_to_string_buf(const uint8_t *blob, char *str_buf, -diff --git a/src/util/util.h b/src/util/util.h -index 82760940269ad8883e725e3a5cf463486c9cfd36..2170c5fb7cffda3910d2b58e33ec7abe3ec4a7d4 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -600,6 +600,11 @@ errno_t name_to_well_known_sid(const char *dom, const char *name, - const char **sid); - - /* from string_utils.c */ -+char *sss_replace_char(TALLOC_CTX *mem_ctx, -+ const char *in, -+ const char match, -+ const char sub); -+ - char * sss_replace_space(TALLOC_CTX *mem_ctx, - const char *orig_name, - const char replace_char); --- -2.9.3 - diff --git a/SOURCES/0053-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch b/SOURCES/0053-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch new file mode 100644 index 0000000..4c2404e --- /dev/null +++ b/SOURCES/0053-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch @@ -0,0 +1,200 @@ +From cbe1f1f8fa207eded53260a0fb288c5b31b18c96 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 2 Nov 2017 15:00:17 +0100 +Subject: [PATCH 53/57] sssctl: call dbus instead of pam to refresh HBAC rules +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit be804178d5e5fee64be2b080e73f4ce7b0074f76) +--- + src/tools/sssctl/sssctl_access_report.c | 127 +++++++++++++++----------------- + 1 file changed, 58 insertions(+), 69 deletions(-) + +diff --git a/src/tools/sssctl/sssctl_access_report.c b/src/tools/sssctl/sssctl_access_report.c +index 11172329817b4dedaca480ab8a4537149853c330..8cf1a8a871b27827c317d658c0f93f34773c4841 100644 +--- a/src/tools/sssctl/sssctl_access_report.c ++++ b/src/tools/sssctl/sssctl_access_report.c +@@ -15,11 +15,11 @@ + along with this program. If not, see . + */ + +-#include +- + #include "util/util.h" + #include "tools/common/sss_tools.h" + #include "tools/sssctl/sssctl.h" ++#include "sbus/sssd_dbus.h" ++#include "responder/ifp/ifp_iface.h" + + /* + * We're searching the cache directly.. +@@ -27,58 +27,9 @@ + #include "providers/ipa/ipa_hbac_private.h" + #include "providers/ipa/ipa_rules_common.h" + +-#ifdef HAVE_SECURITY_PAM_MISC_H +-# include +-#elif defined(HAVE_SECURITY_OPENPAM_H) +-# include +-#endif +- +-#ifdef HAVE_SECURITY_PAM_MISC_H +-static struct pam_conv conv = { +- misc_conv, +- NULL +-}; +-#elif defined(HAVE_SECURITY_OPENPAM_H) +-static struct pam_conv conv = { +- openpam_ttyconv, +- NULL +-}; +-#else +-# error "Missing text based pam conversation function" +-#endif +- +-#ifndef DEFAULT_SERVICE +-#define DEFAULT_SERVICE "system-auth" +-#endif /* DEFAULT_SERVICE */ +- +-#ifndef DEFAULT_USER +-#define DEFAULT_USER "admin" +-#endif /* DEFAULT_USER */ +- + typedef errno_t (*sssctl_dom_access_reporter_fn)(struct sss_tool_ctx *tool_ctx, +- const char *user, +- const char *service, + struct sss_domain_info *domain); + +-static errno_t run_pam_acct(struct sss_tool_ctx *tool_ctx, +- const char *user, +- const char *service, +- struct sss_domain_info *domain) +-{ +- errno_t ret; +- pam_handle_t *pamh; +- +- ret = pam_start(service, user, &conv, &pamh); +- if (ret != PAM_SUCCESS) { +- ERROR("pam_start failed: %s\n", pam_strerror(pamh, ret)); +- return EIO; +- } +- +- ret = pam_acct_mgmt(pamh, 0); +- pam_end(pamh, ret); +- return ret; +-} +- + static errno_t get_rdn_value(TALLOC_CTX *mem_ctx, + struct sss_domain_info *dom, + const char *dn_attr, +@@ -315,9 +266,58 @@ static void print_ipa_hbac_rule(struct sss_domain_info *domain, + PRINT("\n"); + } + ++static errno_t refresh_hbac_rules(struct sss_tool_ctx *tool_ctx, ++ struct sss_domain_info *domain) ++{ ++ TALLOC_CTX *tmp_ctx; ++ sss_sifp_error error; ++ sss_sifp_ctx *sifp; ++ DBusMessage *reply; ++ const char *path; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); ++ return ENOMEM; ++ } ++ ++ path = sbus_opath_compose(tmp_ctx, IFP_PATH_DOMAINS, domain->name); ++ if (path == NULL) { ++ printf(_("Out of memory!\n")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ error = sssctl_sifp_init(tool_ctx, &sifp); ++ if (error != SSS_SIFP_OK) { ++ sssctl_sifp_error(sifp, error, "Unable to connect to the InfoPipe"); ++ ret = EIO; ++ goto done; ++ } ++ ++ error = sssctl_sifp_send(tmp_ctx, sifp, &reply, path, ++ IFACE_IFP_DOMAINS_DOMAIN, ++ IFACE_IFP_DOMAINS_DOMAIN_REFRESHACCESSRULES); ++ if (error != SSS_SIFP_OK) { ++ sssctl_sifp_error(sifp, error, "Unable to refresh HBAC rules"); ++ ret = EIO; ++ goto done; ++ } ++ ++ ret = sbus_parse_reply(reply); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx, +- const char *user, +- const char *service, + struct sss_domain_info *domain) + { + TALLOC_CTX *tmp_ctx = NULL; +@@ -338,9 +338,9 @@ static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx, + struct ldb_message **msgs = NULL; + + /* Run the pam account phase to make sure the rules are fetched by SSSD */ +- ret = run_pam_acct(tool_ctx, user, service, domain); +- if (ret != PAM_SUCCESS && ret != PAM_PERM_DENIED) { +- ERROR("Cannot run the PAM account phase, reporting stale rules\n"); ++ ret = refresh_hbac_rules(tool_ctx, domain); ++ if (ret != EOK) { ++ ERROR("Unable to refresh HBAC rules, using cached content\n"); + /* Non-fatal */ + } + +@@ -398,19 +398,8 @@ errno_t sssctl_access_report(struct sss_cmdline *cmdline, + const char *domname = NULL; + sssctl_dom_access_reporter_fn reporter; + struct sss_domain_info *dom; +- const char *user = DEFAULT_USER; +- const char *service = DEFAULT_SERVICE; + +- /* Parse command line. */ +- struct poptOption options[] = { +- { "user", 'u', POPT_ARG_STRING, &user, 0, +- _("PAM user, default: " DEFAULT_USER), NULL }, +- { "service", 's', POPT_ARG_STRING, &service, 0, +- _("PAM service, default: " DEFAULT_SERVICE), NULL }, +- POPT_TABLEEND +- }; +- +- ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL, ++ ret = sss_tool_popt_ex(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL, + NULL, NULL, "DOMAIN", _("Specify domain name."), + &domname, NULL); + if (ret != EOK) { +@@ -431,5 +420,5 @@ errno_t sssctl_access_report(struct sss_cmdline *cmdline, + return ret; + } + +- return reporter(tool_ctx, user, service, dom); ++ return reporter(tool_ctx, dom); + } +-- +2.14.3 + diff --git a/SOURCES/0054-Add-domain_resolution_order-config-option.patch b/SOURCES/0054-Add-domain_resolution_order-config-option.patch deleted file mode 100644 index e91960d..0000000 --- a/SOURCES/0054-Add-domain_resolution_order-config-option.patch +++ /dev/null @@ -1,205 +0,0 @@ -From 26b838f2229483952aeec92a3446acef828244c4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Sun, 26 Mar 2017 03:00:14 +0200 -Subject: [PATCH 54/54] Add domain_resolution_order config option -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This is the local equivalent of option of ipaDomainResolutionOrder and -has precedence over the ones set on IPA side making the precedence order -to be like: Local > View > Globally. - -As done for the IPA side configurations, the domains which were not -explicitly set up will be apennded to the final of the -domain_resolution_order list in the very same order they're presented in -the "domains" option of [sssd] section in the config file. There's no -guarantee of order for the subdomains though. - -It's also important to mention that no expansion magic is performed on -our side. It means that if 'example.com' is set it does *not* stand for -all its subdomains DNS wise (like 'foo.example.com', 'bar.example.com', -etc). - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/confdb/confdb.h | 1 + - src/config/SSSDConfig/__init__.py.in | 1 + - src/config/SSSDConfigTest.py | 7 ++++++- - src/config/cfg_rules.ini | 1 + - src/config/etc/sssd.api.conf | 1 + - src/man/sssd.conf.5.xml | 20 ++++++++++++++++++++ - src/responder/common/responder.h | 1 + - src/responder/common/responder_common.c | 27 +++++++++++++++++++++++++++ - 8 files changed, 58 insertions(+), 1 deletion(-) - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index fb60675ca8beb2c2a157bf021ed9cad362742988..56a603652d6c8256735e7f8b125300ff7b254645 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -74,6 +74,7 @@ - #define CONFDB_MONITOR_CERT_VERIFICATION "certificate_verification" - #define CONFDB_MONITOR_DISABLE_NETLINK "disable_netlink" - #define CONFDB_MONITOR_ENABLE_FILES_DOM "enable_files_domain" -+#define CONFDB_MONITOR_DOMAIN_RESOLUTION_ORDER "domain_resolution_order" - - /* Both monitor and domains */ - #define CONFDB_NAME_REGEX "re_expression" -diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in -index 03a1a43336604bb815626e64cb54052bdf87acf2..e7fb7673d393d4f12910f355d3edf33f4390c1f1 100644 ---- a/src/config/SSSDConfig/__init__.py.in -+++ b/src/config/SSSDConfig/__init__.py.in -@@ -66,6 +66,7 @@ option_strings = { - 'override_space': _('All spaces in group or user names will be replaced with this character'), - 'disable_netlink' : _('Tune sssd to honor or ignore netlink state changes'), - 'enable_files_domain' : _('Enable or disable the implicit files domain'), -+ 'domain_resolution_order': _('A specific order of the domains to be looked up'), - - # [nss] - 'enum_cache_timeout' : _('Enumeration cache timeout length (seconds)'), -diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py -index 457a6f0a09e7139a05f29f8bef7e475fe3b58ec2..6899bf8ae04bf210546c8cbdba8235f094e23dc0 100755 ---- a/src/config/SSSDConfigTest.py -+++ b/src/config/SSSDConfigTest.py -@@ -94,6 +94,10 @@ class SSSDConfigTestValid(unittest.TestCase): - self.assertTrue('default_domain_suffix' in new_options) - self.assertEquals(new_options['default_domain_suffix'][0], str) - -+ self.assertTrue('domain_resolution_order' in new_options) -+ self.assertEquals(new_options['domain_resolution_order'][0], list) -+ self.assertEquals(new_options['domain_resolution_order'][1], str) -+ - del sssdconfig - - def testDomains(self): -@@ -314,7 +318,8 @@ class SSSDConfigTestSSSDService(unittest.TestCase): - 'certificate_verification', - 'override_space', - 'disable_netlink', -- 'enable_files_domain'] -+ 'enable_files_domain', -+ 'domain_resolution_order'] - - self.assertTrue(type(options) == dict, - "Options should be a dictionary") -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 933ebccd828189d923d2186753dfbc0b5c0814ce..41efcea552a82c5492a0d21a8d0797ee42cdc8c7 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -43,6 +43,7 @@ option = override_space - option = config_file_version - option = disable_netlink - option = enable_files_domain -+option = domain_resolution_order - - [rule/allowed_nss_options] - validator = ini_allowed_options -diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf -index 08cecf00367aaaab3794a48bd1e728421a996e49..6965028e1ca748f8b6677d9fc1faa66d5c307a0c 100644 ---- a/src/config/etc/sssd.api.conf -+++ b/src/config/etc/sssd.api.conf -@@ -32,6 +32,7 @@ certificate_verification = str, None, false - override_space = str, None, false - disable_netlink = bool, None, false - enable_files_domain = str, None, false -+domain_resolution_order = list, str, false - - [nss] - # Name service -diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml -index 1c27742cf0c1b6ffad23ab5b044bf4a168ed8f69..4fe13b85d511fb6a2ccc9b4de956710b05bc898c 100644 ---- a/src/man/sssd.conf.5.xml -+++ b/src/man/sssd.conf.5.xml -@@ -542,6 +542,26 @@ - - - -+ -+ domain_resolution_order -+ -+ -+ Comma separated list of domains and subdomains -+ representing the lookup order that will be -+ followed. -+ The list doesn't have to include all possible -+ domains as the missing domains will be looked -+ up based on the order they're presented in the -+ domains configuration option. -+ The subdomains which are not listed as part of -+ lookup_order will be looked up -+ in a random order for each parent domain. -+ -+ -+ Default: Not set -+ -+ -+ - - - -diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h -index 29e3f95caf484f43307c9c28d4abd3f50f360a95..4210307489fe25829a1674f254ecc7d185029698 100644 ---- a/src/responder/common/responder.h -+++ b/src/responder/common/responder.h -@@ -115,6 +115,7 @@ struct resp_ctx { - int client_idle_timeout; - - struct cache_req_domain *cr_domains; -+ const char *domain_resolution_order; - - time_t last_request_time; - int idle_timeout; -diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c -index 1792a4c3771fa326c7cca31e1981dce315c03758..154d7dc7718c437d10e152fcba98161e2034fb14 100644 ---- a/src/responder/common/responder_common.c -+++ b/src/responder/common/responder_common.c -@@ -1163,6 +1163,19 @@ int sss_process_init(TALLOC_CTX *mem_ctx, - rctx->override_space = tmp[0]; - } - -+ ret = confdb_get_string(rctx->cdb, rctx, -+ CONFDB_MONITOR_CONF_ENTRY, -+ CONFDB_MONITOR_DOMAIN_RESOLUTION_ORDER, NULL, -+ &tmp); -+ if (ret == EOK) { -+ rctx->domain_resolution_order = sss_replace_char(rctx, tmp, ',', ':'); -+ } else { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Cannot get the \"domain_resolution_order\" option.\n" -+ "The set up lookup_order won't be followed [%d]: %s.\n", -+ ret, sss_strerror(ret)); -+ } -+ - ret = sss_monitor_init(rctx, rctx->ev, monitor_intf, - svc_name, svc_version, MT_SVC_SERVICE, - rctx, &rctx->last_request_time, -@@ -1546,6 +1559,20 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) - struct sss_domain_info *dom; - errno_t ret; - -+ if (rctx->domain_resolution_order != NULL) { -+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order( -+ rctx, rctx->domains, rctx->domain_resolution_order); -+ -+ if (cr_domains == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Failed to use domain_resolution_order set in the config file.\n" -+ "Trying to fallback to use ipaDomainOrderResolution setup by " -+ "IPA.\n"); -+ } else { -+ goto done; -+ } -+ } -+ - for (dom = rctx->domains; dom != NULL; dom = dom->next) { - if (dom->provider != NULL && strcmp(dom->provider, "ipa") == 0) { - break; --- -2.9.3 - diff --git a/SOURCES/0054-sysdb-be_refresh_get_values_ex-remove-unused-option.patch b/SOURCES/0054-sysdb-be_refresh_get_values_ex-remove-unused-option.patch new file mode 100644 index 0000000..a4f566f --- /dev/null +++ b/SOURCES/0054-sysdb-be_refresh_get_values_ex-remove-unused-option.patch @@ -0,0 +1,66 @@ +From e32a5bd6fa76c7146a7024d42efeb26895337048 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 8 Nov 2017 14:04:40 +0100 +Subject: [PATCH 54/57] sysdb: be_refresh_get_values_ex() remove unused option +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The objectclass argument is not used in be_refresh_get_values_ex() +anymore. + +Related to https://pagure.io/SSSD/sssd/issue/3503 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit 0cce3d3ad14caf406303cf2ce6bf80171b708a93) +--- + src/providers/be_refresh.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c +index 81f2c5d1d368987bf9135fce730d917a32c1e24f..e8cf5da75847cd6ab647e91865b36ec6e4e59822 100644 +--- a/src/providers/be_refresh.c ++++ b/src/providers/be_refresh.c +@@ -32,7 +32,6 @@ + static errno_t be_refresh_get_values_ex(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + time_t period, +- const char *objectclass, + struct ldb_dn *base_dn, + const char *attr, + char ***_values) +@@ -96,21 +95,17 @@ static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx, + char ***_values) + { + struct ldb_dn *base_dn = NULL; +- const char *class = NULL; + errno_t ret; + + switch (type) { + case BE_REFRESH_TYPE_USERS: + base_dn = sysdb_user_base_dn(mem_ctx, domain); +- class = SYSDB_USER_CLASS; + break; + case BE_REFRESH_TYPE_GROUPS: + base_dn = sysdb_group_base_dn(mem_ctx, domain); +- class = SYSDB_GROUP_CLASS; + break; + case BE_REFRESH_TYPE_NETGROUPS: + base_dn = sysdb_netgroup_base_dn(mem_ctx, domain); +- class = SYSDB_NETGROUP_CLASS; + break; + case BE_REFRESH_TYPE_SENTINEL: + return ERR_INTERNAL; +@@ -121,7 +116,7 @@ static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx, + return ENOMEM; + } + +- ret = be_refresh_get_values_ex(mem_ctx, domain, period, class, ++ ret = be_refresh_get_values_ex(mem_ctx, domain, period, + base_dn, SYSDB_NAME, _values); + + talloc_free(base_dn); +-- +2.14.3 + diff --git a/SOURCES/0055-ssh-handle-binary-keys-correctly.patch b/SOURCES/0055-ssh-handle-binary-keys-correctly.patch deleted file mode 100644 index 05f87b1..0000000 --- a/SOURCES/0055-ssh-handle-binary-keys-correctly.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 3ba9f82ac428f509df33e509a39eb783480f5d19 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 16 Mar 2017 12:38:08 +0100 -Subject: [PATCH 55/60] ssh: handle binary keys correctly - -Related to https://pagure.io/SSSD/sssd/issue/3332 - -Reviewed-by: Jakub Hrozek ---- - src/responder/ssh/ssh_reply.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/src/responder/ssh/ssh_reply.c b/src/responder/ssh/ssh_reply.c -index 807f4ee079128b4a3f1719de890ffac6e0d5b2e0..7093e47253b5687bab387feed5299c2d0841d43c 100644 ---- a/src/responder/ssh/ssh_reply.c -+++ b/src/responder/ssh/ssh_reply.c -@@ -32,6 +32,11 @@ - #include "responder/common/cache_req/cache_req.h" - #include "responder/ssh/ssh_private.h" - -+/* Locally used flag for libldb's ldb_message_element structure to indicate -+ * binary data. Since the related data is only used in memory it is safe. If -+ * should be used with care if libldb's I/O operations are involved. */ -+#define SSS_EL_FLAG_BIN_DATA (1<<4) -+ - static errno_t get_valid_certs_keys(TALLOC_CTX *mem_ctx, - struct ssh_ctx *ssh_ctx, - struct ldb_message_element *el_cert, -@@ -148,7 +153,7 @@ static errno_t decode_and_add_base64_data(struct sss_packet *packet, - } - - for (d = 0; d < el->num_values; d++) { -- if (skip_base64_decode) { -+ if (skip_base64_decode || (el->flags & SSS_EL_FLAG_BIN_DATA)) { - key = el->values[d].data; - key_len = el->values[d].length; - } else { -@@ -233,6 +238,7 @@ ssh_get_output_keys(TALLOC_CTX *mem_ctx, - } - - if (elements[i] != NULL) { -+ elements[i]->flags |= SSS_EL_FLAG_BIN_DATA; - num_keys += elements[i]->num_values; - i++; - } --- -2.9.3 - diff --git a/SOURCES/0055-sysdb-do-not-use-objectClass-for-users-and-groups.patch b/SOURCES/0055-sysdb-do-not-use-objectClass-for-users-and-groups.patch new file mode 100644 index 0000000..4d94916 --- /dev/null +++ b/SOURCES/0055-sysdb-do-not-use-objectClass-for-users-and-groups.patch @@ -0,0 +1,758 @@ +From e4ba8c5c6c08f86d51485d49c27635d7079efe13 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 8 Nov 2017 15:14:58 +0100 +Subject: [PATCH 55/57] sysdb: do not use objectClass for users and groups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The majority of the object in the SSSD cache are users and groups. If +there are many user and groups in the cache the index objects of the +objectclass attributes 'user' and 'group' become large because the +must hold references to all objects of those object classes. + +As a result the management of these index objects becomes costly because +they must be parsed and split apart quite often. Additionally they are +mostly useless because user and groups are lookup up by more specific +attributes in general. + +Only when enumerating all user or groups this kind of index might be +useful. + +There are two way of removing this kind of index from the user and group +objects. Either by removing objectClass from the list of indexes and add +a new attribute to all other type of object we want and index for. Or by +replacing objectClass with a different attribute for the user and group +objects. After some testing I think the latter one is the more reliable +one and implemented it in this patch. + +Related to https://pagure.io/SSSD/sssd/issue/3503 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit 0e238c259c066cf997aaa940d33d6bda96c15925) +--- + src/db/sysdb.h | 10 ++-- + src/db/sysdb_init.c | 5 +- + src/db/sysdb_ops.c | 6 +-- + src/db/sysdb_search.c | 11 +++-- + src/db/sysdb_upgrade.c | 4 ++ + src/ldb_modules/memberof.c | 6 +-- + src/providers/ad/ad_pac.c | 2 +- + src/providers/ipa/ipa_id.c | 9 ++-- + src/providers/ipa/ipa_subdomains_ext_groups.c | 2 +- + src/providers/ipa/ipa_subdomains_id.c | 2 +- + src/providers/krb5/krb5_renew_tgt.c | 3 +- + src/providers/ldap/ldap_id_cleanup.c | 2 +- + src/providers/ldap/sdap_async_groups.c | 8 ++-- + src/providers/ldap/sdap_async_initgroups.c | 2 +- + src/providers/ldap/sdap_async_initgroups_ad.c | 2 +- + src/providers/ldap/sdap_async_nested_groups.c | 2 +- + .../common/cache_req/plugins/cache_req_common.c | 2 +- + src/responder/ifp/ifp_cache.c | 4 +- + src/responder/ifp/ifp_groups.c | 4 +- + src/responder/ifp/ifp_users.c | 2 +- + src/responder/nss/nss_cmd.c | 2 +- + src/responder/nss/nss_protocol_grent.c | 2 +- + src/responder/nss/nss_protocol_sid.c | 4 +- + src/tests/cmocka/test_ad_common.c | 2 +- + src/tests/cmocka/test_ipa_subdomains_server.c | 54 ++++++++++++++++------ + src/tests/sysdb-tests.c | 20 +++++--- + src/tools/sssctl/sssctl_cache.c | 3 +- + 27 files changed, 110 insertions(+), 65 deletions(-) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 4192f9085d941814eccd2ac60ce8fb6d4e1bfa67..fd18ecefed2b2c5f35060fa47fd160a8968e073b 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -192,9 +192,10 @@ + + #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)" + +-#define SYSDB_UC "objectclass="SYSDB_USER_CLASS +-#define SYSDB_GC "objectclass="SYSDB_GROUP_CLASS +-#define SYSDB_NC "objectclass="SYSDB_NETGROUP_CLASS ++#define SYSDB_OBJECTCATEGORY "objectCategory" ++#define SYSDB_UC SYSDB_OBJECTCATEGORY"="SYSDB_USER_CLASS ++#define SYSDB_GC SYSDB_OBJECTCATEGORY"="SYSDB_GROUP_CLASS ++#define SYSDB_NC SYSDB_OBJECTCLASS"="SYSDB_NETGROUP_CLASS + #define SYSDB_MPGC "|("SYSDB_UC")("SYSDB_GC")" + + #define SYSDB_PWNAM_FILTER "(&("SYSDB_UC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))" +@@ -227,7 +228,8 @@ + #define SYSDB_DEFAULT_ATTRS SYSDB_LAST_UPDATE, \ + SYSDB_CACHE_EXPIRE, \ + SYSDB_INITGR_EXPIRE, \ +- SYSDB_OBJECTCLASS ++ SYSDB_OBJECTCLASS, \ ++ SYSDB_OBJECTCATEGORY + + #define SYSDB_PW_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \ + SYSDB_GIDNUM, SYSDB_GECOS, \ +diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c +index e246a165ec1d654dba19aa771ed97bfc3a07f245..44a7918f603fe1368b7d81738666de6bb47b83d0 100644 +--- a/src/db/sysdb_init.c ++++ b/src/db/sysdb_init.c +@@ -31,11 +31,12 @@ + #define LDB_MODULES_PATH "LDB_MODULES_PATH" + + /* If an entry differs only in these attributes, they are written to +- * the timestamp cache only. In addition, objectclass is added so that +- * we can distinguish between users and groups. ++ * the timestamp cache only. In addition, objectclass/objectcategory is added ++ * so that we can distinguish between users and groups. + */ + const char *sysdb_ts_cache_attrs[] = { + SYSDB_OBJECTCLASS, ++ SYSDB_OBJECTCATEGORY, + SYSDB_LAST_UPDATE, + SYSDB_CACHE_EXPIRE, + SYSDB_ORIG_MODSTAMP, +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 1539c41c93e7d6ebd1e544abbb1707df5578cd72..024683317cab99743681db804f7026c8dbb33a38 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -958,7 +958,7 @@ static struct sysdb_attrs *ts_obj_attrs(TALLOC_CTX *mem_ctx, + return NULL; + } + +- ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS, oc); ++ ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCATEGORY, oc); + if (ret != EOK) { + talloc_free(attrs); + return NULL; +@@ -1667,7 +1667,7 @@ int sysdb_add_basic_user(struct sss_domain_info *domain, + ERROR_OUT(ret, ENOMEM, done); + } + +- ret = sysdb_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_USER_CLASS); ++ ret = sysdb_add_string(msg, SYSDB_OBJECTCATEGORY, SYSDB_USER_CLASS); + if (ret) goto done; + + ret = sysdb_add_string(msg, SYSDB_NAME, name); +@@ -2120,7 +2120,7 @@ int sysdb_add_basic_group(struct sss_domain_info *domain, + ERROR_OUT(ret, ENOMEM, done); + } + +- ret = sysdb_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS); ++ ret = sysdb_add_string(msg, SYSDB_OBJECTCATEGORY, SYSDB_GROUP_CLASS); + if (ret) goto done; + + ret = sysdb_add_string(msg, SYSDB_NAME, name); +diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c +index 8083966900429b268a3b984f1cad3d47d1099198..a6a81e23d257331614085403b4dca8ded860600b 100644 +--- a/src/db/sysdb_search.c ++++ b/src/db/sysdb_search.c +@@ -114,10 +114,11 @@ static errno_t merge_msg_ts_attrs(struct sysdb_ctx *sysdb, + return EIO; + } + +- /* Deliberately start from 1 in order to not merge objectclass and avoid +- * breaking MPGs where the OC might be made up ++ /* Deliberately start from 2 in order to not merge ++ * objectclass/objectcategory and avoid breaking MPGs where the OC might ++ * be made up + */ +- for (size_t c = 1; sysdb_ts_cache_attrs[c]; c++) { ++ for (size_t c = 2; sysdb_ts_cache_attrs[c]; c++) { + ret = merge_ts_attr(ts_msgs[0], sysdb_msg, + sysdb_ts_cache_attrs[c], attrs); + if (ret != EOK) { +@@ -751,7 +752,7 @@ static int mpg_convert(struct ldb_message *msg) + struct ldb_val *val = NULL; + int i; + +- el = ldb_msg_find_element(msg, "objectClass"); ++ el = ldb_msg_find_element(msg, SYSDB_OBJECTCATEGORY); + if (!el) return EINVAL; + + /* see if this is a user to convert to a group */ +@@ -2088,7 +2089,7 @@ errno_t sysdb_get_direct_parents(TALLOC_CTX *mem_ctx, + } + + member_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(%s=%s))", +- SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS, ++ SYSDB_OBJECTCATEGORY, SYSDB_GROUP_CLASS, + SYSDB_MEMBER, sanitized_dn); + if (!member_filter) { + ret = ENOMEM; +diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c +index 040c91ca6276e7c51a126eefe034aa5fe9d0433f..365d45f7ebd78523ca9ec4b9c2158cc09acb5489 100644 +--- a/src/db/sysdb_upgrade.c ++++ b/src/db/sysdb_upgrade.c +@@ -149,6 +149,7 @@ int sysdb_upgrade_01(struct ldb_context *ldb, const char **ver) + struct ldb_dn *mem_dn; + struct ldb_message *msg; + const struct ldb_val *val; ++ /* No change needed because this version has objectclass group */ + const char *filter = "(&(memberUid=*)(objectclass=group))"; + const char *attrs[] = { "memberUid", NULL }; + const char *mdn; +@@ -1041,6 +1042,7 @@ int sysdb_upgrade_10(struct sysdb_ctx *sysdb, struct sss_domain_info *domain, + struct ldb_message_element *memberof_el; + const char *name; + struct ldb_dn *basedn; ++ /* No change needed because version 10 has objectclass user */ + const char *filter = "(&(objectClass=user)(!(uidNumber=*))(memberOf=*))"; + const char *attrs[] = { "name", "memberof", NULL }; + struct upgrade_ctx *ctx; +@@ -2082,6 +2084,7 @@ static void qualify_users(struct upgrade_ctx *ctx, + struct sss_names_ctx *names, + struct ldb_dn *base_dn) + { ++ /* No change needed because this version has objectclass user */ + const char *user_filter = "objectclass=user"; + const char *user_name_attrs[] = { SYSDB_NAME, + SYSDB_NAME_ALIAS, +@@ -2107,6 +2110,7 @@ static void qualify_groups(struct upgrade_ctx *ctx, + struct sss_names_ctx *names, + struct ldb_dn *base_dn) + { ++ /* No change needed because this version has objectclass group */ + const char *group_filter = "objectclass=group"; + const char *group_name_attrs[] = { SYSDB_NAME, + SYSDB_NAME_ALIAS, +diff --git a/src/ldb_modules/memberof.c b/src/ldb_modules/memberof.c +index af7147ee7cc9299d4040d63a637373842dcee02a..327a38c5f75afcde1b997796afd1217d45acbde2 100644 +--- a/src/ldb_modules/memberof.c ++++ b/src/ldb_modules/memberof.c +@@ -31,7 +31,7 @@ + #define DB_USER_CLASS "user" + #define DB_GROUP_CLASS "group" + #define DB_CACHE_EXPIRE "dataExpireTimestamp" +-#define DB_OC "objectClass" ++#define DB_OC "objectCategory" + + #ifndef MAX + #define MAX(a,b) (((a) > (b)) ? (a) : (b)) +@@ -3928,7 +3928,7 @@ static int memberof_recompute_task(struct ldb_module *module, + { + struct ldb_context *ldb = ldb_module_get_ctx(module); + static const char *attrs[] = { DB_NAME, DB_MEMBEROF, NULL }; +- static const char *filter = "(objectclass=user)"; ++ static const char *filter = "("DB_OC"="DB_USER_CLASS")"; + struct mbof_rcmp_context *ctx; + struct ldb_request *src_req; + int ret; +@@ -4035,7 +4035,7 @@ static int mbof_rcmp_search_groups(struct mbof_rcmp_context *ctx) + struct ldb_context *ldb = ldb_module_get_ctx(ctx->module); + static const char *attrs[] = { DB_MEMBEROF, DB_MEMBERUID, + DB_NAME, DB_MEMBER, NULL }; +- static const char *filter = "(objectclass=group)"; ++ static const char *filter = "("DB_OC"="DB_GROUP_CLASS")"; + struct ldb_request *req; + int ret; + +diff --git a/src/providers/ad/ad_pac.c b/src/providers/ad/ad_pac.c +index ed002e1f9bf8f15d5b5d4b1c55392a34d18575e4..6b47462cf79a81b9258e3508914c043432edfed3 100644 +--- a/src/providers/ad/ad_pac.c ++++ b/src/providers/ad/ad_pac.c +@@ -31,7 +31,7 @@ static errno_t find_user_entry(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + struct dp_id_data *ar, + struct ldb_message **_msg) + { +- const char *user_attrs[] = { SYSDB_NAME, SYSDB_OBJECTCLASS, ++ const char *user_attrs[] = { SYSDB_NAME, SYSDB_OBJECTCATEGORY, + SYSDB_PAC_BLOB, SYSDB_PAC_BLOB_EXPIRE, + NULL }; + struct ldb_message *msg; +diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c +index 5044577f0faa95b19de9233240e92aa60f029774..8f8759f64b758aae7e45c88588e97a1bcf16ad79 100644 +--- a/src/providers/ipa/ipa_id.c ++++ b/src/providers/ipa/ipa_id.c +@@ -431,7 +431,8 @@ static errno_t ipa_id_get_group_uuids(TALLOC_CTX *mem_ctx, + } + + filter = talloc_asprintf(tmp_ctx, +- "(&(objectclass=%s)(!(%s=*))(%s=*))", ++ "(&(%s=%s)(!(%s=*))(%s=*))", ++ SYSDB_OBJECTCATEGORY, + SYSDB_GROUP_CLASS, SYSDB_OVERRIDE_DN, + SYSDB_UUID); + if (filter == NULL) { +@@ -733,7 +734,7 @@ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq) + const char *attrs[] = { SYSDB_NAME, + SYSDB_UIDNUM, + SYSDB_SID_STR, +- SYSDB_OBJECTCLASS, ++ SYSDB_OBJECTCATEGORY, + SYSDB_UUID, + SYSDB_GHOST, + SYSDB_HOMEDIR, +@@ -819,7 +820,7 @@ static int ipa_id_get_account_info_post_proc_step(struct tevent_req *req) + struct ipa_id_get_account_info_state *state = tevent_req_data(req, + struct ipa_id_get_account_info_state); + +- class = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_OBJECTCLASS, ++ class = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_OBJECTCATEGORY, + NULL); + if (class == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find an objectclass.\n"); +@@ -957,7 +958,7 @@ static void ipa_id_get_account_info_done(struct tevent_req *subreq) + goto fail; + } + +- class = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_OBJECTCLASS, ++ class = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_OBJECTCATEGORY, + NULL); + if (class == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find an objectclass.\n"); +diff --git a/src/providers/ipa/ipa_subdomains_ext_groups.c b/src/providers/ipa/ipa_subdomains_ext_groups.c +index 0359e0dedeef8db0da71d16a6f0044e43a7a9840..9e1d6c3a9bdeda56b421a2dc9198dff0b84c54ce 100644 +--- a/src/providers/ipa/ipa_subdomains_ext_groups.c ++++ b/src/providers/ipa/ipa_subdomains_ext_groups.c +@@ -940,7 +940,7 @@ search_user_or_group_by_sid_str(TALLOC_CTX *mem_ctx, + const char *attrs[] = { SYSDB_NAME, + SYSDB_SID_STR, + SYSDB_ORIG_DN, +- SYSDB_OBJECTCLASS, ++ SYSDB_OBJECTCATEGORY, + SYSDB_CACHE_EXPIRE, + NULL }; + TALLOC_CTX *tmp_ctx = NULL; +diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c +index 3530af94ef59397db72465fcb0c4a03117a4d8bd..2ba9813a44b4d914d9c2ef7a1a7504546f52954c 100644 +--- a/src/providers/ipa/ipa_subdomains_id.c ++++ b/src/providers/ipa/ipa_subdomains_id.c +@@ -888,7 +888,7 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + struct ldb_message_element *msg_el = NULL; + size_t c; + +- msg_el = ldb_msg_find_element(msg, SYSDB_OBJECTCLASS); ++ msg_el = ldb_msg_find_element(msg, SYSDB_OBJECTCATEGORY); + if (msg_el == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_find_element failed.\n"); + ret = ENOENT; +diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c +index ea6b39deb8dacdfa9211058a54a57b6e9f6b7d9d..549c08c6f105276fa9913568c228d3ff627623ae 100644 +--- a/src/providers/krb5/krb5_renew_tgt.c ++++ b/src/providers/krb5/krb5_renew_tgt.c +@@ -385,8 +385,7 @@ static errno_t check_ccache_files(struct renew_tgt_ctx *renew_tgt_ctx) + { + TALLOC_CTX *tmp_ctx; + int ret; +- const char *ccache_filter = "(&("SYSDB_CCACHE_FILE"=*)" \ +- "("SYSDB_OBJECTCLASS"="SYSDB_USER_CLASS"))"; ++ const char *ccache_filter = "(&("SYSDB_CCACHE_FILE"=*)("SYSDB_UC"))"; + const char *ccache_attrs[] = { SYSDB_CCACHE_FILE, SYSDB_UPN, SYSDB_NAME, + SYSDB_CANONICAL_UPN, NULL }; + size_t msgs_count = 0; +diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c +index c85ce45918cf938a95ff85c31bfe0541f9ddd052..8c0f0c18ba587e9bbfec144abe9c172cd5e0465b 100644 +--- a/src/providers/ldap/ldap_id_cleanup.c ++++ b/src/providers/ldap/ldap_id_cleanup.c +@@ -438,7 +438,7 @@ static int cleanup_groups(TALLOC_CTX *memctx, + */ + gid = (gid_t) ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0); + subfilter = talloc_asprintf(tmpctx, "(&(%s=%s)(|(%s=%s)(%s=%lu)))", +- SYSDB_OBJECTCLASS, SYSDB_USER_CLASS, ++ SYSDB_OBJECTCATEGORY, SYSDB_USER_CLASS, + SYSDB_MEMBEROF, sanitized_dn, + SYSDB_GIDNUM, (long unsigned) gid); + } else { +diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c +index 536e3f13744c5350eed518c9bd35fd89e0899dc6..b1cfb7e4a4c054e5d365da5fca65da27c9ef5461 100644 +--- a/src/providers/ldap/sdap_async_groups.c ++++ b/src/providers/ldap/sdap_async_groups.c +@@ -39,7 +39,7 @@ static int sdap_find_entry_by_origDN(TALLOC_CTX *memctx, + bool *_is_group) + { + TALLOC_CTX *tmpctx; +- const char *attrs[] = {SYSDB_OBJECTCLASS, NULL}; ++ const char *attrs[] = {SYSDB_OBJECTCLASS, SYSDB_OBJECTCATEGORY, NULL}; + struct ldb_dn *base_dn; + char *filter; + struct ldb_message **msgs; +@@ -90,11 +90,11 @@ static int sdap_find_entry_by_origDN(TALLOC_CTX *memctx, + } + + if (_is_group != NULL) { +- objectclass = ldb_msg_find_attr_as_string(msgs[0], SYSDB_OBJECTCLASS, ++ objectclass = ldb_msg_find_attr_as_string(msgs[0], SYSDB_OBJECTCATEGORY, + NULL); + if (objectclass == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "An antry without a %s?\n", +- SYSDB_OBJECTCLASS); ++ DEBUG(SSSDBG_OP_FAILURE, "An entry without a %s?\n", ++ SYSDB_OBJECTCATEGORY); + ret = EINVAL; + goto done; + } +diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c +index a33975cde4bc359cfe8395c0de04fd1774b8763d..f8a84474749e08349b539c774d68c876167cfdf1 100644 +--- a/src/providers/ldap/sdap_async_initgroups.c ++++ b/src/providers/ldap/sdap_async_initgroups.c +@@ -2341,7 +2341,7 @@ static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req) + } + + ret = sysdb_attrs_get_string(state->groups[state->group_iter], +- SYSDB_OBJECTCLASS, &class); ++ SYSDB_OBJECTCATEGORY, &class); + if (ret == EOK) { + /* If there is a objectClass attribute the object is coming from the + * cache and the name attribute of the object already has the primary +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index 2831be9776293260aeec0e2ff85160f1938bdb32..61aa69a2dfbe22cac37a5b7fddc07473527e5de5 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -1606,7 +1606,7 @@ sdap_ad_get_domain_local_groups_parse_parents(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sysdb_attrs_get_string(gr->group, SYSDB_OBJECTCLASS, &class); ++ ret = sysdb_attrs_get_string(gr->group, SYSDB_OBJECTCATEGORY, &class); + if (ret != EOK) { + /* If objectclass is missing gr->group is a nested parent found during + * the nested group lookup. It might not already stored in the cache. +diff --git a/src/providers/ldap/sdap_async_nested_groups.c b/src/providers/ldap/sdap_async_nested_groups.c +index 9271d8cfe38d11fb1ea14960a997f0deee175b27..b1f9753d7cdf5f6e278c54394d4f306cc21a42ab 100644 +--- a/src/providers/ldap/sdap_async_nested_groups.c ++++ b/src/providers/ldap/sdap_async_nested_groups.c +@@ -1686,7 +1686,7 @@ static errno_t sdap_nested_group_get_ipa_user(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sysdb_attrs_add_string(user, SYSDB_OBJECTCLASS, SYSDB_USER_CLASS); ++ ret = sysdb_attrs_add_string(user, SYSDB_OBJECTCATEGORY, SYSDB_USER_CLASS); + if (ret != EOK) { + goto done; + } +diff --git a/src/responder/common/cache_req/plugins/cache_req_common.c b/src/responder/common/cache_req/plugins/cache_req_common.c +index b80f310feeebbdbc824db441ff5313632585d3fb..1f86258bc14c7a382712959f24a4ec4c153572d4 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_common.c ++++ b/src/responder/common/cache_req/plugins/cache_req_common.c +@@ -53,7 +53,7 @@ cache_req_well_known_sid_msg(TALLOC_CTX *mem_ctx, + goto done; + } + +- ldberr = ldb_msg_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS); ++ ldberr = ldb_msg_add_string(msg, SYSDB_OBJECTCATEGORY, SYSDB_GROUP_CLASS); + if (ldberr != LDB_SUCCESS) { + goto done; + } +diff --git a/src/responder/ifp/ifp_cache.c b/src/responder/ifp/ifp_cache.c +index 8ea2d8008d40bc0a28f3871b511690af677c5c5e..f84cb14de48b5c86acb027f275edded4eb73e192 100644 +--- a/src/responder/ifp/ifp_cache.c ++++ b/src/responder/ifp/ifp_cache.c +@@ -100,7 +100,7 @@ ifp_cache_get_cached_objects(TALLOC_CTX *mem_ctx, + errno_t ret; + int ldb_ret; + int i; +- const char *attrs[] = {SYSDB_OBJECTCLASS, SYSDB_UIDNUM, ++ const char *attrs[] = {SYSDB_OBJECTCATEGORY, SYSDB_UIDNUM, + SYSDB_GIDNUM, NULL}; + + tmp_ctx = talloc_new(NULL); +@@ -117,7 +117,7 @@ ifp_cache_get_cached_objects(TALLOC_CTX *mem_ctx, + + ldb_ret = ldb_search(sysdb_ctx_get_ldb(domain->sysdb), tmp_ctx, &result, + base_dn, LDB_SCOPE_SUBTREE, attrs, +- "(&(objectClass=%s)(%s=TRUE))", class, ++ "(&(%s=%s)(%s=TRUE))", SYSDB_OBJECTCATEGORY, class, + SYSDB_IFP_CACHED); + if (ldb_ret != LDB_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to search the cache\n"); +diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c +index 7503254238eafdafbe2d90fbf7416587be49e1b7..b274b8f52d7908165acc10b91a7d6afe638f1a82 100644 +--- a/src/responder/ifp/ifp_groups.c ++++ b/src/responder/ifp/ifp_groups.c +@@ -841,7 +841,7 @@ ifp_groups_group_get_members(TALLOC_CTX *mem_ctx, + int num_groups; + int i; + errno_t ret; +- const char *attrs[] = {SYSDB_OBJECTCLASS, SYSDB_UIDNUM, ++ const char *attrs[] = {SYSDB_OBJECTCATEGORY, SYSDB_UIDNUM, + SYSDB_GIDNUM, NULL}; + + tmp_ctx = talloc_new(NULL); +@@ -888,7 +888,7 @@ ifp_groups_group_get_members(TALLOC_CTX *mem_ctx, + num_users = 0; + num_groups = 0; + for (i = 0; i < num_members; i++) { +- class = ldb_msg_find_attr_as_string(members[i], SYSDB_OBJECTCLASS, ++ class = ldb_msg_find_attr_as_string(members[i], SYSDB_OBJECTCATEGORY, + NULL); + if (class == NULL) { + ret = ERR_INTERNAL; +diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c +index 86a1f43a2c6e7d785c9d34e350c71f242ff7182f..cb342a245ef6545168a7a60c252505f50576fdf7 100644 +--- a/src/responder/ifp/ifp_users.c ++++ b/src/responder/ifp/ifp_users.c +@@ -1441,7 +1441,7 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, + } + + filter = talloc_asprintf(sbus_req, "(&(%s=%s)(%s=%s))", +- SYSDB_OBJECTCLASS, SYSDB_USER_CLASS, ++ SYSDB_OBJECTCATEGORY, SYSDB_USER_CLASS, + SYSDB_NAME, name); + if (filter == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n"); +diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c +index 545257a0be7e91e9de767a57848bb77c5791db4e..956ee53cb88dd24faaa95ac39c8d9540af66cfb2 100644 +--- a/src/responder/nss/nss_cmd.c ++++ b/src/responder/nss/nss_cmd.c +@@ -1148,7 +1148,7 @@ static errno_t nss_cmd_getorigbyname(struct cli_ctx *cli_ctx) + errno_t ret; + struct nss_ctx *nss_ctx; + const char **attrs; +- static const char *defattrs[] = { SYSDB_NAME, SYSDB_OBJECTCLASS, ++ static const char *defattrs[] = { SYSDB_NAME, SYSDB_OBJECTCATEGORY, + SYSDB_SID_STR, + ORIGINALAD_PREFIX SYSDB_NAME, + ORIGINALAD_PREFIX SYSDB_UIDNUM, +diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c +index 6f6ae57dd97b000ad3cf174b0f649d46981563e2..3550c3f0d375b305d4dbdf3ea19613696448da35 100644 +--- a/src/responder/nss/nss_protocol_grent.c ++++ b/src/responder/nss/nss_protocol_grent.c +@@ -33,7 +33,7 @@ nss_get_grent(TALLOC_CTX *mem_ctx, + errno_t ret; + + /* Check object class. */ +- if (!ldb_msg_check_string_attribute(msg, "objectClass", ++ if (!ldb_msg_check_string_attribute(msg, SYSDB_OBJECTCATEGORY, + SYSDB_GROUP_CLASS)) { + DEBUG(SSSDBG_MINOR_FAILURE, "Wrong object (%s) found on stack!\n", + ldb_dn_get_linearized(msg->dn)); +diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c +index 61357c2bf92e2f15d978b64a15ad5bd5aa354445..3f60967d750eea3135257ccb597efaa5aa1e2de3 100644 +--- a/src/responder/nss/nss_protocol_sid.c ++++ b/src/responder/nss/nss_protocol_sid.c +@@ -30,9 +30,9 @@ find_sss_id_type(struct ldb_message *msg, + struct ldb_message_element *el; + struct ldb_val *val = NULL; + +- el = ldb_msg_find_element(msg, SYSDB_OBJECTCLASS); ++ el = ldb_msg_find_element(msg, SYSDB_OBJECTCATEGORY); + if (el == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "Objectclass attribute not found.\n"); ++ DEBUG(SSSDBG_OP_FAILURE, "Objectcategory attribute not found.\n"); + return EINVAL; + } + +diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c +index 3187af1b004cf3d1ffc1746950faa842f3a05fbc..80b3bb5599a95578b7734d5dfcd20a2a7428a084 100644 +--- a/src/tests/cmocka/test_ad_common.c ++++ b/src/tests/cmocka/test_ad_common.c +@@ -336,7 +336,7 @@ static void test_ad_get_pac_data_from_user_entry(void **state) + + ret = ldb_msg_add_string(user_msg, SYSDB_NAME, "username"); + assert_int_equal(ret, EOK); +- ret = ldb_msg_add_string(user_msg, SYSDB_OBJECTCLASS, "user"); ++ ret = ldb_msg_add_string(user_msg, SYSDB_OBJECTCATEGORY, SYSDB_USER_CLASS); + assert_int_equal(ret, EOK); + ret = ldb_msg_add_string(user_msg, SYSDB_PAC_BLOB_EXPIRE, "12345"); + assert_int_equal(ret, EOK); +diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c +index eccfc2fe1e2a224b2cec8ea3184796a23d32febe..1e492e86c1caf26d8890bfa37ebb21321afca366 100644 +--- a/src/tests/cmocka/test_ipa_subdomains_server.c ++++ b/src/tests/cmocka/test_ipa_subdomains_server.c +@@ -455,6 +455,8 @@ static void test_ipa_server_create_trusts_twoway(struct tevent_req *req) + tevent_req_callback_data(req, struct trust_test_ctx); + errno_t ret; + struct sss_domain_info *child_dom; ++ struct ipa_ad_server_ctx *s_trust; ++ struct ipa_ad_server_ctx *c_trust; + + ret = ipa_server_create_trusts_recv(req); + talloc_zfree(req); +@@ -462,9 +464,18 @@ static void test_ipa_server_create_trusts_twoway(struct tevent_req *req) + + /* Trust object should be around now */ + assert_non_null(test_ctx->ipa_ctx->server_mode->trusts); ++ assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next); + ++ if (strcmp(test_ctx->ipa_ctx->server_mode->trusts->dom->name, ++ SUBDOM_NAME) == 0) { ++ s_trust = test_ctx->ipa_ctx->server_mode->trusts; ++ c_trust = test_ctx->ipa_ctx->server_mode->trusts->next; ++ } else { ++ s_trust = test_ctx->ipa_ctx->server_mode->trusts->next; ++ c_trust = test_ctx->ipa_ctx->server_mode->trusts; ++ } + /* Two-way trusts should use the system realm */ +- assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts, ++ assert_trust_object(c_trust, + CHILD_NAME, + DOM_REALM, + CHILD_SID, +@@ -472,9 +483,8 @@ static void test_ipa_server_create_trusts_twoway(struct tevent_req *req) + TEST_AUTHID, + DOM_REALM); + +- assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next); + +- assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next, ++ assert_trust_object(s_trust, + SUBDOM_NAME, + DOM_REALM, + SUBDOM_SID, +@@ -523,6 +533,8 @@ static void test_ipa_server_trust_init(void **state) + errno_t ret; + struct tevent_timer *timeout_handler; + struct timeval tv; ++ struct ipa_ad_server_ctx *s_trust; ++ struct ipa_ad_server_ctx *c_trust; + + add_test_2way_subdomains(test_ctx); + +@@ -537,13 +549,21 @@ static void test_ipa_server_trust_init(void **state) + ret = test_ev_loop(test_ctx->tctx); + assert_int_equal(ret, ERR_OK); + +- assert_non_null(test_ctx->ipa_ctx->server_mode->trusts); +- + /* Trust object should be around now */ + assert_non_null(test_ctx->ipa_ctx->server_mode->trusts); ++ assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next); ++ ++ if (strcmp(test_ctx->ipa_ctx->server_mode->trusts->dom->name, ++ SUBDOM_NAME) == 0) { ++ s_trust = test_ctx->ipa_ctx->server_mode->trusts; ++ c_trust = test_ctx->ipa_ctx->server_mode->trusts->next; ++ } else { ++ s_trust = test_ctx->ipa_ctx->server_mode->trusts->next; ++ c_trust = test_ctx->ipa_ctx->server_mode->trusts; ++ } + + /* Two-way trusts should use the system realm */ +- assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts, ++ assert_trust_object(c_trust, + CHILD_NAME, + DOM_REALM, + CHILD_SID, +@@ -551,9 +571,7 @@ static void test_ipa_server_trust_init(void **state) + TEST_AUTHID, + DOM_REALM); + +- assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next); +- +- assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next, ++ assert_trust_object(s_trust, + SUBDOM_NAME, + DOM_REALM, + SUBDOM_SID, +@@ -708,6 +726,8 @@ static void test_ipa_server_create_trusts_oneway(struct tevent_req *req) + struct trust_test_ctx *test_ctx = \ + tevent_req_callback_data(req, struct trust_test_ctx); + errno_t ret; ++ struct ipa_ad_server_ctx *s_trust; ++ struct ipa_ad_server_ctx *c_trust; + + ret = ipa_server_create_trusts_recv(req); + talloc_zfree(req); +@@ -720,9 +740,19 @@ static void test_ipa_server_create_trusts_oneway(struct tevent_req *req) + + /* Trust object should be around now */ + assert_non_null(test_ctx->ipa_ctx->server_mode->trusts); ++ assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next); ++ ++ if (strcmp(test_ctx->ipa_ctx->server_mode->trusts->dom->name, ++ SUBDOM_NAME) == 0) { ++ s_trust = test_ctx->ipa_ctx->server_mode->trusts; ++ c_trust = test_ctx->ipa_ctx->server_mode->trusts->next; ++ } else { ++ s_trust = test_ctx->ipa_ctx->server_mode->trusts->next; ++ c_trust = test_ctx->ipa_ctx->server_mode->trusts; ++ } + + assert_trust_object( +- test_ctx->ipa_ctx->server_mode->trusts, ++ c_trust, + CHILD_NAME, /* AD domain name */ + CHILD_REALM, /* AD realm can be child if SDAP realm is parent's */ + CHILD_SID, +@@ -730,10 +760,8 @@ static void test_ipa_server_create_trusts_oneway(struct tevent_req *req) + ONEWAY_PRINC, /* Principal shared with parent AD dom */ + SUBDOM_REALM); /* SDAP realm must be AD root domain */ + +- assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next); +- + /* Here all properties point to the AD domain */ +- assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next, ++ assert_trust_object(s_trust, + SUBDOM_NAME, + SUBDOM_REALM, + SUBDOM_SID, +diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c +index 4652661087238c18f7fabb398d054db99f77d6cf..fc9936968bcde8370c7054ba303de4463b35e15a 100644 +--- a/src/tests/sysdb-tests.c ++++ b/src/tests/sysdb-tests.c +@@ -503,7 +503,7 @@ static int test_search_all_users(struct test_data *data) + } + + ret = sysdb_search_entry(data, data->ctx->sysdb, base_dn, +- LDB_SCOPE_SUBTREE, "objectClass=user", ++ LDB_SCOPE_SUBTREE, SYSDB_UC, + data->attrlist, &data->msgs_count, &data->msgs); + return ret; + } +@@ -2219,6 +2219,7 @@ START_TEST (test_sysdb_search_all_users) + struct test_data *data; + int ret; + int i; ++ int j; + char *uid_str; + + /* Setup */ +@@ -2253,8 +2254,15 @@ START_TEST (test_sysdb_search_all_users) + "wrong number of values, found [%d] expected [1]", + data->msgs[i]->elements[0].num_values); + +- uid_str = talloc_asprintf(data, "%d", 27010 + i); +- fail_unless(uid_str != NULL, "talloc_asprintf failed."); ++ for (j = 0; j < data->msgs_count; j++) { ++ uid_str = talloc_asprintf(data, "%d", 27010 + j); ++ fail_unless(uid_str != NULL, "talloc_asprintf failed."); ++ if (strncmp(uid_str, ++ (char *) data->msgs[i]->elements[0].values[0].data, ++ data->msgs[i]->elements[0].values[0].length) == 0) { ++ break; ++ } ++ } + fail_unless(strncmp(uid_str, + (char *) data->msgs[i]->elements[0].values[0].data, + data->msgs[i]->elements[0].values[0].length) == 0, +@@ -4411,7 +4419,7 @@ START_TEST(test_SSS_LDB_SEARCH) + + /* Non-empty filter */ + SSS_LDB_SEARCH(ret, test_ctx->sysdb->ldb, test_ctx, &res, group_dn, +- LDB_SCOPE_BASE, NULL, "objectClass=group"); ++ LDB_SCOPE_BASE, NULL, SYSDB_GC); + + fail_unless(ret == EOK, "SSS_LDB_SEARCH error [%d][%s]", + ret, strerror(ret)); +@@ -5203,7 +5211,7 @@ START_TEST (test_sysdb_search_return_ENOENT) + + ret = sysdb_search_entry(test_ctx, test_ctx->sysdb, + user_dn, LDB_SCOPE_SUBTREE, +- "objectClass=user", NULL, ++ SYSDB_UC, NULL, + &count, &msgs); + fail_unless(ret == ENOENT, "sysdb_search_entry failed: %d, %s", + ret, strerror(ret)); +@@ -5215,7 +5223,7 @@ START_TEST (test_sysdb_search_return_ENOENT) + data->username); + fail_if(user_dn == NULL, "sysdb_user_dn failed"); + SSS_LDB_SEARCH(ret, test_ctx->sysdb->ldb, test_ctx, &res, user_dn, +- LDB_SCOPE_BASE, NULL, "objectClass=user"); ++ LDB_SCOPE_BASE, NULL, SYSDB_UC); + + fail_unless(ret == ENOENT, "SSS_LDB_SEARCH failed: %d, %s", + ret, strerror(ret)); +diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c +index 80f65bb55df42d0b123023bb9b1efdb2353b8e20..42a2a60fd31631b3c86d17ddbdd8027a8468366d 100644 +--- a/src/tools/sssctl/sssctl_cache.c ++++ b/src/tools/sssctl/sssctl_cache.c +@@ -335,7 +335,8 @@ static const char *sssctl_create_filter(TALLOC_CTX *mem_ctx, + talloc_free(filter_value_old); + } + +- filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(|(%s=%s)(%s=%s)))", ++ filter = talloc_asprintf(mem_ctx, "(&(%s=%s)(|(%s=%s)(%s=%s)))", ++ obj_type == CACHED_NETGROUP ? SYSDB_OBJECTCLASS : SYSDB_OBJECTCATEGORY, + class, attr_name, filter_value, + SYSDB_NAME_ALIAS, filter_value); + +-- +2.14.3 + diff --git a/SOURCES/0056-ssh-add-support-for-certificates-from-non-default-vi.patch b/SOURCES/0056-ssh-add-support-for-certificates-from-non-default-vi.patch deleted file mode 100644 index cbeb244..0000000 --- a/SOURCES/0056-ssh-add-support-for-certificates-from-non-default-vi.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 61c2661fe7445531f53ef298a98a21ae0278397c Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 16 Mar 2017 13:00:48 +0100 -Subject: [PATCH 56/60] ssh: add support for certificates from non-default - views - -Reviewed-by: Jakub Hrozek ---- - src/responder/ssh/ssh_reply.c | 20 +++++++++++++++++++- - 1 file changed, 19 insertions(+), 1 deletion(-) - -diff --git a/src/responder/ssh/ssh_reply.c b/src/responder/ssh/ssh_reply.c -index 7093e47253b5687bab387feed5299c2d0841d43c..1bb9d331868cc18488718c24fd82f32af780b525 100644 ---- a/src/responder/ssh/ssh_reply.c -+++ b/src/responder/ssh/ssh_reply.c -@@ -204,7 +204,7 @@ ssh_get_output_keys(TALLOC_CTX *mem_ctx, - uint32_t i = 0; - errno_t ret; - -- elements = talloc_zero_array(mem_ctx, struct ldb_message_element *, 5); -+ elements = talloc_zero_array(mem_ctx, struct ldb_message_element *, 6); - if (elements == NULL) { - return ENOMEM; - } -@@ -244,6 +244,24 @@ ssh_get_output_keys(TALLOC_CTX *mem_ctx, - } - } - -+ if (DOM_HAS_VIEWS(domain)) { -+ user_cert = ldb_msg_find_element(msg, OVERRIDE_PREFIX SYSDB_USER_CERT); -+ if (user_cert != NULL) { -+ ret = get_valid_certs_keys(elements, ssh_ctx, user_cert, -+ &elements[i]); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "get_valid_certs_keys failed.\n"); -+ goto done; -+ } -+ -+ if (elements[i] != NULL) { -+ elements[i]->flags |= SSS_EL_FLAG_BIN_DATA; -+ num_keys += elements[i]->num_values; -+ i++; -+ } -+ } -+ } -+ - *_elements = elements; - *_num_keys = num_keys; - --- -2.9.3 - diff --git a/SOURCES/0056-sysdb-do-not-use-LDB_SCOPE_ONELEVEL.patch b/SOURCES/0056-sysdb-do-not-use-LDB_SCOPE_ONELEVEL.patch new file mode 100644 index 0000000..e0f0758 --- /dev/null +++ b/SOURCES/0056-sysdb-do-not-use-LDB_SCOPE_ONELEVEL.patch @@ -0,0 +1,83 @@ +From c36d5d56e62f879dbc1c58155097dfc26746a7f4 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 14 Nov 2017 13:09:18 +0100 +Subject: [PATCH 56/57] sysdb: do not use LDB_SCOPE_ONELEVEL +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently the index for one-level searches is a huge blob which maps all +parents with all it children. Handling this blob is costly and since all +searches using LDB_SCOPE_ONELEVEL also have a filter with indexed +attributes a sub-tree search would be more efficient. But since libldb +currently first looks at the scope and hence use the one-level index +blob we have to explicitly use LDB_SCOPE_SUBTREE in the callers to use +the more efficient attribute based inxed. + +Related to https://pagure.io/SSSD/sssd/issue/3503 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 98195e591c4d97caa6125e8214879660b740973f) +--- + src/db/sysdb_autofs.c | 2 +- + src/db/sysdb_ranges.c | 2 +- + src/db/sysdb_subdomains.c | 2 +- + src/responder/ifp/ifp_users.c | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/db/sysdb_autofs.c b/src/db/sysdb_autofs.c +index b3e9b4ec83b66ec65a72ab7a3180106e2293d8a5..89803a778c370c899611ee5e15b7ae1a48e82cb9 100644 +--- a/src/db/sysdb_autofs.c ++++ b/src/db/sysdb_autofs.c +@@ -384,7 +384,7 @@ sysdb_autofs_entries_by_map(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sysdb_search_entry(tmp_ctx, domain->sysdb, mapdn, LDB_SCOPE_ONELEVEL, ++ ret = sysdb_search_entry(tmp_ctx, domain->sysdb, mapdn, LDB_SCOPE_SUBTREE, + filter, attrs, &count, &msgs); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb search failed: %d\n", ret); +diff --git a/src/db/sysdb_ranges.c b/src/db/sysdb_ranges.c +index 511e4785d9aa68b2a33b440e1c5ee62e5ccf7ce4..be3a0d37220f833d27417808ddfef0e74c0ba9b2 100644 +--- a/src/db/sysdb_ranges.c ++++ b/src/db/sysdb_ranges.c +@@ -71,7 +71,7 @@ errno_t sysdb_get_ranges(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, + goto done; + } + ret = ldb_search(sysdb->ldb, tmp_ctx, &res, +- basedn, LDB_SCOPE_ONELEVEL, ++ basedn, LDB_SCOPE_SUBTREE, + attrs, "objectclass=%s", SYSDB_ID_RANGE_CLASS); + if (ret != LDB_SUCCESS) { + ret = EIO; +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index 353561765904efe4bd698c38949a1b290ecf0b80..0dd05c24c963f12a28ef6f6b64dc40faa7fcc649 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -338,7 +338,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain, + goto done; + } + ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, +- basedn, LDB_SCOPE_ONELEVEL, ++ basedn, LDB_SCOPE_SUBTREE, + attrs, "objectclass=%s", SYSDB_SUBDOMAIN_CLASS); + if (ret != LDB_SUCCESS) { + ret = EIO; +diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c +index cb342a245ef6545168a7a60c252505f50576fdf7..f66587b8cf81a555dd1cb7aff12e0c8347c250b1 100644 +--- a/src/responder/ifp/ifp_users.c ++++ b/src/responder/ifp/ifp_users.c +@@ -1449,7 +1449,7 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, + } + + ret = sysdb_search_entry(sbus_req, domain->sysdb, basedn, +- LDB_SCOPE_ONELEVEL, filter, ++ LDB_SCOPE_SUBTREE, filter, + extra, &count, &user); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user [%d]: %s\n", +-- +2.14.3 + diff --git a/SOURCES/0057-krb5-return-to-responder-that-pkinit-is-not-availabl.patch b/SOURCES/0057-krb5-return-to-responder-that-pkinit-is-not-availabl.patch deleted file mode 100644 index db56ae9..0000000 --- a/SOURCES/0057-krb5-return-to-responder-that-pkinit-is-not-availabl.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 01ed8c7d7fcd9090d0953f85ef0604cbcad4f48b Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 16 Mar 2017 20:43:08 +0100 -Subject: [PATCH 57/60] krb5: return to responder that pkinit is not available -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If pkinit is not available for a user but other authentication methods -are SSSD should still fall back to local certificate based -authentication if Smartcard credentials are provided. - -Resolves https://pagure.io/SSSD/sssd/issue/3343 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - src/providers/krb5/krb5_child.c | 17 +++++++++++++---- - 1 file changed, 13 insertions(+), 4 deletions(-) - -diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c -index 777a25f2a0ea434dde12d2396f6a35c2a1b86cd0..a4128dda6b0861a95dba223047d66c4158b1afb6 100644 ---- a/src/providers/krb5/krb5_child.c -+++ b/src/providers/krb5/krb5_child.c -@@ -42,6 +42,10 @@ - - #define SSSD_KRB5_CHANGEPW_PRINCIPAL "kadmin/changepw" - -+#define IS_SC_AUTHTOK(tok) ( \ -+ sss_authtok_get_type((tok)) == SSS_AUTHTOK_TYPE_SC_PIN \ -+ || sss_authtok_get_type((tok)) == SSS_AUTHTOK_TYPE_SC_KEYPAD) -+ - enum k5c_fast_opt { - K5C_FAST_NEVER, - K5C_FAST_TRY, -@@ -1529,12 +1533,17 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - * pre-auth module is missing or no Smartcard is inserted and only - * pkinit is available KRB5_PREAUTH_FAILED is returned. - * ERR_NO_AUTH_METHOD_AVAILABLE is used to indicate to the -- * frontend that local authentication might be tried. */ -+ * frontend that local authentication might be tried. -+ * Same is true if Smartcard credentials are given but only other -+ * authentication methods are available. */ - if (kr->pd->cmd == SSS_PAM_AUTHENTICATE - && kerr == KRB5_PREAUTH_FAILED -- && kr->password_prompting == false -- && kr->otp == false -- && kr->pkinit_prompting == false) { -+ && kr->pkinit_prompting == false -+ && (( kr->password_prompting == false -+ && kr->otp == false) -+ || ((kr->otp == true -+ || kr->password_prompting == true) -+ && IS_SC_AUTHTOK(kr->pd->authtok))) ) { - return ERR_NO_AUTH_METHOD_AVAILABLE; - } - return kerr; --- -2.9.3 - diff --git a/SOURCES/0057-sysdb-remove-IDXONE-and-objectClass-from-users-and-g.patch b/SOURCES/0057-sysdb-remove-IDXONE-and-objectClass-from-users-and-g.patch new file mode 100644 index 0000000..278541e --- /dev/null +++ b/SOURCES/0057-sysdb-remove-IDXONE-and-objectClass-from-users-and-g.patch @@ -0,0 +1,384 @@ +From 0f907d8501387ec32dbb00e1c38d5da25e698f90 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 14 Nov 2017 13:14:14 +0100 +Subject: [PATCH 57/57] sysdb: remove IDXONE and objectClass from users and + groups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch does the needed sysdb update for the previous to patches. It +removes the one-level search index IDXONE and replaces objectClass with +objectCategory in the user and group objects. + +Related to https://pagure.io/SSSD/sssd/issue/3503 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit 2927da49dd8a16fff6312d89ad43cc355655800c) +--- + src/db/sysdb_init.c | 52 +++++++++++- + src/db/sysdb_private.h | 11 ++- + src/db/sysdb_upgrade.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 274 insertions(+), 6 deletions(-) + +diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c +index 44a7918f603fe1368b7d81738666de6bb47b83d0..74ad23f3050da0ae14fa495d2302f4a858fcd3c5 100644 +--- a/src/db/sysdb_init.c ++++ b/src/db/sysdb_init.c +@@ -359,8 +359,48 @@ static errno_t sysdb_ts_cache_upgrade(TALLOC_CTX *mem_ctx, + const char *cur_version, + const char **_new_version) + { +- /* Currently the sysdb cache only has one version */ +- return EFAULT; ++ errno_t ret; ++ TALLOC_CTX *tmp_ctx; ++ const char *version; ++ struct ldb_context *save_ldb; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ /* The upgrade process depends on having ldb around, yet the upgrade ++ * function shouldn't set the ldb pointer, only the connect function ++ * should after it's successful. To avoid hard refactoring, save the ++ * ldb pointer here and restore in the 'done' handler ++ */ ++ save_ldb = sysdb->ldb; ++ sysdb->ldb = ldb; ++ ++ version = talloc_strdup(tmp_ctx, cur_version); ++ if (version == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_CONF_SETTINGS, ++ "Upgrading timstamp cache of DB [%s] from version: %s\n", ++ domain->name, version); ++ ++ if (strcmp(version, SYSDB_TS_VERSION_0_1) == 0) { ++ ret = sysdb_ts_upgrade_01(sysdb, &version); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++ ++done: ++ sysdb->ldb = save_ldb; ++ *_new_version = version; ++ talloc_free(tmp_ctx); ++ return ret; + } + + static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx, +@@ -511,6 +551,14 @@ static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx, + } + } + ++ if (strcmp(version, SYSDB_VERSION_0_19) == 0) { ++ ret = sysdb_upgrade_19(sysdb, &version); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ ++ + ret = EOK; + done: + sysdb->ldb = save_ldb; +diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h +index dbd75615bc212e73c4338a76dceaa68a5889ed1d..cac06ba46da23080d1ab661502d0792bd37b9291 100644 +--- a/src/db/sysdb_private.h ++++ b/src/db/sysdb_private.h +@@ -23,6 +23,7 @@ + #ifndef __INT_SYS_DB_H__ + #define __INT_SYS_DB_H__ + ++#define SYSDB_VERSION_0_20 "0.20" + #define SYSDB_VERSION_0_19 "0.19" + #define SYSDB_VERSION_0_18 "0.18" + #define SYSDB_VERSION_0_17 "0.17" +@@ -43,7 +44,7 @@ + #define SYSDB_VERSION_0_2 "0.2" + #define SYSDB_VERSION_0_1 "0.1" + +-#define SYSDB_VERSION SYSDB_VERSION_0_19 ++#define SYSDB_VERSION SYSDB_VERSION_0_20 + + #define SYSDB_BASE_LDIF \ + "dn: @ATTRIBUTES\n" \ +@@ -72,7 +73,6 @@ + "@IDXATTR: sudoUser\n" \ + "@IDXATTR: sshKnownHostsExpire\n" \ + "@IDXATTR: objectSIDString\n" \ +- "@IDXONE: 1\n" \ + "@IDXATTR: ghost\n" \ + "@IDXATTR: userPrincipalName\n" \ + "@IDXATTR: canonicalUserPrincipalName\n" \ +@@ -92,9 +92,10 @@ + "\n" + + /* The timestamp cache has its own versioning */ ++#define SYSDB_TS_VERSION_0_2 "0.2" + #define SYSDB_TS_VERSION_0_1 "0.1" + +-#define SYSDB_TS_VERSION SYSDB_TS_VERSION_0_1 ++#define SYSDB_TS_VERSION SYSDB_TS_VERSION_0_2 + + #define SYSDB_TS_BASE_LDIF \ + "dn: @ATTRIBUTES\n" \ +@@ -103,7 +104,6 @@ + "dn: @INDEXLIST\n" \ + "@IDXATTR: lastUpdate\n" \ + "@IDXATTR: dataExpireTimestamp\n" \ +- "@IDXONE: 1\n" \ + "\n" \ + "dn: cn=sysdb\n" \ + "cn: sysdb\n" \ +@@ -169,6 +169,9 @@ int sysdb_upgrade_17(struct sysdb_ctx *sysdb, + struct sysdb_dom_upgrade_ctx *upgrade_ctx, + const char **ver); + int sysdb_upgrade_18(struct sysdb_ctx *sysdb, const char **ver); ++int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver); ++ ++int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver); + + int sysdb_add_string(struct ldb_message *msg, + const char *attr, const char *value); +diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c +index 365d45f7ebd78523ca9ec4b9c2158cc09acb5489..bc157a24664239bc1255e49a1825243a07acc90f 100644 +--- a/src/db/sysdb_upgrade.c ++++ b/src/db/sysdb_upgrade.c +@@ -2317,6 +2317,223 @@ done: + return ret; + } + ++static errno_t add_object_category(struct ldb_context *ldb, ++ struct upgrade_ctx *ctx) ++{ ++ errno_t ret; ++ struct ldb_result *objects = NULL; ++ const char *attrs[] = { SYSDB_OBJECTCLASS, NULL }; ++ struct ldb_dn *base_dn; ++ size_t c; ++ const char *class_name; ++ struct ldb_message *msg = NULL; ++ struct ldb_message *del_msg = NULL; ++ ++ base_dn = ldb_dn_new(ctx, ldb, SYSDB_BASE); ++ if (base_dn == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed create base dn.\n"); ++ return ENOMEM; ++ } ++ ++ ret = ldb_search(ldb, ctx, &objects, base_dn, ++ LDB_SCOPE_SUBTREE, attrs, ++ "(|("SYSDB_OBJECTCLASS"="SYSDB_USER_CLASS")" ++ "("SYSDB_OBJECTCLASS"="SYSDB_GROUP_CLASS"))"); ++ talloc_free(base_dn); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to search objects: %d\n", ret); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ if (objects == NULL || objects->count == 0) { ++ DEBUG(SSSDBG_TRACE_LIBS, "No objects found, nothing to do."); ++ ret = EOK; ++ goto done; ++ } ++ ++ del_msg = ldb_msg_new(ctx); ++ if (del_msg == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ret = ldb_msg_add_empty(del_msg, SYSDB_OBJECTCLASS, LDB_FLAG_MOD_DELETE, ++ NULL); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n"); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_ALL, "Found [%d] objects.\n", objects->count); ++ for (c = 0; c < objects->count; c++) { ++ DEBUG(SSSDBG_TRACE_ALL, "Updating [%s].\n", ++ ldb_dn_get_linearized(objects->msgs[c]->dn)); ++ ++ class_name = ldb_msg_find_attr_as_string(objects->msgs[c], ++ SYSDB_OBJECTCLASS, NULL); ++ if (class_name == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "Searched objects by objectClass, " ++ "but result does not have one.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ talloc_free(msg); ++ msg = ldb_msg_new(ctx); ++ if (msg == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ msg->dn = objects->msgs[c]->dn; ++ del_msg->dn = objects->msgs[c]->dn; ++ ++ ret = ldb_msg_add_empty(msg, SYSDB_OBJECTCATEGORY, LDB_FLAG_MOD_ADD, ++ NULL); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n"); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ ret = ldb_msg_add_string(msg, SYSDB_OBJECTCATEGORY, class_name); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n"); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_ALL, "Adding [%s] to [%s].\n", class_name, ++ ldb_dn_get_linearized(objects->msgs[c]->dn)); ++ ret = ldb_modify(ldb, msg); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to add objectCategory to %s: %d.\n", ++ ldb_dn_get_linearized(objects->msgs[c]->dn), ++ sysdb_error_to_errno(ret)); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ ret = ldb_modify(ldb, del_msg); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to remove objectClass from %s: %d.\n", ++ ldb_dn_get_linearized(objects->msgs[c]->dn), ++ sysdb_error_to_errno(ret)); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(msg); ++ talloc_free(del_msg); ++ talloc_free(objects); ++ ++ return ret; ++} ++ ++int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver) ++{ ++ struct upgrade_ctx *ctx; ++ errno_t ret; ++ struct ldb_message *msg = NULL; ++ ++ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_20, &ctx); ++ if (ret) { ++ return ret; ++ } ++ ++ ret = add_object_category(sysdb->ldb, ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "add_object_category failed.\n"); ++ goto done; ++ } ++ ++ /* Remove @IDXONE from index */ ++ msg = ldb_msg_new(ctx); ++ if (msg == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST"); ++ if (msg->dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_msg_add_empty(msg, "@IDXONE", LDB_FLAG_MOD_DELETE, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_modify(sysdb->ldb, msg); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ /* conversion done, update version number */ ++ ret = update_version(ctx); ++ ++done: ++ ret = finish_upgrade(ret, &ctx, ver); ++ return ret; ++} ++ ++int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver) ++{ ++ struct upgrade_ctx *ctx; ++ errno_t ret; ++ struct ldb_message *msg = NULL; ++ ++ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_TS_VERSION_0_2, &ctx); ++ if (ret) { ++ return ret; ++ } ++ ++ /* Remove @IDXONE from index */ ++ talloc_free(msg); ++ msg = ldb_msg_new(ctx); ++ if (msg == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST"); ++ if (msg->dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_msg_add_empty(msg, "@IDXONE", LDB_FLAG_MOD_DELETE, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_modify(sysdb->ldb, msg); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ /* conversion done, update version number */ ++ ret = update_version(ctx); ++ ++done: ++ ret = finish_upgrade(ret, &ctx, ver); ++ return ret; ++} ++ + /* + * Example template for future upgrades. + * Copy and change version numbers as appropriate. +-- +2.14.3 + diff --git a/SOURCES/0058-IPA-add-mapped-attributes-to-user-from-trusted-domai.patch b/SOURCES/0058-IPA-add-mapped-attributes-to-user-from-trusted-domai.patch deleted file mode 100644 index 2b6616e..0000000 --- a/SOURCES/0058-IPA-add-mapped-attributes-to-user-from-trusted-domai.patch +++ /dev/null @@ -1,153 +0,0 @@ -From b8a36e1be5cdd2c61ddf8e40970270bb878d26a3 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 22 Mar 2017 14:13:05 +0100 -Subject: [PATCH 58/60] IPA: add mapped attributes to user from trusted domains - -Allow the usage of the mapped attribute for the lookup of AD users on -IPA clients as already used for the normal LDAP lookup. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek ---- - src/providers/ipa/ipa_s2n_exop.c | 33 ++++++++++++++++++++++++--------- - 1 file changed, 24 insertions(+), 9 deletions(-) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index c99312274073858e5e03f3e82c069dafc839eb61..05c32a24d61947e62884f460069083fb81f40fe0 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -761,6 +761,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, - struct resp_attrs *simple_attrs, - const char *view_name, - struct sysdb_attrs *override_attrs, -+ struct sysdb_attrs *mapped_attrs, - bool update_initgr_timeout); - - static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, -@@ -1009,6 +1010,7 @@ struct ipa_s2n_get_list_state { - struct resp_attrs *attrs; - struct sss_domain_info *obj_domain; - struct sysdb_attrs *override_attrs; -+ struct sysdb_attrs *mapped_attrs; - }; - - static errno_t ipa_s2n_get_list_step(struct tevent_req *req); -@@ -1025,7 +1027,8 @@ static struct tevent_req *ipa_s2n_get_list_send(TALLOC_CTX *mem_ctx, - int entry_type, - enum request_types request_type, - enum req_input_type list_type, -- char **list) -+ char **list, -+ struct sysdb_attrs *mapped_attrs) - { - int ret; - struct ipa_s2n_get_list_state *state; -@@ -1057,6 +1060,7 @@ static struct tevent_req *ipa_s2n_get_list_send(TALLOC_CTX *mem_ctx, - state->request_type = request_type; - state->attrs = NULL; - state->override_attrs = NULL; -+ state->mapped_attrs = mapped_attrs; - - ret = ipa_s2n_get_list_step(req); - if (ret != EOK) { -@@ -1288,7 +1292,8 @@ static errno_t ipa_s2n_get_list_save_step(struct tevent_req *req) - - ret = ipa_s2n_save_objects(state->dom, &state->req_input, state->attrs, - NULL, state->ipa_ctx->view_name, -- state->override_attrs, false); -+ state->override_attrs, state->mapped_attrs, -+ false); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n"); - return ret; -@@ -1704,7 +1709,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) - BE_REQ_GROUP, - REQ_FULL_WITH_MEMBERS, - REQ_INP_NAME, -- missing_list); -+ missing_list, NULL); - if (subreq == NULL) { - DEBUG(SSSDBG_OP_FAILURE, - "ipa_s2n_get_list_send failed.\n"); -@@ -1732,7 +1737,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) - BE_REQ_USER, - REQ_FULL_WITH_MEMBERS, - REQ_INP_NAME, -- missing_list); -+ missing_list, NULL); - if (subreq == NULL) { - DEBUG(SSSDBG_OP_FAILURE, - "ipa_s2n_get_list_send failed.\n"); -@@ -1810,7 +1815,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) - - if (ret == ENOENT || is_default_view(state->ipa_ctx->view_name)) { - ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs, -- state->simple_attrs, NULL, NULL, true); -+ state->simple_attrs, NULL, NULL, NULL, true); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n"); - goto done; -@@ -1978,6 +1983,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, - struct resp_attrs *simple_attrs, - const char *view_name, - struct sysdb_attrs *override_attrs, -+ struct sysdb_attrs *mapped_attrs, - bool update_initgr_timeout) - { - int ret; -@@ -2305,6 +2311,15 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, - goto done; - } - -+ if (mapped_attrs != NULL) { -+ ret = sysdb_set_user_attr(dom, name, mapped_attrs, -+ SYSDB_MOD_ADD); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_user_attr failed.\n"); -+ goto done; -+ } -+ } -+ - if (gid_override_attrs != NULL) { - ret = sysdb_set_user_attr(dom, name, gid_override_attrs, - SYSDB_MOD_REP); -@@ -2487,7 +2502,7 @@ static void ipa_s2n_get_list_done(struct tevent_req *subreq) - &sid_str); - if (ret == ENOENT) { - ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs, -- state->simple_attrs, NULL, NULL, true); -+ state->simple_attrs, NULL, NULL, NULL, true); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n"); - goto fail; -@@ -2525,7 +2540,7 @@ static void ipa_s2n_get_list_done(struct tevent_req *subreq) - ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs, - state->simple_attrs, - state->ipa_ctx->view_name, -- state->override_attrs, true); -+ state->override_attrs, NULL, true); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n"); - tevent_req_error(req, ret); -@@ -2561,7 +2576,7 @@ static void ipa_s2n_get_user_get_override_done(struct tevent_req *subreq) - - ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs, - state->simple_attrs, state->ipa_ctx->view_name, -- override_attrs, true); -+ override_attrs, NULL, true); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n"); - tevent_req_error(req, ret); -@@ -2662,7 +2677,7 @@ struct tevent_req *ipa_get_subdom_acct_process_pac_send(TALLOC_CTX *mem_ctx, - dp_opt_get_int(ipa_ctx->sdap_id_ctx->opts->basic, - SDAP_SEARCH_TIMEOUT), - BE_REQ_BY_SECID, REQ_FULL, REQ_INP_SECID, -- state->missing_sids); -+ state->missing_sids, NULL); - if (subreq == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_list_send failed.\n"); - ret = ENOMEM; --- -2.9.3 - diff --git a/SOURCES/0058-mmap_cache-make-checks-independent-of-input-size.patch b/SOURCES/0058-mmap_cache-make-checks-independent-of-input-size.patch new file mode 100644 index 0000000..cc91c58 --- /dev/null +++ b/SOURCES/0058-mmap_cache-make-checks-independent-of-input-size.patch @@ -0,0 +1,175 @@ +From 531c0ad3e13ddc1f5c31a620aa1f8b91aa8a4053 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 17 Nov 2017 10:51:44 +0100 +Subject: [PATCH 58/59] mmap_cache: make checks independent of input size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently the consistency checks for the mmap_cache payload data on the +client and the responder side include the length of the input string of +the current request. Since there might be hash collisions which other +much longer or much shorter names those checks might fail although there +is no data corruption. + +This patch removes the checks using the length of the input and adds a +check if the name found in the payload is zero-terminated inside of the +payload data. + +Resolves https://pagure.io/SSSD/sssd/issue/3571 + +Reviewed-by: Michal Židek +Reviewed-by: Lukáš Slebodník +(cherry picked from commit 4382047490dd4f80b407cc1e618da048f13e5f8f) +--- + src/responder/nss/nsssrv_mmap_cache.c | 34 ++++++++++++++++++++++++---------- + src/sss_client/nss_mc_group.c | 14 ++++++++------ + src/sss_client/nss_mc_initgr.c | 14 +++++++++----- + src/sss_client/nss_mc_passwd.c | 14 ++++++++------ + 4 files changed, 49 insertions(+), 27 deletions(-) + +diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c +index a87ad646f9b741db3eb18680678697032fc420ba..ad5adbce15e50c065d4d16e626be97fd23d06643 100644 +--- a/src/responder/nss/nsssrv_mmap_cache.c ++++ b/src/responder/nss/nsssrv_mmap_cache.c +@@ -547,18 +547,32 @@ static struct sss_mc_rec *sss_mc_find_record(struct sss_mc_ctx *mcc, + return NULL; + } + ++ if (key->len > strs_len) { ++ /* The string cannot be in current record */ ++ slot = sss_mc_next_slot_with_hash(rec, hash); ++ continue; ++ } ++ + safealign_memcpy(&name_ptr, rec->data, sizeof(rel_ptr_t), NULL); +- if (key->len > strs_len +- || (name_ptr + key->len) > (strs_offset + strs_len) +- || (uint8_t *)rec->data + strs_offset + strs_len > max_addr) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Corrupted fastcache. name_ptr value is %u.\n", name_ptr); +- sss_mc_save_corrupted(mcc); +- sss_mmap_cache_reset(mcc); +- return NULL; +- } +- + t_key = (char *)rec->data + name_ptr; ++ /* name_ptr must point to some data in the strs/gids area of the data ++ * payload. Since it is a pointer relative to rec->data it must larger ++ * equal strs_offset and must be smaller then strs_offset + strs_len. ++ * Additionally the area must not end outside of the data table and ++ * t_key must be a zero-terminates string. */ ++ if (name_ptr < strs_offset ++ || name_ptr >= strs_offset + strs_len ++ || (uint8_t *)rec->data > max_addr ++ || strs_offset > max_addr - (uint8_t *)rec->data ++ || strs_len > max_addr - (uint8_t *)rec->data - strs_offset) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Corrupted fastcache entry at slot %u. " ++ "name_ptr value is %u.\n", slot, name_ptr); ++ sss_mc_save_corrupted(mcc); ++ sss_mmap_cache_reset(mcc); ++ return NULL; ++ } ++ + if (strcmp(key->str, t_key) == 0) { + break; + } +diff --git a/src/sss_client/nss_mc_group.c b/src/sss_client/nss_mc_group.c +index ce88d42fdaf4f19e78fc43e187bc28651cdc3c4e..4b1601a171a3af700b6f0d2bfedb3a6198e6df6d 100644 +--- a/src/sss_client/nss_mc_group.c ++++ b/src/sss_client/nss_mc_group.c +@@ -148,20 +148,22 @@ errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len, + } + + data = (struct sss_mc_grp_data *)rec->data; ++ rec_name = (char *)data + data->name; + /* Integrity check +- * - name_len cannot be longer than all strings + * - data->name cannot point outside strings + * - all strings must be within copy of record +- * - size of record must be lower that data table size */ +- if (name_len > data->strs_len +- || (data->name + name_len) > (strs_offset + data->strs_len) ++ * - record must not end outside data table ++ * - rec_name is a zero-terminated string */ ++ if (data->name < strs_offset ++ || data->name >= strs_offset + data->strs_len + || data->strs_len > rec->len +- || rec->len > data_size) { ++ || (uint8_t *) rec + rec->len > gr_mc_ctx.data_table + data_size ++ || memchr(rec_name, '\0', ++ (strs_offset + data->strs_len) - data->name) == NULL) { + ret = ENOENT; + goto done; + } + +- rec_name = (char *)data + data->name; + if (strcmp(name, rec_name) == 0) { + break; + } +diff --git a/src/sss_client/nss_mc_initgr.c b/src/sss_client/nss_mc_initgr.c +index a77088d849ad3601cb3edb55fc5ea4ae4c52fe38..d8c01f52ea2d23515d0b462541657dc9416b0915 100644 +--- a/src/sss_client/nss_mc_initgr.c ++++ b/src/sss_client/nss_mc_initgr.c +@@ -131,15 +131,19 @@ errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len, + data = (struct sss_mc_initgr_data *)rec->data; + rec_name = (char *)data + data->name; + /* Integrity check +- * - name_len cannot be longer than all strings or data ++ * - data->name cannot point outside all strings or data + * - all data must be within copy of record + * - size of record must be lower that data table size +- * - data->strs cannot point outside strings */ +- if (name_len > data->strs_len ++ * - data->strs cannot point outside strings ++ * - rec_name is a zero-terminated string */ ++ if (data->name < data_offset ++ || data->name >= data_offset + data->data_len + || data->strs_len > data->data_len + || data->data_len > rec->len +- || rec->len > data_size +- || (data->strs + name_len) > (data_offset + data->data_len)) { ++ || (uint8_t *) rec + rec->len ++ > initgr_mc_ctx.data_table + data_size ++ || memchr(rec_name, '\0', ++ (data_offset + data->data_len) - data->name) == NULL) { + ret = ENOENT; + goto done; + } +diff --git a/src/sss_client/nss_mc_passwd.c b/src/sss_client/nss_mc_passwd.c +index 0da7ad0aeece7d38ca34bb3fde64adc898eaf0ae..868427f03a7ec0c8bd7401c8547a6f6bead7af28 100644 +--- a/src/sss_client/nss_mc_passwd.c ++++ b/src/sss_client/nss_mc_passwd.c +@@ -141,20 +141,22 @@ errno_t sss_nss_mc_getpwnam(const char *name, size_t name_len, + } + + data = (struct sss_mc_pwd_data *)rec->data; ++ rec_name = (char *)data + data->name; + /* Integrity check +- * - name_len cannot be longer than all strings + * - data->name cannot point outside strings + * - all strings must be within copy of record +- * - size of record must be lower that data table size */ +- if (name_len > data->strs_len +- || (data->name + name_len) > (strs_offset + data->strs_len) ++ * - record must not end outside data table ++ * - rec_name is a zero-terminated string */ ++ if (data->name < strs_offset ++ || data->name >= strs_offset + data->strs_len + || data->strs_len > rec->len +- || rec->len > data_size) { ++ || (uint8_t *) rec + rec->len > pw_mc_ctx.data_table + data_size ++ || memchr(rec_name, '\0', ++ (strs_offset + data->strs_len) - data->name) == NULL ) { + ret = ENOENT; + goto done; + } + +- rec_name = (char *)data + data->name; + if (strcmp(name, rec_name) == 0) { + break; + } +-- +2.14.3 + diff --git a/SOURCES/0059-IPA-lookup-AD-users-by-certificates-on-IPA-clients.patch b/SOURCES/0059-IPA-lookup-AD-users-by-certificates-on-IPA-clients.patch deleted file mode 100644 index 1440219..0000000 --- a/SOURCES/0059-IPA-lookup-AD-users-by-certificates-on-IPA-clients.patch +++ /dev/null @@ -1,209 +0,0 @@ -From 537e057ef3bd140e418381f2ce74397ab8c34a73 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 24 Mar 2017 15:40:41 +0100 -Subject: [PATCH 59/60] IPA: lookup AD users by certificates on IPA clients - -Get a list of users mapped to a certificate back from the IPA server, -look them up and store them together with the certificate used for the -search as mapped attribute to the cache. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek ---- - src/providers/ipa/ipa_s2n_exop.c | 109 +++++++++++++++++++++++++++++++++++++-- - 1 file changed, 105 insertions(+), 4 deletions(-) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index 05c32a24d61947e62884f460069083fb81f40fe0..8a3391b4093f1547d84fe44a0f24b1d063d1e28c 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -52,7 +52,8 @@ enum response_types { - RESP_USER, - RESP_GROUP, - RESP_USER_GROUPLIST, -- RESP_GROUP_MEMBERS -+ RESP_GROUP_MEMBERS, -+ RESP_NAME_LIST - }; - - /* ==Sid2Name Extended Operation============================================= */ -@@ -366,8 +367,8 @@ static errno_t s2n_encode_request(TALLOC_CTX *mem_ctx, - break; - case BE_REQ_BY_CERT: - if (req_input->type == REQ_INP_CERT) { -- ret = ber_printf(ber, "{ees}", INP_CERT, request_type, -- req_input->inp.cert); -+ ret = ber_printf(ber, "{ees}", INP_CERT, request_type, -+ req_input->inp.cert); - } else { - DEBUG(SSSDBG_OP_FAILURE, "Unexpected input type [%d].\n", - req_input->type); -@@ -463,6 +464,11 @@ done: - * GroupMemberList ::= SEQUENCE OF OCTET STRING - */ - -+struct name_list { -+ char *domain_name; -+ char *name; -+}; -+ - struct resp_attrs { - enum response_types response_type; - char *domain_name; -@@ -475,6 +481,7 @@ struct resp_attrs { - size_t ngroups; - char **groups; - struct sysdb_attrs *sysdb_attrs; -+ char **name_list; - }; - - static errno_t get_extra_attrs(BerElement *ber, struct resp_attrs *resp_attrs) -@@ -782,6 +789,9 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, - struct resp_attrs *attrs = NULL; - char *sid_str; - bool is_v1 = false; -+ char **name_list = NULL; -+ ber_len_t ber_len; -+ char *fq_name = NULL; - - if (retoid == NULL || retdata == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "Missing OID or data.\n"); -@@ -947,6 +957,53 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, - goto done; - } - break; -+ case RESP_NAME_LIST: -+ tag = ber_scanf(ber, "{"); -+ if (tag == LBER_ERROR) { -+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ while (ber_peek_tag(ber, &ber_len) == LBER_SEQUENCE) { -+ tag = ber_scanf(ber, "{aa}", &domain_name, &name); -+ if (tag == LBER_ERROR) { -+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ fq_name = sss_create_internal_fqname(attrs, name, domain_name); -+ if (fq_name == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sss_create_internal_fqname failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ DEBUG(SSSDBG_TRACE_ALL, "[%s][%s][%s].\n", domain_name, name, -+ fq_name); -+ -+ ret = add_string_to_list(attrs, fq_name, &name_list); -+ ber_memfree(domain_name); -+ ber_memfree(name); -+ talloc_free(fq_name); -+ domain_name = NULL; -+ name = NULL; -+ fq_name = NULL; -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "add_to_name_list failed.\n"); -+ goto done; -+ } -+ } -+ -+ tag = ber_scanf(ber, "}}"); -+ if (tag == LBER_ERROR) { -+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ attrs->name_list = name_list; -+ break; - default: - DEBUG(SSSDBG_OP_FAILURE, "Unexpected response type [%d].\n", - type); -@@ -955,7 +1012,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, - } - - attrs->response_type = type; -- if (type != RESP_SID) { -+ if (type != RESP_SID && type != RESP_NAME_LIST) { - attrs->domain_name = talloc_strdup(attrs, domain_name); - if (attrs->domain_name == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -@@ -969,6 +1026,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, - done: - ber_memfree(domain_name); - ber_memfree(name); -+ talloc_free(fq_name); - ber_free(ber, 1); - - if (ret == EOK) { -@@ -1332,6 +1390,7 @@ struct ipa_s2n_get_user_state { - struct resp_attrs *attrs; - struct resp_attrs *simple_attrs; - struct sysdb_attrs *override_attrs; -+ struct sysdb_attrs *mapped_attrs; - int exop_timeout; - }; - -@@ -1384,6 +1443,11 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx, - goto fail; - } - -+ if (entry_type == BE_REQ_BY_CERT) { -+ /* Only REQ_SIMPLE is supported for BE_REQ_BY_CERT */ -+ state->request_type = REQ_SIMPLE; -+ } -+ - ret = s2n_encode_request(state, dom->name, entry_type, state->request_type, - req_input, &bv_req); - if (ret != EOK) { -@@ -1785,6 +1849,43 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) - goto done; - } - -+ if (state->simple_attrs->response_type == RESP_NAME_LIST -+ && state->req_input->type == REQ_INP_CERT) { -+ state->mapped_attrs = sysdb_new_attrs(state); -+ if (state->mapped_attrs == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sysdb_attrs_add_base64_blob(state->mapped_attrs, -+ SYSDB_USER_MAPPED_CERT, -+ state->req_input->inp.cert); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_base64_blob failed.\n"); -+ goto done; -+ } -+ -+ subreq = ipa_s2n_get_list_send(state, state->ev, -+ state->ipa_ctx, state->dom, -+ state->sh, state->exop_timeout, -+ BE_REQ_USER, -+ REQ_FULL_WITH_MEMBERS, -+ REQ_INP_NAME, -+ state->simple_attrs->name_list, -+ state->mapped_attrs); -+ if (subreq == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "ipa_s2n_get_list_send failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ tevent_req_set_callback(subreq, ipa_s2n_get_list_done, -+ req); -+ -+ return; -+ } -+ - break; - default: - DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected request type.\n"); --- -2.9.3 - diff --git a/SOURCES/0059-NSS-Fix-covscan-warning.patch b/SOURCES/0059-NSS-Fix-covscan-warning.patch new file mode 100644 index 0000000..2dfd5be --- /dev/null +++ b/SOURCES/0059-NSS-Fix-covscan-warning.patch @@ -0,0 +1,54 @@ +From 2fd201a6e8f263f30fb3aeb3d7f826a06321e58e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 21 Nov 2017 16:12:24 +0100 +Subject: [PATCH 59/59] NSS: Fix covscan warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + Error: NULL_RETURNS (CWE-476): [#def1] + sssd-1.16.1/src/responder/nss/nss_protocol.c:162: returned_null: "memchr" returns null (checked 7 out of 8 times). + sssd-1.16.1/src/responder/nss/nsssrv_mmap_cache.c:557: example_checked: Example 1: "memchr(t_key, 0, strs_offset + strs_len - name_ptr)" has its value checked in "memchr(t_key, 0, strs_offset + strs_len - name_ptr) == NULL". + sssd-1.16.1/src/sss_client/idmap/sss_nss_idmap.c:171: example_assign: Example 2: Assigning: "p" = return value from "memchr(p, 0, buf_len - (p - buf))". + sssd-1.16.1/src/sss_client/idmap/sss_nss_idmap.c:172: example_checked: Example 2 (cont.): "p" has its value checked in "p == NULL". + sssd-1.16.1/src/sss_client/nss_mc_group.c:157: example_checked: Example 3: "memchr(rec_name, 0, 16UL + data->strs_len - data->name)" has its value checked in "memchr(rec_name, 0, 16UL + data->strs_len - data->name) == NULL". + sssd-1.16.1/src/sss_client/nss_mc_initgr.c:139: example_checked: Example 4: "memchr(rec_name, 0, 24UL + data->data_len - data->name)" has its value checked in "memchr(rec_name, 0, 24UL + data->data_len - data->name) == NULL". + sssd-1.16.1/src/sss_client/nss_mc_passwd.c:150: example_checked: Example 5: "memchr(rec_name, 0, 16UL + data->strs_len - data->name)" has its value checked in "memchr(rec_name, 0, 16UL + data->strs_len - data->name) == NULL". + sssd-1.16.1/src/responder/nss/nss_protocol.c:162: var_assigned: Assigning: "p" = null return value from "memchr". + sssd-1.16.1/src/responder/nss/nss_protocol.c:176: dereference: Incrementing a pointer which might be null: "p". + # 174| } + # 175| + # 176|-> p++; + # 177| if ((p - body) + sizeof(uint32_t) != blen) { + # 178| DEBUG(SSSDBG_CRIT_FAILURE, "Body has unexpected size!\n"); + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Lukáš Slebodník +Reviewed-by: Michal Židek +(cherry picked from commit 1d88a0591ce8445ea3b6a88845a5997d61c915b4) +--- + src/responder/nss/nss_protocol.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/responder/nss/nss_protocol.c b/src/responder/nss/nss_protocol.c +index 2655386498754c46fbb363bdd1f976f9ded6a434..13f6d1541b79bf5494e1560841f027bf98bef72b 100644 +--- a/src/responder/nss/nss_protocol.c ++++ b/src/responder/nss/nss_protocol.c +@@ -160,6 +160,13 @@ nss_protocol_parse_name_ex(struct cli_ctx *cli_ctx, const char **_rawname, + } + + p = memchr(body, '\0', blen); ++ /* Although body for sure is null terminated, let's add this check here ++ * so static analyzers are happier. */ ++ if (p == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "memchr() returned NULL, body is not null terminated!\n"); ++ return EINVAL; ++ } + + /* If the body isn't valid UTF-8, fail */ + if (!sss_utf8_check(body, (p - body))) { +-- +2.14.3 + diff --git a/SOURCES/0060-IPA-enable-AD-user-lookup-by-certificate.patch b/SOURCES/0060-IPA-enable-AD-user-lookup-by-certificate.patch deleted file mode 100644 index e6ed62e..0000000 --- a/SOURCES/0060-IPA-enable-AD-user-lookup-by-certificate.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 1f29c3d5302dc4ca9f5f9c6fe64dc8de5381041f Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 24 Mar 2017 15:41:37 +0100 -Subject: [PATCH 60/60] IPA: enable AD user lookup by certificate - -Without this the lookup by certificate for AD users on an IPA client -will just error out. - -Related to https://pagure.io/SSSD/sssd/issue/3050 - -Reviewed-by: Jakub Hrozek ---- - src/providers/ipa/ipa_subdomains_id.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c -index 4777d7cfd97fed39b807a659fd1f9000c7ff8625..3530af94ef59397db72465fcb0c4a03117a4d8bd 100644 ---- a/src/providers/ipa/ipa_subdomains_id.c -+++ b/src/providers/ipa/ipa_subdomains_id.c -@@ -399,6 +399,7 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx, - case BE_REQ_USER: - case BE_REQ_GROUP: - case BE_REQ_BY_SECID: -+ case BE_REQ_BY_CERT: - case BE_REQ_USER_AND_GROUP: - ret = EOK; - break; --- -2.9.3 - diff --git a/SOURCES/0060-responder-Fix-talloc-hierarchy-in-sized_output_name.patch b/SOURCES/0060-responder-Fix-talloc-hierarchy-in-sized_output_name.patch new file mode 100644 index 0000000..dc76425 --- /dev/null +++ b/SOURCES/0060-responder-Fix-talloc-hierarchy-in-sized_output_name.patch @@ -0,0 +1,59 @@ +From af95dd657586d3fc5680a7f8b493a5502640235e Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 28 Nov 2017 12:19:54 +0100 +Subject: [PATCH 60/67] responder: Fix talloc hierarchy in sized_output_name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +sized_output_name was a called with NULL context in +memcache_delete_entry but returned data from sized_output_name +didn't have proper talloc hierarchy and we could not release all +all returned data. + +==00:01:01:29.871 10088== 934,414 bytes in 8,731 blocks are definitely lost in loss record 121 of 121 +==00:01:01:29.871 10088== at 0x4C29BE3: malloc (vg_replace_malloc.c:299) +==00:01:01:29.871 10088== by 0x8FF4EAB: talloc_strdup (in /usr/lib64/libtalloc.so.2.1.9) +==00:01:01:29.871 10088== by 0x52933B9: sss_output_name (usertools.c:808) +==00:01:01:29.871 10088== by 0x5293550: sss_output_fqname (usertools.c:863) +==00:01:01:29.871 10088== by 0x1211F9: sized_output_name (responder_common.c:1708) +==00:01:01:29.871 10088== by 0x1137E6: memcache_delete_entry (nss_get_object.c:112) +==00:01:01:29.871 10088== by 0x113BB6: nss_get_object_done (nss_get_object.c:245) +==00:01:01:29.871 10088== by 0x8DE5291: _tevent_req_error (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x1276CE: cache_req_done (cache_req.c:1047) +==00:01:01:29.871 10088== by 0x8DE5291: _tevent_req_error (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x126AF6: cache_req_search_domains_done (cache_req.c:607) +==00:01:01:29.871 10088== by 0x8DE4AB9: tevent_common_loop_immediate (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x8DE9C9C: ??? (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x8DE82A6: ??? (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x8DE40CC: _tevent_loop_once (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x8DE42FA: tevent_common_loop_wait (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x8DE8246: ??? (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x5291B32: server_loop (server.c:718) +==00:01:01:29.871 10088== by 0x11004C: main (nsssrv.c:560) + +Resolves: +https://pagure.io/SSSD/sssd/issue/3588 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 06e741a9bf23a18a998f366d9a8990b887a01638) +--- + src/responder/common/responder_common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index 6b4d2d9e5936c79944b6f883e9fe46fd03ff32f6..e1100ce4b1eaae8bc561246699dc9bacc96133c8 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -1815,7 +1815,7 @@ int sized_output_name(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sss_output_fqname(mem_ctx, name_dom, orig_name, ++ ret = sss_output_fqname(name, name_dom, orig_name, + rctx->override_space, &name_str); + if (ret != EOK) { + goto done; +-- +2.14.3 + diff --git a/SOURCES/0061-CONFDB-Introduce-SSSD-domain-type-to-distinguish-POS.patch b/SOURCES/0061-CONFDB-Introduce-SSSD-domain-type-to-distinguish-POS.patch deleted file mode 100644 index 31f541e..0000000 --- a/SOURCES/0061-CONFDB-Introduce-SSSD-domain-type-to-distinguish-POS.patch +++ /dev/null @@ -1,242 +0,0 @@ -From 75a8d8e7996c35fd9bef504f2f4d3e308b7553c8 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 22 Mar 2017 12:53:17 +0100 -Subject: [PATCH 61/72] CONFDB: Introduce SSSD domain type to distinguish POSIX - and application domains -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related to: -https://pagure.io/SSSD/sssd/issue/3310 - -Adds a new option that allows to distinguish domains that do contain -POSIX users and groups and those that don't. The POSIX domains are the -default. The non-POSIX domains are selected by selecting an -"application" type domain. - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/confdb/confdb.c | 18 +++++++++++++++++- - src/confdb/confdb.h | 15 +++++++++++++++ - src/config/SSSDConfig/__init__.py.in | 1 + - src/config/SSSDConfigTest.py | 2 ++ - src/config/cfg_rules.ini | 1 + - src/config/etc/sssd.api.conf | 1 + - src/man/sssd.conf.5.xml | 33 +++++++++++++++++++++++++++++++++ - src/util/domain_info_utils.c | 14 ++++++++++++++ - src/util/util.h | 1 + - 9 files changed, 85 insertions(+), 1 deletion(-) - -diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c -index d82fd98ee02928b3c20df014528bd869ec946f92..70a1eb7b2c7e83dfa9d217a15c7d3d4c8580b891 100644 ---- a/src/confdb/confdb.c -+++ b/src/confdb/confdb.c -@@ -1367,6 +1367,22 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, - } - } - -+ domain->type = DOM_TYPE_POSIX; -+ tmp = ldb_msg_find_attr_as_string(res->msgs[0], -+ CONFDB_DOMAIN_TYPE, -+ CONFDB_DOMAIN_TYPE_POSIX); -+ if (tmp != NULL) { -+ if (strcasecmp(tmp, CONFDB_DOMAIN_TYPE_POSIX) == 0) { -+ domain->type = DOM_TYPE_POSIX; -+ } else if (strcasecmp(tmp, CONFDB_DOMAIN_TYPE_APP) == 0) { -+ domain->type = DOM_TYPE_APPLICATION; -+ } else { -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "Invalid value %s for [%s]\n", tmp, CONFDB_DOMAIN_TYPE); -+ goto done; -+ } -+ } -+ - ret = get_entry_as_uint32(res->msgs[0], &domain->subdomain_refresh_interval, - CONFDB_DOMAIN_SUBDOMAIN_REFRESH, 14400); - if (ret != EOK || domain->subdomain_refresh_interval == 0) { -@@ -1444,7 +1460,7 @@ int confdb_get_domains(struct confdb_ctx *cdb, - if (ret) { - DEBUG(SSSDBG_FATAL_FAILURE, - "Error (%d [%s]) retrieving domain [%s], skipping!\n", -- ret, sss_strerror(ret), domlist[i]); -+ ret, sss_strerror(ret), domlist[i]); - continue; - } - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index 56a603652d6c8256735e7f8b125300ff7b254645..a4046610f3cdbdb832de8924bf4397fb0018f2db 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -209,6 +209,9 @@ - #define CONFDB_DOMAIN_OFFLINE_TIMEOUT "offline_timeout" - #define CONFDB_DOMAIN_SUBDOMAIN_INHERIT "subdomain_inherit" - #define CONFDB_DOMAIN_CACHED_AUTH_TIMEOUT "cached_auth_timeout" -+#define CONFDB_DOMAIN_TYPE "domain_type" -+#define CONFDB_DOMAIN_TYPE_POSIX "posix" -+#define CONFDB_DOMAIN_TYPE_APP "application" - - /* Local Provider */ - #define CONFDB_LOCAL_DEFAULT_SHELL "default_shell" -@@ -261,11 +264,23 @@ enum sss_domain_state { - DOM_INCONSISTENT, - }; - -+/** Whether the domain only supports looking up POSIX entries */ -+enum sss_domain_type { -+ /** This is the default domain type. It resolves only entries -+ * with the full POSIX set of attributes -+ */ -+ DOM_TYPE_POSIX, -+ /** In this mode, entries are typically resolved only by name */ -+ DOM_TYPE_APPLICATION, -+}; -+ - /** - * Data structure storing all of the basic features - * of a domain. - */ - struct sss_domain_info { -+ enum sss_domain_type type; -+ - char *name; - char *conn_name; - char *provider; -diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in -index e7fb7673d393d4f12910f355d3edf33f4390c1f1..806611b6076048c08ce08c772dbd3cea5fdd656c 100644 ---- a/src/config/SSSDConfig/__init__.py.in -+++ b/src/config/SSSDConfig/__init__.py.in -@@ -148,6 +148,7 @@ option_strings = { - 'selinux_provider' : _('SELinux provider'), - - # [domain] -+ 'domain_type' : _('Whether the domain is usable by the OS or by applications'), - 'min_id' : _('Minimum user ID'), - 'max_id' : _('Maximum user ID'), - 'enumerate' : _('Enable enumerating all users/groups'), -diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py -index 6899bf8ae04bf210546c8cbdba8235f094e23dc0..9b3175962c697e314b3d5d94c2bc5beda537b66e 100755 ---- a/src/config/SSSDConfigTest.py -+++ b/src/config/SSSDConfigTest.py -@@ -510,6 +510,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): - 'debug', - 'debug_level', - 'debug_timestamps', -+ 'domain_type', - 'min_id', - 'max_id', - 'timeout', -@@ -878,6 +879,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): - 'debug', - 'debug_level', - 'debug_timestamps', -+ 'domain_type', - 'min_id', - 'max_id', - 'timeout', -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 41efcea552a82c5492a0d21a8d0797ee42cdc8c7..3c857236eaa55b313d176bc4bb479918163b60d5 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -311,6 +311,7 @@ option = subdomains_provider - option = selinux_provider - - # Options available to all domains -+option = domain_type - option = min_id - option = max_id - option = timeout -diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf -index 6965028e1ca748f8b6677d9fc1faa66d5c307a0c..a38b24208f89e4502e41625c540ea9958d5bbffe 100644 ---- a/src/config/etc/sssd.api.conf -+++ b/src/config/etc/sssd.api.conf -@@ -129,6 +129,7 @@ selinux_provider = str, None, false - [domain] - # Options available to all domains - description = str, None, false -+domain_type = str, None, false - debug = int, None, false - debug_level = int, None, false - debug_timestamps = bool, None, false -diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml -index 4fe13b85d511fb6a2ccc9b4de956710b05bc898c..9abcff84a95ea1b27e36845e830cc125fdc89f90 100644 ---- a/src/man/sssd.conf.5.xml -+++ b/src/man/sssd.conf.5.xml -@@ -1512,6 +1512,39 @@ pam_account_locked_message = Account locked, please contact help desk. - [domain/NAME] - - -+ domain_type (string) -+ -+ -+ Specifies whether the domain is meant to be used -+ by POSIX-aware clients such as the Name Service Switch -+ or by applications that do not need POSIX data to be -+ present or generated. Only objects from POSIX domains -+ are available to the operating system interfaces and -+ utilities. -+ -+ -+ Allowed values for this option are posix -+ and application. -+ -+ -+ POSIX domains are reachable by all services. Application -+ domains are only reachable from the InfoPipe responder (see -+ -+ sssd-ifp -+ 5 -+ ) and the PAM responder. -+ -+ -+ NOTE: The application domains are currently well tested with -+ id_provider=ldap only. -+ -+ -+ Default: posix -+ -+ -+ -+ -+ - min_id,max_id (integer) - - -diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c -index a7f118842aa8ba870143b2f2b425a3e3c0ea5a78..2af7852f03f89b61f5b9fd8a244e98fb27b7e6a2 100644 ---- a/src/util/domain_info_utils.c -+++ b/src/util/domain_info_utils.c -@@ -885,3 +885,17 @@ char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx, - subdomain->parent->name, - subdomain->name); - } -+ -+const char *sss_domain_type_str(struct sss_domain_info *dom) -+{ -+ if (dom == NULL) { -+ return "BUG: Invalid domain"; -+ } -+ switch (dom->type) { -+ case DOM_TYPE_POSIX: -+ return "POSIX"; -+ case DOM_TYPE_APPLICATION: -+ return "Application"; -+ } -+ return "Unknown"; -+} -diff --git a/src/util/util.h b/src/util/util.h -index 2170c5fb7cffda3910d2b58e33ec7abe3ec4a7d4..436550f5078cc173b8ed8cb58836d366f813146b 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -539,6 +539,7 @@ enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom); - void sss_domain_set_state(struct sss_domain_info *dom, - enum sss_domain_state state); - bool is_email_from_domain(const char *email, struct sss_domain_info *dom); -+const char *sss_domain_type_str(struct sss_domain_info *dom); - - struct sss_domain_info* - sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain, --- -2.9.3 - diff --git a/SOURCES/0061-test_responder-Check-memory-leak-in-sized_output_nam.patch b/SOURCES/0061-test_responder-Check-memory-leak-in-sized_output_nam.patch new file mode 100644 index 0000000..79da5fd --- /dev/null +++ b/SOURCES/0061-test_responder-Check-memory-leak-in-sized_output_nam.patch @@ -0,0 +1,58 @@ +From d624420972d061f72b08727bd7b2e227ce047272 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 28 Nov 2017 12:20:26 +0100 +Subject: [PATCH 61/67] test_responder: Check memory leak in sized_output_name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: +https://pagure.io/SSSD/sssd/issue/3588 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 051e0fc7cc86fb4e4b3a9323a61684ad3a6fa589) +--- + src/tests/cmocka/test_responder_common.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/src/tests/cmocka/test_responder_common.c b/src/tests/cmocka/test_responder_common.c +index fb7e4ee500570319999e6e85ee14a05cddea8de3..5441167caeb284982ee76926117da029966ec997 100644 +--- a/src/tests/cmocka/test_responder_common.c ++++ b/src/tests/cmocka/test_responder_common.c +@@ -316,6 +316,23 @@ void test_schedule_get_domains_task(void **state) + talloc_free(dummy_ncache_ptr); + } + ++void test_sss_output_fqname(void **state) ++{ ++ struct parse_inp_test_ctx *parse_inp_ctx = talloc_get_type(*state, ++ struct parse_inp_test_ctx); ++ errno_t ret; ++ struct sized_string *res = NULL; ++ ++ ret = sized_output_name(parse_inp_ctx, parse_inp_ctx->rctx, "dummy", ++ parse_inp_ctx->tctx->dom, &res); ++ assert_int_equal(ret, EOK); ++ assert_non_null(res); ++ assert_string_equal("dummy", res->str); ++ assert_int_equal(6, res->len); ++ ++ talloc_zfree(res); ++} ++ + int main(int argc, const char *argv[]) + { + int rv; +@@ -346,6 +363,9 @@ int main(int argc, const char *argv[]) + cmocka_unit_test_setup_teardown(test_schedule_get_domains_task, + parse_inp_test_setup, + parse_inp_test_teardown), ++ cmocka_unit_test_setup_teardown(test_sss_output_fqname, ++ parse_inp_test_setup, ++ parse_inp_test_teardown), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +-- +2.14.3 + diff --git a/SOURCES/0062-CONFDB-Allow-configuring-application-sections-as-non.patch b/SOURCES/0062-CONFDB-Allow-configuring-application-sections-as-non.patch deleted file mode 100644 index 24ecd56..0000000 --- a/SOURCES/0062-CONFDB-Allow-configuring-application-sections-as-non.patch +++ /dev/null @@ -1,531 +0,0 @@ -From 05ae58c86eae80c7e69fb809dc3cd89d0b7418f4 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 27 Mar 2017 09:48:46 +0200 -Subject: [PATCH 62/72] CONFDB: Allow configuring [application] sections as - non-POSIX domains -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related to: -https://pagure.io/SSSD/sssd/issue/3310 - -Allows to add a new section: - [application/$name] - -This section internally (on the confdb level) expands to: - [domain/$name] - domain_type = application - -The reasons to add this new section is two-fold. One, to make the -configuration of application domains more explicit and two, to make it -possible to share configuration between two domains, one POSIX and one -non-POSIX by application domain's inherit_from option: - [application/$name] - inherit_from = posix_domain_name - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/confdb/confdb.c | 288 ++++++++++++++++++++++++++++++++++++++++++++--- - src/confdb/confdb.h | 4 + - src/config/cfg_rules.ini | 9 +- - src/man/sssd.conf.5.xml | 77 +++++++++++++ - src/monitor/monitor.c | 8 ++ - 5 files changed, 368 insertions(+), 18 deletions(-) - -diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c -index 70a1eb7b2c7e83dfa9d217a15c7d3d4c8580b891..88e114457deac3ca50c291a131122624fb6f6fe4 100644 ---- a/src/confdb/confdb.c -+++ b/src/confdb/confdb.c -@@ -813,6 +813,50 @@ done: - return ret; - } - -+static int confdb_get_domain_section(TALLOC_CTX *mem_ctx, -+ struct confdb_ctx *cdb, -+ const char *section, -+ const char *name, -+ struct ldb_result **_res) -+{ -+ TALLOC_CTX *tmp_ctx; -+ int ret; -+ struct ldb_result *res; -+ struct ldb_dn *dn; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb, "cn=%s,%s", name, section); -+ if (dn == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, -+ LDB_SCOPE_BASE, NULL, NULL); -+ if (ret != LDB_SUCCESS) { -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ -+ if (res->count == 0) { -+ ret = ENOENT; -+ goto done; -+ } else if (res->count > 1) { -+ ret = E2BIG; -+ goto done; -+ } -+ -+ *_res = talloc_steal(mem_ctx, res); -+ ret = EOK; -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ - static int confdb_get_domain_internal(struct confdb_ctx *cdb, - TALLOC_CTX *mem_ctx, - const char *name, -@@ -821,7 +865,6 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, - struct sss_domain_info *domain; - struct ldb_result *res; - TALLOC_CTX *tmp_ctx; -- struct ldb_dn *dn; - const char *tmp; - int ret, val; - uint32_t entry_cache_timeout; -@@ -833,23 +876,15 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, - tmp_ctx = talloc_new(mem_ctx); - if (!tmp_ctx) return ENOMEM; - -- dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb, -- "cn=%s,%s", name, CONFDB_DOMAIN_BASEDN); -- if (!dn) { -- ret = ENOMEM; -- goto done; -- } -- -- ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, -- LDB_SCOPE_BASE, NULL, NULL); -- if (ret != LDB_SUCCESS) { -- ret = EIO; -- goto done; -- } -- -- if (res->count != 1) { -+ ret = confdb_get_domain_section(tmp_ctx, cdb, CONFDB_DOMAIN_BASEDN, -+ name, &res); -+ if (ret == ENOENT) { - DEBUG(SSSDBG_FATAL_FAILURE, "Unknown domain [%s]\n", name); -- ret = ENOENT; -+ goto done; -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "Error %d: %s while retrieving %s\n", -+ ret, sss_strerror(ret), name); - goto done; - } - -@@ -1841,3 +1876,222 @@ int confdb_ensure_files_domain(struct confdb_ctx *cdb, - return activate_files_domain(cdb, implicit_files_dom_name); - #endif /* ADD_FILES_DOMAIN */ - } -+ -+static int confdb_get_parent_domain(TALLOC_CTX *mem_ctx, -+ const char *name, -+ struct confdb_ctx *cdb, -+ struct ldb_result *app_dom, -+ struct ldb_result **_parent_dom) -+{ -+ const char *inherit_from; -+ -+ inherit_from = ldb_msg_find_attr_as_string(app_dom->msgs[0], -+ CONFDB_DOMAIN_INHERIT_FROM, NULL); -+ if (inherit_from == NULL) { -+ DEBUG(SSSDBG_CONF_SETTINGS, -+ "%s does not inherit from any POSIX domain\n", name); -+ *_parent_dom = NULL; -+ return EOK; -+ } -+ -+ return confdb_get_domain_section(mem_ctx, cdb, -+ CONFDB_DOMAIN_BASEDN, inherit_from, -+ _parent_dom); -+} -+ -+static int confdb_add_app_domain(TALLOC_CTX *mem_ctx, -+ struct confdb_ctx *cdb, -+ const char *name) -+{ -+ char *cdb_path = NULL; -+ const char *val[2] = { NULL, NULL }; -+ int ret; -+ -+ cdb_path = talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL, name); -+ if (cdb_path == NULL) { -+ return ENOMEM; -+ } -+ -+ val[0] = CONFDB_DOMAIN_TYPE_APP; -+ ret = confdb_add_param(cdb, true, cdb_path, CONFDB_DOMAIN_TYPE, val); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add id_provider [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return ret; -+ } -+ -+ return EOK; -+} -+ -+static int confdb_merge_parent_domain(const char *name, -+ struct confdb_ctx *cdb, -+ struct ldb_result *app_section) -+{ -+ int ret; -+ int ldb_flag; -+ struct ldb_result *parent_domain = NULL; -+ struct ldb_message *replace_msg = NULL; -+ struct ldb_message *app_msg = NULL; -+ struct ldb_dn *domain_dn; -+ TALLOC_CTX *tmp_ctx = NULL; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); -+ return ENOMEM; -+ } -+ -+ domain_dn = ldb_dn_new_fmt(tmp_ctx, -+ cdb->ldb, -+ "%s=%s,%s", -+ CONFDB_DOMAIN_ATTR, -+ name, -+ CONFDB_DOMAIN_BASEDN); -+ if (domain_dn == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ /* Copy the parent domain parameters */ -+ ret = confdb_get_parent_domain(tmp_ctx, name, cdb, -+ app_section, &parent_domain); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot retrieve the parent domain [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ if (parent_domain != NULL) { -+ replace_msg = ldb_msg_copy(tmp_ctx, parent_domain->msgs[0]); -+ if (replace_msg == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ replace_msg->dn = domain_dn; -+ -+ for (unsigned i = 0; i < replace_msg->num_elements; i++) { -+ replace_msg->elements[i].flags = LDB_FLAG_MOD_ADD; -+ } -+ -+ ret = ldb_modify(cdb->ldb, replace_msg); -+ if (ret != LDB_SUCCESS) { -+ ret = sysdb_error_to_errno(ret); -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Inheriting options from parent domain failed [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ } -+ -+ /* Finally, add any app-domain specific overrides */ -+ app_msg = ldb_msg_new(tmp_ctx); -+ if (app_msg == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ app_msg->dn = domain_dn; -+ -+ for (unsigned i = 0; i < app_section->msgs[0]->num_elements; i++) { -+ struct ldb_message_element *el = NULL; -+ -+ if (replace_msg != NULL) { -+ el = ldb_msg_find_element(replace_msg, -+ app_section->msgs[0]->elements[i].name); -+ if (el == NULL) { -+ /* Adding an element */ -+ ldb_flag = LDB_FLAG_MOD_ADD; -+ } else { -+ /* Overriding an element */ -+ ldb_flag = LDB_FLAG_MOD_REPLACE; -+ } -+ } else { -+ /* If there was no domain to inherit from, just add all */ -+ ldb_flag = LDB_FLAG_MOD_ADD; -+ } -+ -+ ret = ldb_msg_add(app_msg, -+ &app_section->msgs[0]->elements[i], -+ ldb_flag); -+ if (ret != EOK) { -+ continue; -+ } -+ } -+ -+ ret = ldb_modify(cdb->ldb, app_msg); -+ if (ret != LDB_SUCCESS) { -+ ret = sysdb_error_to_errno(ret); -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Adding app-specific options failed [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ DEBUG(SSSDBG_TRACE_LIBS, "Added a domain section for %s\n", name); -+ ret = EOK; -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ -+int confdb_expand_app_domains(struct confdb_ctx *cdb) -+{ -+ int ret; -+ char **domlist; -+ TALLOC_CTX *tmp_ctx; -+ struct ldb_result *app_domain = NULL; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = confdb_get_string_as_list(cdb, tmp_ctx, -+ CONFDB_MONITOR_CONF_ENTRY, -+ CONFDB_MONITOR_ACTIVE_DOMAINS, -+ &domlist); -+ if (ret == ENOENT) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured, fatal error!\n"); -+ goto done; -+ } else if (ret != EOK ) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error retrieving domains list!\n"); -+ goto done; -+ } -+ -+ for (int i = 0; domlist[i]; i++) { -+ ret = confdb_get_domain_section(tmp_ctx, cdb, -+ CONFDB_APP_DOMAIN_BASEDN, domlist[i], -+ &app_domain); -+ if (ret == ENOENT) { -+ DEBUG(SSSDBG_TRACE_INTERNAL, -+ "%s is not an app domain\n", domlist[i]); -+ continue; -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "Error %d: %s while retrieving %s\n", -+ ret, sss_strerror(ret), domlist[i]); -+ goto done; -+ } -+ -+ ret = confdb_add_app_domain(tmp_ctx, cdb, domlist[i]); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot add the app domain section [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ ret = confdb_merge_parent_domain(domlist[i], cdb, app_domain); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot add options into the app domain section [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ } -+ -+ ret = EOK; -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index a4046610f3cdbdb832de8924bf4397fb0018f2db..5a8d377c312f641f544b1c7cf38826192462ea3c 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -164,6 +164,7 @@ - /* Domains */ - #define CONFDB_DOMAIN_PATH_TMPL "config/domain/%s" - #define CONFDB_DOMAIN_BASEDN "cn=domain,cn=config" -+#define CONFDB_APP_DOMAIN_BASEDN "cn=application,cn=config" - #define CONFDB_DOMAIN_ID_PROVIDER "id_provider" - #define CONFDB_DOMAIN_AUTH_PROVIDER "auth_provider" - #define CONFDB_DOMAIN_ACCESS_PROVIDER "access_provider" -@@ -212,6 +213,7 @@ - #define CONFDB_DOMAIN_TYPE "domain_type" - #define CONFDB_DOMAIN_TYPE_POSIX "posix" - #define CONFDB_DOMAIN_TYPE_APP "application" -+#define CONFDB_DOMAIN_INHERIT_FROM "inherit_from" - - /* Local Provider */ - #define CONFDB_LOCAL_DEFAULT_SHELL "default_shell" -@@ -398,6 +400,8 @@ int confdb_get_domains(struct confdb_ctx *cdb, - int confdb_ensure_files_domain(struct confdb_ctx *cdb, - const char *implicit_files_dom_name); - -+int confdb_expand_app_domains(struct confdb_ctx *cdb); -+ - /** - * Get a null-terminated linked-list of all domain names - * @param[in] mem_ctx The parent memory context for the value list -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 3c857236eaa55b313d176bc4bb479918163b60d5..8fd2d2c5236246394353a88c50d1510bd6233f77 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -12,6 +12,7 @@ section = secrets - section = kcm - section_re = ^secrets/users/[0-9]\+$ - section_re = ^domain/.*$ -+section_re = ^application/.*$ - - [rule/allowed_sssd_options] - validator = ini_allowed_options -@@ -286,7 +287,7 @@ option = responder_idle_timeout - - [rule/allowed_domain_options] - validator = ini_allowed_options --section_re = ^domain/.*$ -+section_re = ^(domain|application)/.*$ - - option = debug - option = debug_level -@@ -684,3 +685,9 @@ option = ldap_user_ssh_public_key - option = ldap_user_uid_number - option = ldap_user_uuid - option = ldap_use_tokengroups -+ -+[rule/allowed_application_options] -+validator = ini_allowed_options -+section_re = ^application/.*$ -+ -+option = inherit_from -diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml -index 9abcff84a95ea1b27e36845e830cc125fdc89f90..8294793c765bfa6bf481693c7d7f206950454681 100644 ---- a/src/man/sssd.conf.5.xml -+++ b/src/man/sssd.conf.5.xml -@@ -1539,6 +1539,10 @@ pam_account_locked_message = Account locked, please contact help desk. - id_provider=ldap only. - - -+ For an easy way to configure a non-POSIX domains, please -+ see the Application domains section. -+ -+ - Default: posix - - -@@ -2692,6 +2696,79 @@ subdomain_inherit = ldap_purge_cache_timeout - - - -+ -+ Application domains -+ -+ SSSD, with its D-Bus interface (see -+ -+ sssd-ifp -+ 5 -+ ) is appealing to applications -+ as a gateway to an LDAP directory where users and groups -+ are stored. However, contrary to the traditional SSSD -+ deployment where all users and groups either have POSIX -+ attributes or those attributes can be inferred from the -+ Windows SIDs, in many cases the users and groups in the -+ application support scenario have no POSIX attributes. -+ Instead of setting a -+ [domain/NAME] -+ section, the administrator can set up an -+ [application/NAME] -+ section that internally represents a domain with type -+ application optionally inherits settings -+ from a tradition SSSD domain. -+ -+ -+ Please note that the application domain must still be -+ explicitly enabled in the domains parameter -+ so that the lookup order between the application domain -+ and its POSIX sibling domain is set correctly. -+ -+ -+ Application domain parameters -+ -+ inherit_from (string) -+ -+ -+ The SSSD POSIX-type domain the application -+ domain inherits all settings from. The -+ application domain can moreover add its own -+ settings to the application settings that augment -+ or override the sibling -+ domain settings. -+ -+ -+ Default: Not set -+ -+ -+ -+ -+ -+ The following example illustrates the use of an application -+ domain. In this setup, the POSIX domain is connected to an LDAP -+ server and is used by the OS through the NSS responder. In addition, -+ the application domains also requests the telephoneNumber attribute, -+ stores it as the phone attribute in the cache and makes the phone -+ attribute reachable through the D-Bus interface. -+ -+ -+[sssd] -+domains = appdom, posixdom -+ -+[ifp] -+user_attributes = +phone -+ -+[domain/posixdom] -+id_provider = ldap -+ldap_uri = ldap://ldap.example.com -+ldap_search_base = dc=example,dc=com -+ -+[application/appdom] -+inherit_from = posixdom -+ldap_user_extra_attrs = phone:telephoneNumber -+ -+ -+ - - The local domain section - -diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c -index 7e7b5a07d11aecf1c0b11592213b90d385fd5076..2753b46667f7ae0b022776862c67a327d3356d6d 100644 ---- a/src/monitor/monitor.c -+++ b/src/monitor/monitor.c -@@ -1064,6 +1064,14 @@ static int get_monitor_config(struct mt_ctx *ctx) - /* Not fatal */ - } - -+ ret = confdb_expand_app_domains(ctx->cdb); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to expand application domains\n"); -+ /* This must not be fatal so that SSSD keeps running and lets -+ * admin correct the error. -+ */ -+ } -+ - ret = confdb_get_domains(ctx->cdb, &ctx->domains); - if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured.\n"); --- -2.9.3 - diff --git a/SOURCES/0062-UTIL-add-find_domain_by_object_name_ex.patch b/SOURCES/0062-UTIL-add-find_domain_by_object_name_ex.patch new file mode 100644 index 0000000..321cedc --- /dev/null +++ b/SOURCES/0062-UTIL-add-find_domain_by_object_name_ex.patch @@ -0,0 +1,82 @@ +From ab9a8db7539bea30effe398d9bd82b1ecadd8a6f Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 12:08:30 +0100 +Subject: [PATCH 62/67] UTIL: add find_domain_by_object_name_ex() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The _ex version of find_domain_by_object_name() has a additional option +'strict'. If set to 'true' NULL is return instead to domain from the +first argument. This way the caller can see if the provider object name +really contains a known domain. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit b6d3da6cfe78c6d0ddb854088bc23e293b336401) +--- + src/util/domain_info_utils.c | 17 ++++++++++++++--- + src/util/util.h | 4 ++++ + 2 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c +index 3a3f5130a32e2c5fe4b81819bf2de697a4474111..66077092a40111967a98b0937506d9e4472f50d5 100644 +--- a/src/util/domain_info_utils.c ++++ b/src/util/domain_info_utils.c +@@ -174,8 +174,8 @@ sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain, + } + + struct sss_domain_info * +-find_domain_by_object_name(struct sss_domain_info *domain, +- const char *object_name) ++find_domain_by_object_name_ex(struct sss_domain_info *domain, ++ const char *object_name, bool strict) + { + TALLOC_CTX *tmp_ctx; + struct sss_domain_info *dom = NULL; +@@ -197,7 +197,11 @@ find_domain_by_object_name(struct sss_domain_info *domain, + } + + if (domainname == NULL) { +- dom = domain; ++ if (strict) { ++ dom = NULL; ++ } else { ++ dom = domain; ++ } + } else { + dom = find_domain_by_name(domain, domainname, true); + } +@@ -207,6 +211,13 @@ done: + return dom; + } + ++struct sss_domain_info * ++find_domain_by_object_name(struct sss_domain_info *domain, ++ const char *object_name) ++{ ++ return find_domain_by_object_name_ex(domain, object_name, false); ++} ++ + errno_t sssd_domain_init(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *domain_name, +diff --git a/src/util/util.h b/src/util/util.h +index 37383011763a9a2a3c2c066215e3ed94aca77308..2521b1789b0b8701b1fbcce33890eedb7fe18d5e 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -551,6 +551,10 @@ struct sss_domain_info * + find_domain_by_object_name(struct sss_domain_info *domain, + const char *object_name); + ++struct sss_domain_info * ++find_domain_by_object_name_ex(struct sss_domain_info *domain, ++ const char *object_name, bool strict); ++ + bool subdomain_enumerates(struct sss_domain_info *parent, + const char *sd_name); + +-- +2.14.3 + diff --git a/SOURCES/0063-CACHE_REQ-Domain-type-selection-in-cache_req.patch b/SOURCES/0063-CACHE_REQ-Domain-type-selection-in-cache_req.patch deleted file mode 100644 index 86b6c73..0000000 --- a/SOURCES/0063-CACHE_REQ-Domain-type-selection-in-cache_req.patch +++ /dev/null @@ -1,976 +0,0 @@ -From 5519295726bb2a0e88475e1d8deff0b8c0f65119 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 24 Mar 2017 10:39:12 +0100 -Subject: [PATCH 63/72] CACHE_REQ: Domain type selection in cache_req -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related to: - https://pagure.io/SSSD/sssd/issue/3310 - -Adds a new enumeration cache_req_dom_type. It is a tri-state that -allows the caller to select which domains can be contacted - either only -POSIX, only application domains or any type. - -Not all plugins of cache_req have the new parameter added -- only those -that are usable/useful in a non-POSIX environment. For example, it makes -no sense to allow the selection for calls by ID because those are -inherently POSIX-specific. Also, services or netgroups are supported -only coming from POSIX domains. - -At the moment, the patch should not change any behaviour as all calls -default to contacting POSIX domains only. - -Reviewed-by: Pavel Březina ---- - src/responder/common/cache_req/cache_req.c | 80 ++++++++++++++++++++-- - src/responder/common/cache_req/cache_req.h | 19 +++++ - src/responder/common/cache_req/cache_req_private.h | 3 + - .../cache_req/plugins/cache_req_enum_groups.c | 4 +- - .../common/cache_req/plugins/cache_req_enum_svc.c | 3 +- - .../cache_req/plugins/cache_req_enum_users.c | 4 +- - .../cache_req/plugins/cache_req_group_by_filter.c | 5 +- - .../cache_req/plugins/cache_req_group_by_id.c | 4 +- - .../cache_req/plugins/cache_req_group_by_name.c | 5 +- - .../cache_req/plugins/cache_req_host_by_name.c | 4 +- - .../plugins/cache_req_initgroups_by_name.c | 5 +- - .../cache_req/plugins/cache_req_netgroup_by_name.c | 4 +- - .../cache_req/plugins/cache_req_object_by_id.c | 4 +- - .../cache_req/plugins/cache_req_object_by_name.c | 4 +- - .../cache_req/plugins/cache_req_object_by_sid.c | 4 +- - .../cache_req/plugins/cache_req_svc_by_name.c | 4 +- - .../cache_req/plugins/cache_req_svc_by_port.c | 4 +- - .../cache_req/plugins/cache_req_user_by_cert.c | 4 +- - .../cache_req/plugins/cache_req_user_by_filter.c | 5 +- - .../cache_req/plugins/cache_req_user_by_id.c | 4 +- - .../cache_req/plugins/cache_req_user_by_name.c | 9 ++- - src/responder/ifp/ifp_groups.c | 14 +++- - src/responder/ifp/ifp_users.c | 19 +++-- - src/responder/ifp/ifpsrv_cmd.c | 3 +- - src/responder/nss/nss_enum.c | 2 +- - src/responder/nss/nss_get_object.c | 3 +- - src/responder/pam/pamsrv_cmd.c | 5 +- - src/responder/sudo/sudosrv_get_sudorules.c | 3 +- - src/tests/cmocka/test_responder_cache_req.c | 62 ++++++++++++++--- - 29 files changed, 246 insertions(+), 47 deletions(-) - -diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c -index 483126396f8addbad744ae03bfc739801cd0c18b..3a5fecf34427437bbf95317e05c5bd8b07b4537d 100644 ---- a/src/responder/common/cache_req/cache_req.c -+++ b/src/responder/common/cache_req/cache_req.c -@@ -89,12 +89,31 @@ static errno_t cache_req_set_plugin(struct cache_req *cr, - return EOK; - } - -+static const char * -+cache_req_dom_type_as_str(struct cache_req *cr) -+{ -+ if (cr == NULL) { -+ return "BUG: Invalid cache_req pointer\n"; -+ } -+ switch (cr->req_dom_type) { -+ case CACHE_REQ_POSIX_DOM: -+ return "POSIX-only"; -+ case CACHE_REQ_APPLICATION_DOM: -+ return "Application-only"; -+ case CACHE_REQ_ANY_DOM: -+ return "Any"; -+ } -+ -+ return "Unknown"; -+} -+ - static struct cache_req * - cache_req_create(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct cache_req_data *data, - struct sss_nc_ctx *ncache, -- int midpoint) -+ int midpoint, -+ enum cache_req_dom_type req_dom_type) - { - struct cache_req *cr; - errno_t ret; -@@ -108,6 +127,7 @@ cache_req_create(TALLOC_CTX *mem_ctx, - cr->data = data; - cr->ncache = ncache; - cr->midpoint = midpoint; -+ cr->req_dom_type = req_dom_type; - cr->req_start = time(NULL); - - /* It is perfectly fine to just overflow here. */ -@@ -145,8 +165,8 @@ cache_req_set_name(struct cache_req *cr, const char *name) - } - - static bool --cache_req_validate_domain(struct cache_req *cr, -- struct sss_domain_info *domain) -+cache_req_validate_domain_enumeration(struct cache_req *cr, -+ struct sss_domain_info *domain) - { - if (!cr->plugin->require_enumeration) { - return true; -@@ -164,6 +184,52 @@ cache_req_validate_domain(struct cache_req *cr, - return true; - } - -+static bool -+cache_req_validate_domain_type(struct cache_req *cr, -+ struct sss_domain_info *domain) -+{ -+ bool valid = false; -+ -+ switch (cr->req_dom_type) { -+ case CACHE_REQ_POSIX_DOM: -+ valid = domain->type == DOM_TYPE_POSIX ? true : false; -+ break; -+ case CACHE_REQ_APPLICATION_DOM: -+ valid = domain->type == DOM_TYPE_APPLICATION ? true : false; -+ break; -+ case CACHE_REQ_ANY_DOM: -+ valid = true; -+ break; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, -+ "Request type %s for domain %s type %s is %svalid\n", -+ cache_req_dom_type_as_str(cr), -+ domain->name, -+ sss_domain_type_str(domain), -+ valid ? "" : "not "); -+ return valid; -+} -+ -+static bool -+cache_req_validate_domain(struct cache_req *cr, -+ struct sss_domain_info *domain) -+{ -+ bool ok; -+ -+ ok = cache_req_validate_domain_enumeration(cr, domain); -+ if (ok == false) { -+ return false; -+ } -+ -+ ok = cache_req_validate_domain_type(cr, domain); -+ if (ok == false) { -+ return false; -+ } -+ -+ return true; -+} -+ - static errno_t - cache_req_is_well_known_object(TALLOC_CTX *mem_ctx, - struct cache_req *cr, -@@ -651,6 +717,7 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int midpoint, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - struct cache_req_data *data) - { -@@ -667,7 +734,8 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, - } - - state->ev = ev; -- state->cr = cr = cache_req_create(state, rctx, data, ncache, midpoint); -+ state->cr = cr = cache_req_create(state, rctx, data, -+ ncache, midpoint, req_dom_type); - if (state->cr == NULL) { - ret = ENOMEM; - goto done; -@@ -952,13 +1020,15 @@ cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int cache_refresh_percent, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - struct cache_req_data *data) - { - struct tevent_req *req; - - req = cache_req_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ req_dom_type, domain, data); - if (req == NULL) { - talloc_zfree(data); - return NULL; -diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h -index d0e5ff43921467fc191fd5cc7d5b49cc039b7f67..c04b2fba6f0445dcfcc9cfe1b5963ac975c39118 100644 ---- a/src/responder/common/cache_req/cache_req.h -+++ b/src/responder/common/cache_req/cache_req.h -@@ -57,6 +57,18 @@ enum cache_req_type { - CACHE_REQ_SENTINEL - }; - -+/* Whether to limit the request type to a certain domain type -+ * (POSIX/non-POSIX) -+ */ -+enum cache_req_dom_type { -+ /* Only look up data in POSIX domains */ -+ CACHE_REQ_POSIX_DOM, -+ /* Only look up data in application domains */ -+ CACHE_REQ_APPLICATION_DOM, -+ /* Look up data in any domain type */ -+ CACHE_REQ_ANY_DOM -+}; -+ - /* Input data. */ - - struct cache_req_data; -@@ -172,6 +184,7 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int midpoint, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - struct cache_req_data *data); - -@@ -191,6 +204,7 @@ cache_req_user_by_name_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int cache_refresh_percent, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *name); - -@@ -228,6 +242,7 @@ cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int cache_refresh_percent, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *pem_cert); - -@@ -240,6 +255,7 @@ cache_req_group_by_name_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int cache_refresh_percent, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *name); - -@@ -264,6 +280,7 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int cache_refresh_percent, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *name); - -@@ -274,6 +291,7 @@ struct tevent_req * - cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct resp_ctx *rctx, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *filter); - -@@ -284,6 +302,7 @@ struct tevent_req * - cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct resp_ctx *rctx, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *filter); - -diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h -index 2d3c1870795e4fd5667f603280edcee24f926220..851005c389f994b1bd2d04cda9b68df8b18492cc 100644 ---- a/src/responder/common/cache_req/cache_req_private.h -+++ b/src/responder/common/cache_req/cache_req_private.h -@@ -42,6 +42,8 @@ struct cache_req { - struct sss_domain_info *domain; - bool cache_first; - bool bypass_cache; -+ /* Only contact domains with this type */ -+ enum cache_req_dom_type req_dom_type; - - /* Debug information */ - uint32_t reqid; -@@ -108,6 +110,7 @@ cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int cache_refresh_percent, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - struct cache_req_data *data); - -diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c -index dbb40c98339cc9295e3678e05340396aff51ac78..49ce3508e678862e4389657187b9659ce90fbd1c 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c -+++ b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c -@@ -96,5 +96,7 @@ cache_req_enum_groups_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c -index 28dea33c601f500b9c7af0de3eb9e1c342f03522..499b994738d62707b4e86d5a8383e3e2b82e8c57 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c -+++ b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c -@@ -97,5 +97,6 @@ cache_req_enum_svc_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_users.c b/src/responder/common/cache_req/plugins/cache_req_enum_users.c -index 3b1a85841e3ed853cd329dfa9d762cb7a05cbd43..b635354be6e9d2e2e2af1a6f867ac68e6cf7f085 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_enum_users.c -+++ b/src/responder/common/cache_req/plugins/cache_req_enum_users.c -@@ -96,5 +96,7 @@ cache_req_enum_users_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c -index 6ce6ae0d63967ac50b813a47ac938251619948da..4377a476c36e5e03c8533bc62335b84fa1cee3ff 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c -+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c -@@ -140,6 +140,7 @@ struct tevent_req * - cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct resp_ctx *rctx, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *filter) - { -@@ -151,5 +152,7 @@ cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, NULL, -- 0, domain, data); -+ 0, -+ req_dom_type, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -index e98f76f8cd20742b81ae247df61db159d2584a17..ad5b7d890a42f29b586ab8e0943fef3dfab1162d 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -@@ -166,5 +166,7 @@ cache_req_group_by_id_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c -index af6f23ccfd68f952027462ba3e74ed7219d04651..de1e8f9442273acf386a2278b06f28ee63a7e3c6 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c -@@ -205,6 +205,7 @@ cache_req_group_by_name_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int cache_refresh_percent, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *name) - { -@@ -216,5 +217,7 @@ cache_req_group_by_name_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ req_dom_type, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c -index 77b46831fec3abc4126ef9d9be67221469801094..1171cd63fac5cc1d36b31bf8a069f059705cae90 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c -@@ -117,5 +117,7 @@ cache_req_host_by_name_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c -index 307b65a24282838b99c472b50a71f06865aed3f0..f100aefe5c92279cde7e3209c7f48f5e2b35f135 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c -@@ -220,6 +220,7 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int cache_refresh_percent, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *name) - { -@@ -231,5 +232,7 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ req_dom_type, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -index e49d6d84a41ce8dabf18c87373826f8e7b684bda..ab3e553d3ecb8ae09094dcfc938ed0ac01925327 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -@@ -150,5 +150,7 @@ cache_req_netgroup_by_name_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -index 046e313c83d1d4c75237b047be779201b8a5d3c0..9557bd15270b2eb1a0671f9ef91033efac29c3ac 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -@@ -134,5 +134,7 @@ cache_req_object_by_id_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c -index 74d2b3dea287e890b38e4d5bb176ad2dc6337b7e..e236d1fa4aadcd87b192d34ebaf5f9ad8908b6c2 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c -@@ -228,5 +228,7 @@ cache_req_object_by_name_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c -index ab577663111cfd424e7f46308b2621af7f1ca264..dfec79da07d669165205a767cab22c2254686134 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c -+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c -@@ -143,5 +143,7 @@ cache_req_object_by_sid_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c -index ef13f097a8ae78ec9db5b7f6e14924b511578b34..b2bfb26ffed1a60ed8389fa89b0e728c8c6cf76c 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c -@@ -175,5 +175,7 @@ cache_req_svc_by_name_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c -index afa2eeeda12794de26e798aee4b88900bc87ed93..0e48437f4b64d26112be88af1eebc20f012b70fd 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c -+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c -@@ -149,5 +149,7 @@ cache_req_svc_by_port_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c -index f237c8d0fe3faf5aea553480f3f92eb279209a20..286a34db276e0098060982c572e2a68ceceebf60 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c -@@ -105,6 +105,7 @@ cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int cache_refresh_percent, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *pem_cert) - { -@@ -117,5 +118,6 @@ cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx, - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, - cache_refresh_percent, -- domain, data); -+ req_dom_type, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c -index eb71b42dad3a805298df0c8425409d571befb31b..c476814373cd784bf8dbbea1da7b010afe5bb4e4 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c -@@ -140,6 +140,7 @@ struct tevent_req * - cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct resp_ctx *rctx, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *filter) - { -@@ -151,5 +152,7 @@ cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, NULL, -- 0, domain, data); -+ 0, -+ req_dom_type, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -index fa783714b7c67ca029d18a223b64a3a69e3e6929..9ba73292e5dc518e86c6e00e7e493d6871f28e70 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -@@ -166,5 +166,7 @@ cache_req_user_by_id_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c -index 0670febdce2d51e0373045570dd07f56255db7bc..15da7d0d20b1ac97511a226daecc8ef7e7d2e7e4 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c -@@ -210,6 +210,7 @@ cache_req_user_by_name_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_nc_ctx *ncache, - int cache_refresh_percent, -+ enum cache_req_dom_type req_dom_type, - const char *domain, - const char *name) - { -@@ -221,7 +222,9 @@ cache_req_user_by_name_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ req_dom_type, domain, -+ data); - } - - struct tevent_req * -@@ -243,5 +246,7 @@ cache_req_user_by_name_attrs_send(TALLOC_CTX *mem_ctx, - } - - return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, -- cache_refresh_percent, domain, data); -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, domain, -+ data); - } -diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c -index 94d1e84cc9de75727d3c47c0a5a24790d21ce132..99908e96bd971bce4b4e9064a77d8413f837d743 100644 ---- a/src/responder/ifp/ifp_groups.c -+++ b/src/responder/ifp/ifp_groups.c -@@ -118,7 +118,9 @@ int ifp_groups_find_by_name(struct sbus_request *sbus_req, - } - - req = cache_req_group_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, -- ctx->rctx->ncache, 0, NULL, name); -+ ctx->rctx->ncache, 0, -+ CACHE_REQ_POSIX_DOM, NULL, -+ name); - if (req == NULL) { - return ENOMEM; - } -@@ -271,6 +273,7 @@ static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx) - req = cache_req_group_by_filter_send(list_ctx, - list_ctx->ctx->rctx->ev, - list_ctx->ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - list_ctx->dom->name, - list_ctx->filter); - if (req == NULL) { -@@ -355,7 +358,8 @@ int ifp_groups_list_by_domain_and_name(struct sbus_request *sbus_req, - } - - req = cache_req_group_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx, -- domain, filter); -+ CACHE_REQ_POSIX_DOM, -+ domain, filter); - if (req == NULL) { - return ENOMEM; - } -@@ -522,7 +526,10 @@ static struct tevent_req *resolv_ghosts_send(TALLOC_CTX *mem_ctx, - } - - subreq = cache_req_group_by_name_send(state, ev, ctx->rctx, -- ctx->rctx->ncache, 0, domain->name, name); -+ ctx->rctx->ncache, 0, -+ CACHE_REQ_POSIX_DOM, -+ domain->name, -+ name); - if (subreq == NULL) { - ret = ENOMEM; - goto immediately; -@@ -601,6 +608,7 @@ errno_t resolv_ghosts_step(struct tevent_req *req) - - subreq = cache_req_user_by_name_send(state, state->ev, state->ctx->rctx, - state->ctx->rctx->ncache, 0, -+ CACHE_REQ_POSIX_DOM, - state->domain->name, - state->ghosts[state->index]); - if (subreq == NULL) { -diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c -index cc78300f31e863fcb5366e18a14abc597c6f7ddb..436bb268fa9c78d72fb744e0d338aa561a7d8764 100644 ---- a/src/responder/ifp/ifp_users.c -+++ b/src/responder/ifp/ifp_users.c -@@ -99,7 +99,9 @@ int ifp_users_find_by_name(struct sbus_request *sbus_req, - } - - req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, -- ctx->rctx->ncache, 0, NULL, name); -+ ctx->rctx->ncache, 0, -+ CACHE_REQ_POSIX_DOM, -+ NULL, name); - if (req == NULL) { - return ENOMEM; - } -@@ -253,7 +255,9 @@ int ifp_users_find_by_cert(struct sbus_request *sbus_req, void *data, - } - - req = cache_req_user_by_cert_send(sbus_req, ctx->rctx->ev, ctx->rctx, -- ctx->rctx->ncache, 0, NULL, derb64); -+ ctx->rctx->ncache, 0, -+ CACHE_REQ_POSIX_DOM, NULL, -+ derb64); - if (req == NULL) { - return ENOMEM; - } -@@ -367,6 +371,7 @@ static int ifp_users_list_by_cert_step(struct ifp_list_ctx *list_ctx) - list_ctx->ctx->rctx, - list_ctx->ctx->rctx->ncache, - 0, -+ CACHE_REQ_POSIX_DOM, - list_ctx->dom->name, - list_ctx->filter); - if (req == NULL) { -@@ -532,7 +537,9 @@ int ifp_users_find_by_name_and_cert(struct sbus_request *sbus_req, void *data, - - if (name_and_cert_ctx->name != NULL) { - req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, -- ctx->rctx->ncache, 0, NULL, -+ ctx->rctx->ncache, 0, -+ CACHE_REQ_POSIX_DOM, -+ NULL, - name_and_cert_ctx->name); - if (req == NULL) { - return ENOMEM; -@@ -614,6 +621,7 @@ static int ifp_users_find_by_name_and_cert_step( - list_ctx->ctx->rctx, - list_ctx->ctx->rctx->ncache, - 0, -+ CACHE_REQ_POSIX_DOM, - list_ctx->dom->name, - list_ctx->filter); - if (req == NULL) { -@@ -774,6 +782,7 @@ static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx) - req = cache_req_user_by_filter_send(list_ctx, - list_ctx->ctx->rctx->ev, - list_ctx->ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - list_ctx->dom->name, - list_ctx->filter); - if (req == NULL) { -@@ -858,6 +867,7 @@ int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req, - } - - req = cache_req_user_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - domain, filter); - if (req == NULL) { - return ENOMEM; -@@ -1102,7 +1112,8 @@ int ifp_users_user_update_groups_list(struct sbus_request *sbus_req, - } - - req = cache_req_initgr_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, -- ctx->rctx->ncache, 0, domain->name, -+ ctx->rctx->ncache, 0, -+ CACHE_REQ_POSIX_DOM, domain->name, - username); - if (req == NULL) { - return ENOMEM; -diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c -index 07edcddffa1091f8bbcf79a25962aadc791bb890..118b5083b14bf5692c6fdd7ba90668fe514aa89d 100644 ---- a/src/responder/ifp/ifpsrv_cmd.c -+++ b/src/responder/ifp/ifpsrv_cmd.c -@@ -509,7 +509,8 @@ ifp_user_get_attr_lookup(struct tevent_req *subreq) - } - - subreq = cache_req_send(state, state->rctx->ev, state->rctx, -- state->ncache, 0, state->domname, data); -+ state->ncache, 0, CACHE_REQ_POSIX_DOM, -+ state->domname, data); - if (subreq == NULL) { - tevent_req_error(req, ENOMEM); - return; -diff --git a/src/responder/nss/nss_enum.c b/src/responder/nss/nss_enum.c -index b1cce2cde43ece735285c132d0127c142ee83cb0..aa7d8428f37e943a6b5904495c40ad4b8011b767 100644 ---- a/src/responder/nss/nss_enum.c -+++ b/src/responder/nss/nss_enum.c -@@ -93,7 +93,7 @@ nss_setent_internal_send(TALLOC_CTX *mem_ctx, - /* Create new object. */ - state->enum_ctx->is_ready = false; - subreq = cache_req_send(req, ev, cli_ctx->rctx, cli_ctx->rctx->ncache, -- 0, NULL, data); -+ 0, CACHE_REQ_POSIX_DOM, NULL, data); - if (subreq == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send cache request!\n"); - ret = ENOMEM; -diff --git a/src/responder/nss/nss_get_object.c b/src/responder/nss/nss_get_object.c -index f83dd393c0e333d8914802e005672a15a51d5939..9058793ea2d72b57003a7219414af6a0f0c5b89e 100644 ---- a/src/responder/nss/nss_get_object.c -+++ b/src/responder/nss/nss_get_object.c -@@ -190,7 +190,8 @@ nss_get_object_send(TALLOC_CTX *mem_ctx, - } - - subreq = cache_req_send(req, ev, cli_ctx->rctx, cli_ctx->rctx->ncache, -- state->nss_ctx->cache_refresh_percent, NULL, data); -+ state->nss_ctx->cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, NULL, data); - if (subreq == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send cache request!\n"); - ret = ENOMEM; -diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c -index ba2563c11885ff39681c2ef432acaedf26702b64..fa6d2cc10fe1404196f9d9221a469d7a9a768211 100644 ---- a/src/responder/pam/pamsrv_cmd.c -+++ b/src/responder/pam/pamsrv_cmd.c -@@ -1315,7 +1315,9 @@ static void pam_forwarder_cert_cb(struct tevent_req *req) - - - req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx, -- pctx->rctx->ncache, 0, NULL, cert); -+ pctx->rctx->ncache, 0, -+ CACHE_REQ_POSIX_DOM, NULL, -+ cert); - if (req == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n"); - ret = ENOMEM; -@@ -1507,6 +1509,7 @@ static int pam_check_user_search(struct pam_auth_req *preq) - preq->cctx->rctx, - preq->cctx->rctx->ncache, - 0, -+ CACHE_REQ_POSIX_DOM, - preq->pd->domain, - data); - if (!dpreq) { -diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c -index 52dfd5c709e48f0d4610a4b384962fbc2869312b..cfdbfc9c9c66d96f774822d6a4d4aaaf1327abe3 100644 ---- a/src/responder/sudo/sudosrv_get_sudorules.c -+++ b/src/responder/sudo/sudosrv_get_sudorules.c -@@ -644,7 +644,8 @@ struct tevent_req *sudosrv_get_rules_send(TALLOC_CTX *mem_ctx, - DEBUG(SSSDBG_TRACE_FUNC, "Running initgroups for [%s]\n", username); - - subreq = cache_req_initgr_by_name_send(state, ev, sudo_ctx->rctx, -- sudo_ctx->rctx->ncache, 0, NULL, -+ sudo_ctx->rctx->ncache, 0, -+ CACHE_REQ_POSIX_DOM, NULL, - username); - if (subreq == NULL) { - ret = ENOMEM; -diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c -index 5f1e5350eaf1d85de376c94731f0bd678f884a1d..80086232fd437876c2b190fb972c2ee3194d9efd 100644 ---- a/src/tests/cmocka/test_responder_cache_req.c -+++ b/src/tests/cmocka/test_responder_cache_req.c -@@ -84,6 +84,28 @@ struct test_group { - talloc_free(req_mem_ctx); \ - } while (0) - -+#define run_cache_req_domtype(ctx, send_fn, done_fn, dom, crp, domtype, lookup, expret) do { \ -+ TALLOC_CTX *req_mem_ctx; \ -+ struct tevent_req *req; \ -+ errno_t ret; \ -+ \ -+ req_mem_ctx = talloc_new(global_talloc_context); \ -+ check_leaks_push(req_mem_ctx); \ -+ \ -+ req = send_fn(req_mem_ctx, ctx->tctx->ev, ctx->rctx, \ -+ ctx->ncache, crp, \ -+ domtype, \ -+ (dom == NULL ? NULL : dom->name), lookup); \ -+ assert_non_null(req); \ -+ tevent_req_set_callback(req, done_fn, ctx); \ -+ \ -+ ret = test_ev_loop(ctx->tctx); \ -+ assert_int_equal(ret, expret); \ -+ assert_true(check_leaks_pop(req_mem_ctx)); \ -+ \ -+ talloc_free(req_mem_ctx); \ -+} while (0) -+ - struct cache_req_test_ctx { - struct sss_test_ctx *tctx; - struct resp_ctx *rctx; -@@ -211,9 +233,11 @@ static void run_user_by_name(struct cache_req_test_ctx *test_ctx, - int cache_refresh_percent, - errno_t exp_ret) - { -- run_cache_req(test_ctx, cache_req_user_by_name_send, -- cache_req_user_by_name_test_done, domain, -- cache_refresh_percent, users[0].short_name, exp_ret); -+ run_cache_req_domtype(test_ctx, cache_req_user_by_name_send, -+ cache_req_user_by_name_test_done, domain, -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, -+ users[0].short_name, exp_ret); - } - - static void run_user_by_upn(struct cache_req_test_ctx *test_ctx, -@@ -221,9 +245,11 @@ static void run_user_by_upn(struct cache_req_test_ctx *test_ctx, - int cache_refresh_percent, - errno_t exp_ret) - { -- run_cache_req(test_ctx, cache_req_user_by_name_send, -- cache_req_user_by_name_test_done, domain, -- cache_refresh_percent, users[0].upn, exp_ret); -+ run_cache_req_domtype(test_ctx, cache_req_user_by_name_send, -+ cache_req_user_by_name_test_done, domain, -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, -+ users[0].upn, exp_ret); - } - - static void run_user_by_id(struct cache_req_test_ctx *test_ctx, -@@ -318,9 +344,11 @@ static void run_group_by_name(struct cache_req_test_ctx *test_ctx, - int cache_refresh_percent, - errno_t exp_ret) - { -- run_cache_req(test_ctx, cache_req_group_by_name_send, -- cache_req_group_by_name_test_done, domain, -- cache_refresh_percent, groups[0].short_name, exp_ret); -+ run_cache_req_domtype(test_ctx, cache_req_group_by_name_send, -+ cache_req_group_by_name_test_done, domain, -+ cache_refresh_percent, -+ CACHE_REQ_POSIX_DOM, -+ groups[0].short_name, exp_ret); - } - - static void run_group_by_id(struct cache_req_test_ctx *test_ctx, -@@ -605,7 +633,9 @@ void test_user_by_name_multiple_domains_parse(void **state) - check_leaks_push(req_mem_ctx); - - req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, -- test_ctx->rctx, test_ctx->ncache, 0, -+ test_ctx->rctx, test_ctx->ncache, -+ CACHE_REQ_POSIX_DOM, -+ 0, - NULL, input_fqn); - assert_non_null(req); - tevent_req_set_callback(req, cache_req_user_by_name_test_done, test_ctx); -@@ -1119,7 +1149,8 @@ void test_group_by_name_multiple_domains_parse(void **state) - - req = cache_req_group_by_name_send(req_mem_ctx, test_ctx->tctx->ev, - test_ctx->rctx, test_ctx->ncache, 0, -- NULL, input_fqn); -+ CACHE_REQ_POSIX_DOM, NULL, -+ input_fqn); - assert_non_null(req); - tevent_req_set_callback(req, cache_req_group_by_name_test_done, test_ctx); - -@@ -1421,6 +1452,7 @@ void test_user_by_recent_filter_valid(void **state) - /* User TEST_USER is created with a DP callback. */ - req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, - test_ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - test_ctx->tctx->dom->name, - TEST_USER_PREFIX); - assert_non_null(req); -@@ -1463,6 +1495,7 @@ void test_users_by_recent_filter_valid(void **state) - /* User TEST_USER1 and TEST_USER2 are created with a DP callback. */ - req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, - test_ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - test_ctx->tctx->dom->name, - TEST_USER_PREFIX); - assert_non_null(req); -@@ -1524,6 +1557,7 @@ void test_users_by_filter_filter_old(void **state) - - req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, - test_ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - test_ctx->tctx->dom->name, - TEST_USER_PREFIX); - assert_non_null(req); -@@ -1559,6 +1593,7 @@ void test_users_by_filter_notfound(void **state) - - req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, - test_ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - test_ctx->tctx->dom->name, - "nosuchuser*"); - assert_non_null(req); -@@ -1592,6 +1627,7 @@ static void test_users_by_filter_multiple_domains_notfound(void **state) - - req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, - test_ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - domain->name, - "nosuchuser*"); - assert_non_null(req); -@@ -1636,6 +1672,7 @@ void test_group_by_recent_filter_valid(void **state) - /* Group TEST_GROUP is created with a DP callback. */ - req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, - test_ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - test_ctx->tctx->dom->name, - TEST_USER_PREFIX); - assert_non_null(req); -@@ -1680,6 +1717,7 @@ void test_groups_by_recent_filter_valid(void **state) - /* Group TEST_GROUP1 and TEST_GROUP2 are created with a DP callback. */ - req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, - test_ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - test_ctx->tctx->dom->name, - TEST_USER_PREFIX); - assert_non_null(req); -@@ -1738,6 +1776,7 @@ void test_groups_by_filter_notfound(void **state) - - req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, - test_ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - test_ctx->tctx->dom->name, - "nosuchgroup*"); - assert_non_null(req); -@@ -1770,6 +1809,7 @@ void test_groups_by_filter_multiple_domains_notfound(void **state) - - req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, - test_ctx->rctx, -+ CACHE_REQ_POSIX_DOM, - domain->name, - "nosuchgroup*"); - assert_non_null(req); --- -2.9.3 - diff --git a/SOURCES/0063-ipa-handle-users-from-different-domains-in-ipa_resol.patch b/SOURCES/0063-ipa-handle-users-from-different-domains-in-ipa_resol.patch new file mode 100644 index 0000000..68c09b2 --- /dev/null +++ b/SOURCES/0063-ipa-handle-users-from-different-domains-in-ipa_resol.patch @@ -0,0 +1,76 @@ +From d8d4e9fb842444eb3bd4e1a116fce00aba557707 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 12:04:50 +0100 +Subject: [PATCH 63/67] ipa: handle users from different domains in + ipa_resolve_user_list_send() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Instead of assuming that all users in the list can be found in the +provided domain with this patch the domain name part of the user name is +preferred. The provided domain name is used as a fallback. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 7988988aab5bd0249476671b850eb3909aa753f8) +--- + src/providers/ipa/ipa_id.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c +index 8f8759f64b758aae7e45c88588e97a1bcf16ad79..2b4386584192d6b5ef0372099292ed73b77177bd 100644 +--- a/src/providers/ipa/ipa_id.c ++++ b/src/providers/ipa/ipa_id.c +@@ -63,6 +63,8 @@ struct ipa_resolve_user_list_state { + struct ipa_id_ctx *ipa_ctx; + struct ldb_message_element *users; + const char *domain_name; ++ struct sss_domain_info *domain; ++ struct sss_domain_info *user_domain; + size_t user_idx; + + int dp_error; +@@ -91,6 +93,8 @@ ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev, + state->ev = ev; + state->ipa_ctx = ipa_ctx; + state->domain_name = domain_name; ++ state->domain = find_domain_by_name(state->ipa_ctx->sdap_id_ctx->be->domain, ++ state->domain_name, true); + state->users = users; + state->user_idx = 0; + state->dp_error = DP_ERR_FATAL; +@@ -132,8 +136,17 @@ static errno_t ipa_resolve_user_list_get_user_step(struct tevent_req *req) + + DEBUG(SSSDBG_TRACE_ALL, "Trying to resolve user [%s].\n", ar->filter_value); + +- if (strcasecmp(state->domain_name, +- state->ipa_ctx->sdap_id_ctx->be->domain->name) != 0) { ++ state->user_domain = find_domain_by_object_name_ex( ++ state->ipa_ctx->sdap_id_ctx->be->domain, ++ ar->filter_value, true); ++ /* Use provided domain as as fallback is no known domain was found in the ++ * user name. */ ++ if (state->user_domain == NULL) { ++ state->user_domain = state->domain; ++ } ++ ar->domain = state->user_domain->name; ++ ++ if (state->user_domain != state->ipa_ctx->sdap_id_ctx->be->domain) { + subreq = ipa_subdomain_account_send(state, state->ev, state->ipa_ctx, + ar); + } else { +@@ -158,8 +171,7 @@ static void ipa_resolve_user_list_get_user_done(struct tevent_req *subreq) + struct ipa_resolve_user_list_state); + int ret; + +- if (strcasecmp(state->domain_name, +- state->ipa_ctx->sdap_id_ctx->be->domain->name) != 0) { ++ if (state->user_domain != state->ipa_ctx->sdap_id_ctx->be->domain) { + ret = ipa_subdomain_account_recv(subreq, &state->dp_error); + } else { + ret = ipa_id_get_account_info_recv(subreq, &state->dp_error); +-- +2.14.3 + diff --git a/SOURCES/0064-IFP-Search-both-POSIX-and-non-POSIX-domains.patch b/SOURCES/0064-IFP-Search-both-POSIX-and-non-POSIX-domains.patch deleted file mode 100644 index c956b23..0000000 --- a/SOURCES/0064-IFP-Search-both-POSIX-and-non-POSIX-domains.patch +++ /dev/null @@ -1,705 +0,0 @@ -From bab9c21c9ec7ad39555db52511f0f2e425decd94 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 24 Mar 2017 12:44:09 +0100 -Subject: [PATCH 64/72] IFP: Search both POSIX and non-POSIX domains -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related to: -https://pagure.io/SSSD/sssd/issue/3310 - -Changes the behaviour of the InfoPipe responder so that both application -and POSIX domains are searched. In general, the IFP responder uses the -CACHE_REQ_ANY_DOM lookup type because we can't presume the intention of -the caller. Therefore, deployments that combine both POSIX and non-POSIX -domains must use fully qualified names or select the right domain order -manually. - -There is one change between the POSIX and non-POSIX users or groups - -the object path. For the POSIX users, the object path includes the UID -or GID. Because we don't have that for the non-POSIX objects, the object -name is used in the path instead. - -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/responder/ifp/ifp_groups.c | 135 ++++++++++++++++++++++------------- - src/responder/ifp/ifp_users.c | 158 ++++++++++++++++++++++++++--------------- - src/responder/ifp/ifpsrv_cmd.c | 6 +- - 3 files changed, 194 insertions(+), 105 deletions(-) - -diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c -index 99908e96bd971bce4b4e9064a77d8413f837d743..c568c62009cd4b777919dea048fd381a91bd3460 100644 ---- a/src/responder/ifp/ifp_groups.c -+++ b/src/responder/ifp/ifp_groups.c -@@ -35,25 +35,33 @@ char * ifp_groups_build_path_from_msg(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - struct ldb_message *msg) - { -- const char *gid; -+ const char *key = NULL; - -- gid = ldb_msg_find_attr_as_string(msg, SYSDB_GIDNUM, NULL); -+ switch (domain->type) { -+ case DOM_TYPE_APPLICATION: -+ key = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); -+ break; -+ case DOM_TYPE_POSIX: -+ key = ldb_msg_find_attr_as_string(msg, SYSDB_GIDNUM, NULL); -+ break; -+ } - -- if (gid == NULL) { -+ -+ if (key == NULL) { - return NULL; - } - -- return sbus_opath_compose(mem_ctx, IFP_PATH_GROUPS, domain->name, gid); -+ return sbus_opath_compose(mem_ctx, IFP_PATH_GROUPS, domain->name, key); - } - --static errno_t ifp_groups_decompose_path(struct sss_domain_info *domains, -+static errno_t ifp_groups_decompose_path(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domains, - const char *path, - struct sss_domain_info **_domain, -- gid_t *_gid) -+ char **_key) - { - char **parts = NULL; - struct sss_domain_info *domain; -- gid_t gid; - errno_t ret; - - ret = sbus_opath_decompose_exact(NULL, path, IFP_PATH_GROUPS, 2, &parts); -@@ -67,14 +75,8 @@ static errno_t ifp_groups_decompose_path(struct sss_domain_info *domains, - goto done; - } - -- gid = strtouint32(parts[1], NULL, 10); -- ret = errno; -- if (ret != EOK) { -- goto done; -- } -- - *_domain = domain; -- *_gid = gid; -+ *_key = talloc_steal(mem_ctx, parts[1]); - - done: - talloc_free(parts); -@@ -119,7 +121,7 @@ int ifp_groups_find_by_name(struct sbus_request *sbus_req, - - req = cache_req_group_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, - ctx->rctx->ncache, 0, -- CACHE_REQ_POSIX_DOM, NULL, -+ CACHE_REQ_ANY_DOM, NULL, - name); - if (req == NULL) { - return ENOMEM; -@@ -273,7 +275,7 @@ static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx) - req = cache_req_group_by_filter_send(list_ctx, - list_ctx->ctx->rctx->ev, - list_ctx->ctx->rctx, -- CACHE_REQ_POSIX_DOM, -+ CACHE_REQ_ANY_DOM, - list_ctx->dom->name, - list_ctx->filter); - if (req == NULL) { -@@ -358,7 +360,7 @@ int ifp_groups_list_by_domain_and_name(struct sbus_request *sbus_req, - } - - req = cache_req_group_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx, -- CACHE_REQ_POSIX_DOM, -+ CACHE_REQ_ANY_DOM, - domain, filter); - if (req == NULL) { - return ENOMEM; -@@ -412,16 +414,65 @@ done: - } - - static errno_t -+ifp_groups_get_from_cache(struct sbus_request *sbus_req, -+ struct sss_domain_info *domain, -+ const char *key, -+ struct ldb_message **_group) -+{ -+ struct ldb_result *group_res; -+ errno_t ret; -+ gid_t gid; -+ -+ switch (domain->type) { -+ case DOM_TYPE_POSIX: -+ gid = strtouint32(key, NULL, 10); -+ ret = errno; -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid UID value\n"); -+ return ret; -+ } -+ -+ ret = sysdb_getgrgid_with_views(sbus_req, domain, gid, &group_res); -+ if (ret == EOK && group_res->count == 0) { -+ *_group = NULL; -+ return ENOENT; -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup group %u@%s [%d]: %s\n", -+ gid, domain->name, ret, sss_strerror(ret)); -+ return ret; -+ } -+ break; -+ case DOM_TYPE_APPLICATION: -+ ret = sysdb_getgrnam_with_views(sbus_req, domain, key, &group_res); -+ if (ret == EOK && group_res->count == 0) { -+ *_group = NULL; -+ return ENOENT; -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup group %s@%s [%d]: %s\n", -+ key, domain->name, ret, sss_strerror(ret)); -+ return ret; -+ } -+ break; -+ } -+ -+ if (group_res->count > 1) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "More groups matched by the single key\n"); -+ return EIO; -+ } -+ -+ *_group = group_res->msgs[0]; -+ return EOK; -+} -+ -+static errno_t - ifp_groups_group_get(struct sbus_request *sbus_req, - void *data, -- gid_t *_gid, - struct sss_domain_info **_domain, - struct ldb_message **_group) - { - struct ifp_ctx *ctx; - struct sss_domain_info *domain; -- struct ldb_result *res; -- uid_t gid; -+ char *key; - errno_t ret; - - ctx = talloc_get_type(data, struct ifp_ctx); -@@ -430,8 +481,9 @@ ifp_groups_group_get(struct sbus_request *sbus_req, - return ERR_INTERNAL; - } - -- ret = ifp_groups_decompose_path(ctx->rctx->domains, sbus_req->path, -- &domain, &gid); -+ ret = ifp_groups_decompose_path(sbus_req, -+ ctx->rctx->domains, sbus_req->path, -+ &domain, &key); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to decompose object path" - "[%s] [%d]: %s\n", sbus_req->path, ret, sss_strerror(ret)); -@@ -439,28 +491,15 @@ ifp_groups_group_get(struct sbus_request *sbus_req, - } - - if (_group != NULL) { -- ret = sysdb_getgrgid_with_views(sbus_req, domain, gid, &res); -- if (ret == EOK && res->count == 0) { -- *_group = NULL; -- ret = ENOENT; -- } -- -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup group %u@%s [%d]: %s\n", -- gid, domain->name, ret, sss_strerror(ret)); -- } else { -- *_group = res->msgs[0]; -- } -+ ret = ifp_groups_get_from_cache(sbus_req, domain, key, _group); - } - - if (ret == EOK || ret == ENOENT) { -- if (_gid != NULL) { -- *_gid = gid; -- } -- - if (_domain != NULL) { - *_domain = domain; - } -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve group from cache\n"); - } - - return ret; -@@ -513,7 +552,7 @@ static struct tevent_req *resolv_ghosts_send(TALLOC_CTX *mem_ctx, - state->ctx = ctx; - state->data = data; - -- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group); -+ ret = ifp_groups_group_get(sbus_req, data, &domain, &group); - if (ret != EOK) { - goto immediately; - } -@@ -527,7 +566,7 @@ static struct tevent_req *resolv_ghosts_send(TALLOC_CTX *mem_ctx, - - subreq = cache_req_group_by_name_send(state, ev, ctx->rctx, - ctx->rctx->ncache, 0, -- CACHE_REQ_POSIX_DOM, -+ CACHE_REQ_ANY_DOM, - domain->name, - name); - if (subreq == NULL) { -@@ -561,7 +600,7 @@ static void resolv_ghosts_group_done(struct tevent_req *subreq) - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct resolv_ghosts_state); - -- ret = ifp_groups_group_get(state->sbus_req, state->data, NULL, -+ ret = ifp_groups_group_get(state->sbus_req, state->data, - &state->domain, &group); - if (ret != EOK) { - goto done; -@@ -608,7 +647,7 @@ errno_t resolv_ghosts_step(struct tevent_req *req) - - subreq = cache_req_user_by_name_send(state, state->ev, state->ctx->rctx, - state->ctx->rctx->ncache, 0, -- CACHE_REQ_POSIX_DOM, -+ CACHE_REQ_ANY_DOM, - state->domain->name, - state->ghosts[state->index]); - if (subreq == NULL) { -@@ -719,7 +758,7 @@ void ifp_groups_group_get_name(struct sbus_request *sbus_req, - return; - } - -- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &msg); -+ ret = ifp_groups_group_get(sbus_req, data, &domain, &msg); - if (ret != EOK) { - *_out = NULL; - return; -@@ -744,7 +783,7 @@ void ifp_groups_group_get_gid_number(struct sbus_request *sbus_req, - struct sss_domain_info *domain; - errno_t ret; - -- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &msg); -+ ret = ifp_groups_group_get(sbus_req, data, &domain, &msg); - if (ret != EOK) { - *_out = 0; - return; -@@ -763,7 +802,7 @@ void ifp_groups_group_get_unique_id(struct sbus_request *sbus_req, - struct sss_domain_info *domain; - errno_t ret; - -- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &msg); -+ ret = ifp_groups_group_get(sbus_req, data, &domain, &msg); - if (ret != EOK) { - *_out = 0; - return; -@@ -803,7 +842,7 @@ ifp_groups_group_get_members(TALLOC_CTX *mem_ctx, - return ENOMEM; - } - -- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group); -+ ret = ifp_groups_group_get(sbus_req, data, &domain, &group); - if (ret != EOK) { - goto done; - } -@@ -954,7 +993,7 @@ int ifp_cache_object_store_group(struct sbus_request *sbus_req, - struct ldb_message *group; - errno_t ret; - -- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group); -+ ret = ifp_groups_group_get(sbus_req, data, &domain, &group); - if (ret != EOK) { - error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch " - "group [%d]: %s\n", ret, sss_strerror(ret)); -@@ -973,7 +1012,7 @@ int ifp_cache_object_remove_group(struct sbus_request *sbus_req, - struct ldb_message *group; - errno_t ret; - -- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group); -+ ret = ifp_groups_group_get(sbus_req, data, &domain, &group); - if (ret != EOK) { - error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch " - "group [%d]: %s\n", ret, sss_strerror(ret)); -diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c -index 436bb268fa9c78d72fb744e0d338aa561a7d8764..ce9557f94351b730ee46f3cbce31613cb5901942 100644 ---- a/src/responder/ifp/ifp_users.c -+++ b/src/responder/ifp/ifp_users.c -@@ -37,25 +37,33 @@ char * ifp_users_build_path_from_msg(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - struct ldb_message *msg) - { -- const char *uid; -+ const char *key = NULL; - -- uid = ldb_msg_find_attr_as_string(msg, SYSDB_UIDNUM, NULL); -+ switch (domain->type) { -+ case DOM_TYPE_APPLICATION: -+ key = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); -+ break; -+ case DOM_TYPE_POSIX: -+ key = ldb_msg_find_attr_as_string(msg, SYSDB_UIDNUM, NULL); -+ break; -+ } - -- if (uid == NULL) { -+ -+ if (key == NULL) { - return NULL; - } - -- return sbus_opath_compose(mem_ctx, IFP_PATH_USERS, domain->name, uid); -+ return sbus_opath_compose(mem_ctx, IFP_PATH_USERS, domain->name, key); - } - --static errno_t ifp_users_decompose_path(struct sss_domain_info *domains, -+static errno_t ifp_users_decompose_path(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domains, - const char *path, - struct sss_domain_info **_domain, -- uid_t *_uid) -+ char **_key) - { - char **parts = NULL; - struct sss_domain_info *domain; -- uid_t uid; - errno_t ret; - - ret = sbus_opath_decompose_exact(NULL, path, IFP_PATH_USERS, 2, &parts); -@@ -69,14 +77,8 @@ static errno_t ifp_users_decompose_path(struct sss_domain_info *domains, - goto done; - } - -- uid = strtouint32(parts[1], NULL, 10); -- ret = errno; -- if (ret != EOK) { -- goto done; -- } -- - *_domain = domain; -- *_uid = uid; -+ *_key = talloc_steal(mem_ctx, parts[1]); - - done: - talloc_free(parts); -@@ -100,7 +102,7 @@ int ifp_users_find_by_name(struct sbus_request *sbus_req, - - req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, - ctx->rctx->ncache, 0, -- CACHE_REQ_POSIX_DOM, -+ CACHE_REQ_ANY_DOM, - NULL, name); - if (req == NULL) { - return ENOMEM; -@@ -256,7 +258,7 @@ int ifp_users_find_by_cert(struct sbus_request *sbus_req, void *data, - - req = cache_req_user_by_cert_send(sbus_req, ctx->rctx->ev, ctx->rctx, - ctx->rctx->ncache, 0, -- CACHE_REQ_POSIX_DOM, NULL, -+ CACHE_REQ_ANY_DOM, NULL, - derb64); - if (req == NULL) { - return ENOMEM; -@@ -371,7 +373,7 @@ static int ifp_users_list_by_cert_step(struct ifp_list_ctx *list_ctx) - list_ctx->ctx->rctx, - list_ctx->ctx->rctx->ncache, - 0, -- CACHE_REQ_POSIX_DOM, -+ CACHE_REQ_ANY_DOM, - list_ctx->dom->name, - list_ctx->filter); - if (req == NULL) { -@@ -538,7 +540,7 @@ int ifp_users_find_by_name_and_cert(struct sbus_request *sbus_req, void *data, - if (name_and_cert_ctx->name != NULL) { - req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, - ctx->rctx->ncache, 0, -- CACHE_REQ_POSIX_DOM, -+ CACHE_REQ_ANY_DOM, - NULL, - name_and_cert_ctx->name); - if (req == NULL) { -@@ -621,7 +623,7 @@ static int ifp_users_find_by_name_and_cert_step( - list_ctx->ctx->rctx, - list_ctx->ctx->rctx->ncache, - 0, -- CACHE_REQ_POSIX_DOM, -+ CACHE_REQ_ANY_DOM, - list_ctx->dom->name, - list_ctx->filter); - if (req == NULL) { -@@ -782,7 +784,7 @@ static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx) - req = cache_req_user_by_filter_send(list_ctx, - list_ctx->ctx->rctx->ev, - list_ctx->ctx->rctx, -- CACHE_REQ_POSIX_DOM, -+ CACHE_REQ_ANY_DOM, - list_ctx->dom->name, - list_ctx->filter); - if (req == NULL) { -@@ -867,7 +869,7 @@ int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req, - } - - req = cache_req_user_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx, -- CACHE_REQ_POSIX_DOM, -+ CACHE_REQ_ANY_DOM, - domain, filter); - if (req == NULL) { - return ENOMEM; -@@ -930,19 +932,69 @@ done: - } - - static errno_t -+ifp_users_get_from_cache(struct sbus_request *sbus_req, -+ struct sss_domain_info *domain, -+ const char *key, -+ struct ldb_message **_user) -+{ -+ struct ldb_result *user_res; -+ errno_t ret; -+ uid_t uid; -+ -+ switch (domain->type) { -+ case DOM_TYPE_POSIX: -+ uid = strtouint32(key, NULL, 10); -+ ret = errno; -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid UID value\n"); -+ return ret; -+ } -+ -+ ret = sysdb_getpwuid_with_views(sbus_req, domain, uid, &user_res); -+ if (ret == EOK && user_res->count == 0) { -+ *_user = NULL; -+ return ENOENT; -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user %u@%s [%d]: %s\n", -+ uid, domain->name, ret, sss_strerror(ret)); -+ return ret; -+ } -+ break; -+ case DOM_TYPE_APPLICATION: -+ ret = sysdb_getpwnam_with_views(sbus_req, domain, key, &user_res); -+ if (ret == EOK && user_res->count == 0) { -+ *_user = NULL; -+ return ENOENT; -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user %s@%s [%d]: %s\n", -+ key, domain->name, ret, sss_strerror(ret)); -+ return ret; -+ } -+ break; -+ } -+ -+ if (user_res->count > 1) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "More users matched by the single key\n"); -+ return EIO; -+ } -+ -+ *_user = user_res->msgs[0]; -+ return EOK; -+} -+ -+static errno_t - ifp_users_user_get(struct sbus_request *sbus_req, - struct ifp_ctx *ifp_ctx, -- uid_t *_uid, - struct sss_domain_info **_domain, - struct ldb_message **_user) - { - struct sss_domain_info *domain; -- struct ldb_result *res; -- uid_t uid; -+ char *key; - errno_t ret; - -- ret = ifp_users_decompose_path(ifp_ctx->rctx->domains, sbus_req->path, -- &domain, &uid); -+ ret = ifp_users_decompose_path(sbus_req, -+ ifp_ctx->rctx->domains, sbus_req->path, -+ &domain, &key); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to decompose object path" - "[%s] [%d]: %s\n", sbus_req->path, ret, sss_strerror(ret)); -@@ -950,28 +1002,15 @@ ifp_users_user_get(struct sbus_request *sbus_req, - } - - if (_user != NULL) { -- ret = sysdb_getpwuid_with_views(sbus_req, domain, uid, &res); -- if (ret == EOK && res->count == 0) { -- *_user = NULL; -- ret = ENOENT; -- } -- -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user %u@%s [%d]: %s\n", -- uid, domain->name, ret, sss_strerror(ret)); -- } else { -- *_user = res->msgs[0]; -- } -+ ret = ifp_users_get_from_cache(sbus_req, domain, key, _user); - } - - if (ret == EOK || ret == ENOENT) { -- if (_uid != NULL) { -- *_uid = uid; -- } -- - if (_domain != NULL) { - *_domain = domain; - } -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve user from cache\n"); - } - - return ret; -@@ -1000,7 +1039,7 @@ static void ifp_users_get_as_string(struct sbus_request *sbus_req, - return; - } - -- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg); -+ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &msg); - if (ret != EOK) { - return; - } -@@ -1034,7 +1073,7 @@ static void ifp_users_get_name(struct sbus_request *sbus_req, - return; - } - -- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg); -+ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &msg); - if (ret != EOK) { - return; - } -@@ -1072,7 +1111,7 @@ static void ifp_users_get_as_uint32(struct sbus_request *sbus_req, - return; - } - -- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg); -+ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &msg); - if (ret != EOK) { - return; - } -@@ -1100,7 +1139,7 @@ int ifp_users_user_update_groups_list(struct sbus_request *sbus_req, - return ERR_INTERNAL; - } - -- ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user); -+ ret = ifp_users_user_get(sbus_req, data, &domain, &user); - if (ret != EOK) { - return ret; - } -@@ -1113,7 +1152,7 @@ int ifp_users_user_update_groups_list(struct sbus_request *sbus_req, - - req = cache_req_initgr_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, - ctx->rctx->ncache, 0, -- CACHE_REQ_POSIX_DOM, domain->name, -+ CACHE_REQ_ANY_DOM, domain->name, - username); - if (req == NULL) { - return ENOMEM; -@@ -1235,7 +1274,7 @@ void ifp_users_user_get_groups(struct sbus_request *sbus_req, - return; - } - -- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &user); -+ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &user); - if (ret != EOK) { - return; - } -@@ -1268,7 +1307,7 @@ void ifp_users_user_get_groups(struct sbus_request *sbus_req, - for (i = 0; i < res->count; i++) { - gid = sss_view_ldb_msg_find_attr_as_uint64(domain, res->msgs[i], - SYSDB_GIDNUM, 0); -- if (gid == 0) { -+ if (gid == 0 && domain->type == DOM_TYPE_POSIX) { - continue; - } - -@@ -1293,11 +1332,12 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, - { - struct ifp_ctx *ifp_ctx; - struct sss_domain_info *domain; -+ struct ldb_message *base_user; -+ const char *name; - struct ldb_message **user; - struct ldb_message_element *el; - struct ldb_dn *basedn; - size_t count; -- uid_t uid; - const char *filter; - const char **extra; - hash_table_t *table; -@@ -1322,7 +1362,7 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, - return; - } - -- ret = ifp_users_user_get(sbus_req, data, &uid, &domain, NULL); -+ ret = ifp_users_user_get(sbus_req, data, &domain, &base_user); - if (ret != EOK) { - return; - } -@@ -1333,9 +1373,15 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, - return; - } - -- filter = talloc_asprintf(sbus_req, "(&(%s=%s)(%s=%u))", -+ name = ldb_msg_find_attr_as_string(base_user, SYSDB_NAME, NULL); -+ if (name == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "A user with no name\n"); -+ return; -+ } -+ -+ filter = talloc_asprintf(sbus_req, "(&(%s=%s)(%s=%s))", - SYSDB_OBJECTCLASS, SYSDB_USER_CLASS, -- SYSDB_UIDNUM, uid); -+ SYSDB_NAME, name); - if (filter == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n"); - return; -@@ -1351,7 +1397,7 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, - } - - if (count == 0) { -- DEBUG(SSSDBG_TRACE_FUNC, "User %u not found!\n", uid); -+ DEBUG(SSSDBG_TRACE_FUNC, "User %s not found!\n", name); - return; - } else if (count > 1) { - DEBUG(SSSDBG_CRIT_FAILURE, "More than one entry found!\n"); -@@ -1421,7 +1467,7 @@ int ifp_cache_object_store_user(struct sbus_request *sbus_req, - struct ldb_message *user; - errno_t ret; - -- ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user); -+ ret = ifp_users_user_get(sbus_req, data, &domain, &user); - if (ret != EOK) { - error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch " - "user [%d]: %s\n", ret, sss_strerror(ret)); -@@ -1440,7 +1486,7 @@ int ifp_cache_object_remove_user(struct sbus_request *sbus_req, - struct ldb_message *user; - errno_t ret; - -- ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user); -+ ret = ifp_users_user_get(sbus_req, data, &domain, &user); - if (ret != EOK) { - error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch " - "user [%d]: %s\n", ret, sss_strerror(ret)); -diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c -index 118b5083b14bf5692c6fdd7ba90668fe514aa89d..d10f35e41dbb1623a0b9de37a4c43363cbefc1a3 100644 ---- a/src/responder/ifp/ifpsrv_cmd.c -+++ b/src/responder/ifp/ifpsrv_cmd.c -@@ -508,8 +508,12 @@ ifp_user_get_attr_lookup(struct tevent_req *subreq) - return; - } - -+ /* IFP serves both POSIX and application domains. Requests that need -+ * to differentiate between the two must be qualified -+ */ - subreq = cache_req_send(state, state->rctx->ev, state->rctx, -- state->ncache, 0, CACHE_REQ_POSIX_DOM, -+ state->ncache, 0, -+ CACHE_REQ_ANY_DOM, - state->domname, data); - if (subreq == NULL) { - tevent_req_error(req, ENOMEM); --- -2.9.3 - diff --git a/SOURCES/0064-overrides-fixes-for-sysdb_invalidate_overrides.patch b/SOURCES/0064-overrides-fixes-for-sysdb_invalidate_overrides.patch new file mode 100644 index 0000000..c8d9de9 --- /dev/null +++ b/SOURCES/0064-overrides-fixes-for-sysdb_invalidate_overrides.patch @@ -0,0 +1,203 @@ +From c0263b48a3512d8b6984693c4b8e772844215f9e Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 15:51:27 +0100 +Subject: [PATCH 64/67] overrides: fixes for sysdb_invalidate_overrides() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There were two issues in sysdb_invalidate_overrides(). + +First, SYSDB_CACHE_EXPIRE was only reset for the entry in the data cache +but not in the timestamp cache. + +Second, if one of the steps in the combined replace and delete operation +failed no change was committed to the cache. If, for whatever reasons, +a user or group object didn't had SYSDB_OVERRIDE_DN set the delete +failed and hence SYSDB_CACHE_EXPIRE wasn't reset as well. To make sure +the cache is in a consistent state after a view change the replace and +the delete operations are don in two steps. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 4671acb949c65c5c080532e03b1b6f1c9377a6a5) +--- + src/db/sysdb_views.c | 111 +++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 80 insertions(+), 31 deletions(-) + +diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c +index afc7852ecf402ef144beca9c1b94fbe3cc4bbb6a..70082d8db9b25c11e8c0823d4e5da2ba0c0d10d1 100644 +--- a/src/db/sysdb_views.c ++++ b/src/db/sysdb_views.c +@@ -279,6 +279,45 @@ done: + return ret; + } + ++static errno_t invalidate_entry_override(struct sysdb_ctx *sysdb, ++ struct ldb_dn *dn, ++ struct ldb_message *msg_del, ++ struct ldb_message *msg_repl) ++{ ++ int ret; ++ ++ msg_del->dn = dn; ++ msg_repl->dn = dn; ++ ++ ret = ldb_modify(sysdb->ldb, msg_del); ++ if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ldb_modify failed: [%s](%d)[%s]\n", ++ ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)); ++ return sysdb_error_to_errno(ret); ++ } ++ ++ ret = ldb_modify(sysdb->ldb, msg_repl); ++ if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ldb_modify failed: [%s](%d)[%s]\n", ++ ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)); ++ return sysdb_error_to_errno(ret); ++ } ++ ++ if (sysdb->ldb_ts != NULL) { ++ ret = ldb_modify(sysdb->ldb_ts, msg_repl); ++ if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ldb_modify failed: [%s](%d)[%s]\n", ++ ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb_ts)); ++ return sysdb_error_to_errno(ret); ++ } ++ } ++ ++ return EOK; ++} ++ + errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb) + { + int ret; +@@ -287,22 +326,23 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb) + bool in_transaction = false; + struct ldb_result *res; + size_t c; +- struct ldb_message *msg; ++ struct ldb_message *msg_del; ++ struct ldb_message *msg_repl; + struct ldb_dn *base_dn; + ++ if (sysdb->ldb_ts == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Timestamp cache context not available, cache might not be " ++ "invalidated completely. Please call 'sss_cache -E' or remove " ++ "the cache file if there are issues after a view name change.\n"); ++ } ++ + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + +- msg = ldb_msg_new(tmp_ctx); +- if (msg == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n"); +- ret = ENOMEM; +- goto done; +- } +- + base_dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_BASE); + if (base_dn == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed\n"); +@@ -310,27 +350,40 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb) + goto done; + } + +- ret = ldb_msg_add_empty(msg, SYSDB_CACHE_EXPIRE, LDB_FLAG_MOD_REPLACE, ++ msg_del = ldb_msg_new(tmp_ctx); ++ if (msg_del == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ret = ldb_msg_add_empty(msg_del, SYSDB_OVERRIDE_DN, LDB_FLAG_MOD_DELETE, + NULL); + if (ret != LDB_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n"); + ret = sysdb_error_to_errno(ret); + goto done; + } +- ret = ldb_msg_add_string(msg, SYSDB_CACHE_EXPIRE, "1"); ++ ++ msg_repl = ldb_msg_new(tmp_ctx); ++ if (msg_repl == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ret = ldb_msg_add_empty(msg_repl, SYSDB_CACHE_EXPIRE, ++ LDB_FLAG_MOD_REPLACE, NULL); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n"); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ret = ldb_msg_add_string(msg_repl, SYSDB_CACHE_EXPIRE, "1"); + if (ret != LDB_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n"); + ret = sysdb_error_to_errno(ret); + goto done; + } + +- ret = ldb_msg_add_empty(msg, SYSDB_OVERRIDE_DN, LDB_FLAG_MOD_DELETE, NULL); +- if (ret != LDB_SUCCESS) { +- DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n"); +- ret = sysdb_error_to_errno(ret); +- goto done; +- } +- + ret = sysdb_transaction_start(sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_start failed.\n"); +@@ -347,14 +400,12 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb) + } + + for (c = 0; c < res->count; c++) { +- msg->dn = res->msgs[c]->dn; +- +- ret = ldb_modify(sysdb->ldb, msg); +- if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ ret = invalidate_entry_override(sysdb, res->msgs[c]->dn, msg_del, ++ msg_repl); ++ if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +- "ldb_modify failed: [%s](%d)[%s]\n", +- ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)); +- ret = sysdb_error_to_errno(ret); ++ "invalidate_entry_override failed [%d][%s].\n", ++ ret, sss_strerror(ret)); + goto done; + } + } +@@ -370,14 +421,12 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb) + } + + for (c = 0; c < res->count; c++) { +- msg->dn = res->msgs[c]->dn; +- +- ret = ldb_modify(sysdb->ldb, msg); +- if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ ret = invalidate_entry_override(sysdb, res->msgs[c]->dn, msg_del, ++ msg_repl); ++ if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +- "ldb_modify failed: [%s](%d)[%s]\n", +- ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)); +- ret = sysdb_error_to_errno(ret); ++ "invalidate_entry_override failed [%d][%s].\n", ++ ret, sss_strerror(ret)); + goto done; + } + } +-- +2.14.3 + diff --git a/SOURCES/0065-IFP-ListByName-Don-t-crash-when-no-results-are-found.patch b/SOURCES/0065-IFP-ListByName-Don-t-crash-when-no-results-are-found.patch deleted file mode 100644 index f062ffa..0000000 --- a/SOURCES/0065-IFP-ListByName-Don-t-crash-when-no-results-are-found.patch +++ /dev/null @@ -1,57 +0,0 @@ -From c9268488cd24fe8e13580d6c4ea2fa237faededa Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 28 Mar 2017 14:07:29 +0200 -Subject: [PATCH 65/72] IFP: ListByName: Don't crash when no results are found -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If no results were found using the List command, the results variable -was undefined which resulted in a crash. - -Instead, only copy the results of the cache_req lookup returns EOK and -we can presume that the results are valid. - -Reviewed-by: Pavel Březina -Reviewed-by: Sumit Bose ---- - src/responder/ifp/ifp_users.c | 16 +++++++++------- - 1 file changed, 9 insertions(+), 7 deletions(-) - -diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c -index ce9557f94351b730ee46f3cbce31613cb5901942..188194f2ab356d0e67b0f26b003f3a9ce48e6acd 100644 ---- a/src/responder/ifp/ifp_users.c -+++ b/src/responder/ifp/ifp_users.c -@@ -801,7 +801,7 @@ static void ifp_users_list_by_name_done(struct tevent_req *req) - DBusError *error; - struct ifp_list_ctx *list_ctx; - struct sbus_request *sbus_req; -- struct cache_req_result *result; -+ struct cache_req_result *result = NULL; - errno_t ret; - - list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx); -@@ -816,12 +816,14 @@ static void ifp_users_list_by_name_done(struct tevent_req *req) - return; - } - -- ret = ifp_users_list_copy(list_ctx, result->ldb_result); -- if (ret != EOK) { -- error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, -- "Failed to copy domain result"); -- sbus_request_fail_and_finish(sbus_req, error); -- return; -+ if (ret == EOK) { -+ ret = ifp_users_list_copy(list_ctx, result->ldb_result); -+ if (ret != EOK) { -+ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, -+ "Failed to copy domain result"); -+ sbus_request_fail_and_finish(sbus_req, error); -+ return; -+ } - } - - list_ctx->dom = get_next_domain(list_ctx->dom, SSS_GND_DESCEND); --- -2.9.3 - diff --git a/SOURCES/0065-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch b/SOURCES/0065-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch new file mode 100644 index 0000000..74f5f5e --- /dev/null +++ b/SOURCES/0065-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch @@ -0,0 +1,254 @@ +From 53c6201539d24f8b929120565ca661977ecbb1a4 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 16:12:58 +0100 +Subject: [PATCH 65/67] ipa: check for SYSDB_OVERRIDE_DN in process_members and + get_group_dn_list +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +process_members() and get_group_dn_list() are used on an IPA client to +determine a list of users or groups which are missing in the cache and +are needed to properly add a group or user object to the cache +respectively. + +If a non-default view is assigned to the client the SYSDB_OVERRIDE_DN +must be set for all user and group objects to indicate that it was +already checked if there is an id-override defined for the object or +not. There a circumstances were SYSDB_OVERRIDE_DN is not set, e.g. after +a view name change. To make sure the cache is in a consistent state with +this patch user and group entries without SYSDB_OVERRIDE_DN are +considered as missing is a non-default view is assigned to the client. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 919b5d76057d31877e0c25ca495711ff76c713d6) +--- + src/providers/ipa/ipa_s2n_exop.c | 145 ++++++++++++++++++++++----------------- + 1 file changed, 83 insertions(+), 62 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 39ed17cbf0e8c523212084197e9f2963fed88dc8..c6132f509dcc8e7af84e03e8bfe20701107d1392 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -1523,6 +1523,7 @@ fail: + } + + static errno_t process_members(struct sss_domain_info *domain, ++ bool is_default_view, + struct sysdb_attrs *group_attrs, + char **members, + TALLOC_CTX *mem_ctx, char ***_missing_members) +@@ -1536,6 +1537,7 @@ static errno_t process_members(struct sss_domain_info *domain, + struct sss_domain_info *parent_domain; + char **missing_members = NULL; + size_t miss_count = 0; ++ const char *attrs[] = {SYSDB_NAME, SYSDB_OVERRIDE_DN, NULL}; + + if (members == NULL) { + DEBUG(SSSDBG_TRACE_INTERNAL, "No members\n"); +@@ -1572,53 +1574,59 @@ static errno_t process_members(struct sss_domain_info *domain, + goto done; + } + +- ret = sysdb_search_user_by_name(tmp_ctx, obj_domain, members[c], NULL, ++ ret = sysdb_search_user_by_name(tmp_ctx, obj_domain, members[c], attrs, + &msg); +- if (ret == EOK) { +- if (group_attrs != NULL) { +- dn_str = ldb_dn_get_linearized(msg->dn); +- if (dn_str == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_get_linearized failed.\n"); +- ret = EINVAL; +- goto done; +- } +- +- DEBUG(SSSDBG_TRACE_ALL, "Adding member [%s][%s]\n", +- members[c], dn_str); ++ if (ret == EOK || ret == ENOENT) { ++ if (ret == ENOENT ++ || (!is_default_view ++ && ldb_msg_find_attr_as_string(msg, SYSDB_OVERRIDE_DN, ++ NULL) == NULL)) { ++ /* only add ghost if the member is really missing */ ++ if (group_attrs != NULL && ret == ENOENT) { ++ DEBUG(SSSDBG_TRACE_ALL, "Adding ghost member [%s]\n", ++ members[c]); + +- ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_MEMBER, +- dn_str); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "sysdb_attrs_add_string_safe failed.\n"); +- goto done; ++ /* There were cases where the server returned the same user ++ * multiple times */ ++ ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_GHOST, ++ members[c]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_attrs_add_string failed.\n"); ++ goto done; ++ } + } +- } +- } else if (ret == ENOENT) { +- if (group_attrs != NULL) { +- DEBUG(SSSDBG_TRACE_ALL, "Adding ghost member [%s]\n", +- members[c]); + +- /* There were cases where the server returned the same user +- * multiple times */ +- ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_GHOST, +- members[c]); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "sysdb_attrs_add_string failed.\n"); +- goto done; ++ if (missing_members != NULL) { ++ missing_members[miss_count] = talloc_strdup(missing_members, ++ members[c]); ++ if (missing_members[miss_count] == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ miss_count++; + } +- } ++ } else { ++ if (group_attrs != NULL) { ++ dn_str = ldb_dn_get_linearized(msg->dn); ++ if (dn_str == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_get_linearized failed.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_ALL, "Adding member [%s][%s]\n", ++ members[c], dn_str); + +- if (missing_members != NULL) { +- missing_members[miss_count] = talloc_strdup(missing_members, +- members[c]); +- if (missing_members[miss_count] == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); +- ret = ENOMEM; +- goto done; ++ ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_MEMBER, ++ dn_str); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_attrs_add_string_safe failed.\n"); ++ goto done; ++ } + } +- miss_count++; + } + } else { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_name failed.\n"); +@@ -1649,6 +1657,7 @@ done: + } + + static errno_t get_group_dn_list(TALLOC_CTX *mem_ctx, ++ bool is_default_view, + struct sss_domain_info *dom, + size_t ngroups, char **groups, + struct ldb_dn ***_dn_list, +@@ -1664,6 +1673,7 @@ static errno_t get_group_dn_list(TALLOC_CTX *mem_ctx, + size_t n_missing = 0; + struct sss_domain_info *obj_domain; + struct sss_domain_info *parent_domain; ++ const char *attrs[] = {SYSDB_NAME, SYSDB_OVERRIDE_DN, NULL}; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { +@@ -1689,25 +1699,31 @@ static errno_t get_group_dn_list(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sysdb_search_group_by_name(tmp_ctx, obj_domain, groups[c], NULL, ++ ret = sysdb_search_group_by_name(tmp_ctx, obj_domain, groups[c], attrs, + &msg); +- if (ret == EOK) { +- dn_list[n_dns] = ldb_dn_copy(dn_list, msg->dn); +- if (dn_list[n_dns] == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_copy failed.\n"); +- ret = ENOMEM; +- goto done; ++ if (ret == EOK || ret == ENOENT) { ++ if (ret == ENOENT ++ || (!is_default_view ++ && ldb_msg_find_attr_as_string(msg, SYSDB_OVERRIDE_DN, ++ NULL) == NULL)) { ++ missing_groups[n_missing] = talloc_strdup(missing_groups, ++ groups[c]); ++ if (missing_groups[n_missing] == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ n_missing++; ++ ++ } else { ++ dn_list[n_dns] = ldb_dn_copy(dn_list, msg->dn); ++ if (dn_list[n_dns] == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_copy failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ n_dns++; + } +- n_dns++; +- } else if (ret == ENOENT) { +- missing_groups[n_missing] = talloc_strdup(missing_groups, +- groups[c]); +- if (missing_groups[n_missing] == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); +- ret = ENOMEM; +- goto done; +- } +- n_missing++; + } else { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_group_by_name failed.\n"); + goto done; +@@ -1803,7 +1819,9 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + } + + +- ret = get_group_dn_list(state, state->dom, ++ ret = get_group_dn_list(state, ++ is_default_view(state->ipa_ctx->view_name), ++ state->dom, + attrs->ngroups, attrs->groups, + &group_dn_list, &missing_list); + if (ret != EOK) { +@@ -1832,8 +1850,10 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + } + break; + } else if (attrs->response_type == RESP_GROUP_MEMBERS) { +- ret = process_members(state->dom, NULL, attrs->a.group.gr_mem, +- state, &missing_list); ++ ret = process_members(state->dom, ++ is_default_view(state->ipa_ctx->view_name), ++ NULL, attrs->a.group.gr_mem, state, ++ &missing_list); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "process_members failed.\n"); + goto done; +@@ -2572,8 +2592,9 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + } + } + +- ret = process_members(dom, attrs->sysdb_attrs, +- attrs->a.group.gr_mem, NULL, NULL); ++ ret = process_members(dom, is_default_view(view_name), ++ attrs->sysdb_attrs, attrs->a.group.gr_mem, ++ NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "process_members failed.\n"); + goto done; +-- +2.14.3 + diff --git a/SOURCES/0066-IPA-use-cache-searches-in-get_groups_dns.patch b/SOURCES/0066-IPA-use-cache-searches-in-get_groups_dns.patch new file mode 100644 index 0000000..5268e1a --- /dev/null +++ b/SOURCES/0066-IPA-use-cache-searches-in-get_groups_dns.patch @@ -0,0 +1,70 @@ +From 3500a7766f5443c9ec50f9c8de27e2dea8c0c234 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 16:41:29 +0100 +Subject: [PATCH 66/67] IPA: use cache searches in get_groups_dns() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the group name is overridden in the default view we have to search +for the name and cannot construct it because the extdom plugin will +return the overridden name but the DN of the related group object in the +cache will contain the original name. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit f29040342a6d69e170f4543662621f2e27221f91) +--- + src/providers/ipa/ipa_s2n_exop.c | 27 +++++++++++++++++++-------- + 1 file changed, 19 insertions(+), 8 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index c6132f509dcc8e7af84e03e8bfe20701107d1392..49c393e9a1eb19ab683949cf633a6838274bc0fe 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -2038,6 +2038,7 @@ static errno_t get_groups_dns(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + int c; + struct sss_domain_info *root_domain; + char **dn_list; ++ struct ldb_message *msg; + + if (name_list == NULL) { + *_dn_list = NULL; +@@ -2082,15 +2083,25 @@ static errno_t get_groups_dns(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + goto done; + } + +- /* This might fail if some unexpected cases are used. But current +- * sysdb code which handles group membership constructs DNs this way +- * as well, IPA names are lowercased and AD names by default will be +- * lowercased as well. If there are really use-cases which cause an +- * issue here, sysdb_group_strdn() has to be replaced by a proper +- * search. */ +- dn_list[c] = sysdb_group_strdn(dn_list, dom->name, name_list[c]); ++ /* If the group name is overridden in the default view we have to ++ * search for the name and cannot construct it because the extdom ++ * plugin will return the overridden name but the DN of the related ++ * group object in the cache will contain the original name. */ ++ ++ ret = sysdb_search_group_by_name(tmp_ctx, dom, name_list[c], NULL, ++ &msg); ++ if (ret == EOK) { ++ dn_list[c] = ldb_dn_alloc_linearized(dn_list, msg->dn); ++ } else { ++ /* best effort, try to construct the DN */ ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "sysdb_search_group_by_name failed with [%d], " ++ "generating DN for [%s] in domain [%s].\n", ++ ret, name_list[c], dom->name); ++ dn_list[c] = sysdb_group_strdn(dn_list, dom->name, name_list[c]); ++ } + if (dn_list[c] == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_group_strdn failed.\n"); ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_alloc_linearized failed.\n"); + ret = ENOMEM; + goto done; + } +-- +2.14.3 + diff --git a/SOURCES/0066-PAM-Remove-unneeded-memory-context.patch b/SOURCES/0066-PAM-Remove-unneeded-memory-context.patch deleted file mode 100644 index 64ba6af..0000000 --- a/SOURCES/0066-PAM-Remove-unneeded-memory-context.patch +++ /dev/null @@ -1,58 +0,0 @@ -From d11e7faa2a3464ed921ccf88a02e0a48871484b4 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 24 Mar 2017 20:36:06 +0100 -Subject: [PATCH 66/72] PAM: Remove unneeded memory context - -Since we only store data into pam_ctx in get_public_domains(), it -doesn't make sense to allow passing a separate memory context. It is -always going to be pam_ctx, otherwise the memory hierarchy will cause -issues anyway. - -Reviewed-by: Sumit Bose ---- - src/responder/pam/pamsrv.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c -index 816f2293130ff8761ca94b4a42ca93063c11ea35..ab3f4545520f3fcb2492a6089a039c46f0fb847f 100644 ---- a/src/responder/pam/pamsrv.c -+++ b/src/responder/pam/pamsrv.c -@@ -122,7 +122,7 @@ done: - return ret; - } - --static errno_t get_public_domains(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx) -+static errno_t get_public_domains(struct pam_ctx *pctx) - { - char *domains_str = NULL; - errno_t ret; -@@ -137,7 +137,7 @@ static errno_t get_public_domains(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx) - - if (strcmp(domains_str, ALL_DOMAIMS_ARE_PUBLIC) == 0) { /* all */ - /* copy all domains */ -- ret = get_dom_names(mem_ctx, -+ ret = get_dom_names(pctx, - pctx->rctx->domains, - &pctx->public_domains, - &pctx->public_domains_count); -@@ -149,7 +149,7 @@ static errno_t get_public_domains(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx) - pctx->public_domains = NULL; - pctx->public_domains_count = 0; - } else { -- ret = split_on_separator(mem_ctx, domains_str, ',', true, false, -+ ret = split_on_separator(pctx, domains_str, ',', true, false, - &pctx->public_domains, - &pctx->public_domains_count); - if (ret != EOK) { -@@ -212,7 +212,7 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, - goto done; - } - -- ret = get_public_domains(pctx, pctx); -+ ret = get_public_domains(pctx); - if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, "get_public_domains failed: %d:[%s].\n", - ret, sss_strerror(ret)); --- -2.9.3 - diff --git a/SOURCES/0067-PAM-Add-application-services.patch b/SOURCES/0067-PAM-Add-application-services.patch deleted file mode 100644 index 2c8fddd..0000000 --- a/SOURCES/0067-PAM-Add-application-services.patch +++ /dev/null @@ -1,452 +0,0 @@ -From 855201c70f69f2b1dbcb3faef780fbdb84354f18 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Sun, 26 Mar 2017 18:28:41 +0200 -Subject: [PATCH 67/72] PAM: Add application services - -Related to: -https://pagure.io/SSSD/sssd/issue/3310 - -Adds a new PAM responder option 'pam_app_services'. This option can hold -a list of PAM services that are allowed to contact the application -non-POSIX domains. These services are NOT allowed to contact any of the -POSIX domains. - -Reviewed-by: Sumit Bose ---- - src/confdb/confdb.h | 1 + - src/config/SSSDConfig/__init__.py.in | 1 + - src/config/cfg_rules.ini | 1 + - src/config/etc/sssd.api.conf | 1 + - src/man/sssd.conf.5.xml | 12 +++ - src/responder/pam/pamsrv.c | 33 +++++++ - src/responder/pam/pamsrv.h | 5 ++ - src/responder/pam/pamsrv_cmd.c | 26 +++++- - src/tests/cmocka/test_pam_srv.c | 167 ++++++++++++++++++++++++++++++++++- - 9 files changed, 241 insertions(+), 6 deletions(-) - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index 5a8d377c312f641f544b1c7cf38826192462ea3c..8719c239362b371fcdb1b78956bcddde871f141b 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -129,6 +129,7 @@ - #define CONFDB_PAM_CERT_AUTH "pam_cert_auth" - #define CONFDB_PAM_CERT_DB_PATH "pam_cert_db_path" - #define CONFDB_PAM_P11_CHILD_TIMEOUT "p11_child_timeout" -+#define CONFDB_PAM_APP_SERVICES "pam_app_services" - - /* SUDO */ - #define CONFDB_SUDO_CONF_ENTRY "config/sudo" -diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in -index 806611b6076048c08ce08c772dbd3cea5fdd656c..211338778e81c1c60ffb3cdbc67c9619343d7798 100644 ---- a/src/config/SSSDConfig/__init__.py.in -+++ b/src/config/SSSDConfig/__init__.py.in -@@ -102,6 +102,7 @@ option_strings = { - 'pam_cert_auth' : _('Allow certificate based/Smartcard authentication.'), - 'pam_cert_db_path' : _('Path to certificate databse with PKCS#11 modules.'), - 'p11_child_timeout' : _('How many seconds will pam_sss wait for p11_child to finish'), -+ 'pam_app_services' : _('Which PAM services are permitted to contact application domains'), - - # [sudo] - 'sudo_timed' : _('Whether to evaluate the time-based attributes in sudo rules'), -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 8fd2d2c5236246394353a88c50d1510bd6233f77..1a749db754cedd87f263f7ae596d6f8238bb4357 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -119,6 +119,7 @@ option = pam_account_locked_message - option = pam_cert_auth - option = pam_cert_db_path - option = p11_child_timeout -+option = pam_app_services - - [rule/allowed_sudo_options] - validator = ini_allowed_options -diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf -index a38b24208f89e4502e41625c540ea9958d5bbffe..a1a0c2992925a4c7df86832117eec2a0cf7894c9 100644 ---- a/src/config/etc/sssd.api.conf -+++ b/src/config/etc/sssd.api.conf -@@ -73,6 +73,7 @@ pam_account_locked_message = str, None, false - pam_cert_auth = bool, None, false - pam_cert_db_path = str, None, false - p11_child_timeout = int, None, false -+pam_app_services = str, None, false - - [sudo] - # sudo service -diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml -index 8294793c765bfa6bf481693c7d7f206950454681..c4e30396f16c40db37af2f56ac218b6e37201ef7 100644 ---- a/src/man/sssd.conf.5.xml -+++ b/src/man/sssd.conf.5.xml -@@ -1325,6 +1325,18 @@ pam_account_locked_message = Account locked, please contact help desk. - - - -+ -+ pam_app_services (string) -+ -+ -+ Which PAM services are permitted to contact -+ domains of type application -+ -+ -+ Default: Not set -+ -+ -+ - - - -diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c -index ab3f4545520f3fcb2492a6089a039c46f0fb847f..79470823d18138da6ef9235e6336a3220ead1797 100644 ---- a/src/responder/pam/pamsrv.c -+++ b/src/responder/pam/pamsrv.c -@@ -166,6 +166,32 @@ done: - return ret; - } - -+static errno_t get_app_services(struct pam_ctx *pctx) -+{ -+ errno_t ret; -+ -+ ret = confdb_get_string_as_list(pctx->rctx->cdb, pctx, -+ CONFDB_PAM_CONF_ENTRY, -+ CONFDB_PAM_APP_SERVICES, -+ &pctx->app_services); -+ if (ret == ENOENT) { -+ pctx->app_services = talloc_zero_array(pctx, char *, 1); -+ if (pctx->app_services == NULL) { -+ return ENOMEM; -+ } -+ /* Allocating an empty array makes it easier for the consumer -+ * to iterate over it -+ */ -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot read "CONFDB_PAM_APP_SERVICES" [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return ret; -+ } -+ -+ return EOK; -+} -+ - static int pam_process_init(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct confdb_ctx *cdb, -@@ -219,6 +245,13 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, - goto done; - } - -+ ret = get_app_services(pctx); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "get_app_services failed: %d:[%s].\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ - /* Enable automatic reconnection to the Data Provider */ - - /* FIXME: "retries" is too generic, either get it from a global config -diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h -index b3eb56441048ecdba82866a95f1d6d6d5e786c60..b569748fe2a2005cee5df34bef55e803175492a9 100644 ---- a/src/responder/pam/pamsrv.h -+++ b/src/responder/pam/pamsrv.h -@@ -26,6 +26,7 @@ - #include "util/util.h" - #include "sbus/sssd_dbus.h" - #include "responder/common/responder.h" -+#include "responder/common/cache_req/cache_req.h" - - struct pam_auth_req; - -@@ -42,6 +43,9 @@ struct pam_ctx { - char **public_domains; - int public_domains_count; - -+ /* What services are permitted to access application domains */ -+ char **app_services; -+ - bool cert_auth; - int p11_child_debug_fd; - char *nss_db; -@@ -54,6 +58,7 @@ struct pam_auth_dp_req { - struct pam_auth_req { - struct cli_ctx *cctx; - struct sss_domain_info *domain; -+ enum cache_req_dom_type req_dom_type; - - struct pam_data *pd; - -diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c -index fa6d2cc10fe1404196f9d9221a469d7a9a768211..f2b3c74b483e527932dda42279d14a9ac184b475 100644 ---- a/src/responder/pam/pamsrv_cmd.c -+++ b/src/responder/pam/pamsrv_cmd.c -@@ -1161,6 +1161,25 @@ static bool is_domain_public(char *name, - return false; - } - -+static enum cache_req_dom_type -+get_domain_request_type(struct pam_auth_req *preq, -+ struct pam_ctx *pctx) -+{ -+ enum cache_req_dom_type req_dom_type; -+ -+ /* By default, only POSIX domains are to be contacted */ -+ req_dom_type = CACHE_REQ_POSIX_DOM; -+ -+ for (int i = 0; pctx->app_services[i]; i++) { -+ if (strcmp(pctx->app_services[i], preq->pd->service) == 0) { -+ req_dom_type = CACHE_REQ_APPLICATION_DOM; -+ break; -+ } -+ } -+ -+ return req_dom_type; -+} -+ - static errno_t check_cert(TALLOC_CTX *mctx, - struct tevent_context *ev, - struct pam_ctx *pctx, -@@ -1257,6 +1276,9 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) - goto done; - } - -+ /* Determine what domain type to contact */ -+ preq->req_dom_type = get_domain_request_type(preq, pctx); -+ - /* try backend first for authentication before doing local Smartcard - * authentication */ - if (pd->cmd != SSS_PAM_AUTHENTICATE && may_do_cert_auth(pctx, pd)) { -@@ -1316,7 +1338,7 @@ static void pam_forwarder_cert_cb(struct tevent_req *req) - - req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx, - pctx->rctx->ncache, 0, -- CACHE_REQ_POSIX_DOM, NULL, -+ preq->req_dom_type, NULL, - cert); - if (req == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n"); -@@ -1509,7 +1531,7 @@ static int pam_check_user_search(struct pam_auth_req *preq) - preq->cctx->rctx, - preq->cctx->rctx->ncache, - 0, -- CACHE_REQ_POSIX_DOM, -+ preq->req_dom_type, - preq->pd->domain, - data); - if (!dpreq) { -diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c -index 847419658bb983e6548722d6fa6fb22c63ee86b8..d249b8f1ea48f1c17b461c3add9e8c63774e5f88 100644 ---- a/src/tests/cmocka/test_pam_srv.c -+++ b/src/tests/cmocka/test_pam_srv.c -@@ -186,6 +186,15 @@ struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx) - ret = sss_hash_create(pctx, 10, &pctx->id_table); - assert_int_equal(ret, EOK); - -+ /* Two NULLs so that tests can just assign a const to the first slot -+ * should they need it. The code iterates until first NULL anyway -+ */ -+ pctx->app_services = talloc_zero_array(pctx, char *, 2); -+ if (pctx->app_services == NULL) { -+ talloc_free(pctx); -+ return NULL; -+ } -+ - return pctx; - } - -@@ -495,8 +504,12 @@ int __wrap_pam_dp_send_req(struct pam_auth_req *preq, int timeout) - return EOK; - } - --static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name, -- const char *pwd, const char *fa2) -+static void mock_input_pam_ex(TALLOC_CTX *mem_ctx, -+ const char *name, -+ const char *pwd, -+ const char *fa2, -+ const char *svc, -+ bool contact_dp) - { - size_t buf_size; - uint8_t *m_buf; -@@ -536,7 +549,10 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name, - } - } - -- pi.pam_service = "pam_test_service"; -+ if (svc == NULL) { -+ svc = "pam_test_service"; -+ } -+ pi.pam_service = svc; - pi.pam_service_size = strlen(pi.pam_service) + 1; - pi.pam_tty = "/dev/tty"; - pi.pam_tty_size = strlen(pi.pam_tty) + 1; -@@ -559,7 +575,17 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name, - will_return(__wrap_sss_packet_get_body, buf_size); - - mock_parse_inp(name, NULL, EOK); -- mock_account_recv_simple(); -+ if (contact_dp) { -+ mock_account_recv_simple(); -+ } -+} -+ -+static void mock_input_pam(TALLOC_CTX *mem_ctx, -+ const char *name, -+ const char *pwd, -+ const char *fa2) -+{ -+ return mock_input_pam_ex(mem_ctx, name, pwd, fa2, NULL, true); - } - - static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, -@@ -2097,6 +2123,127 @@ void test_filter_response(void **state) - talloc_free(pd); - } - -+static int pam_test_setup_appsvc_posix_dom(void **state) -+{ -+ int ret; -+ -+ ret = pam_test_setup(state); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ /* This config option is only read on startup, which is not executed -+ * in test, so we can't just pass in a param -+ */ -+ pam_test_ctx->pctx->app_services[0] = discard_const("app_svc"); -+ return 0; -+} -+ -+void test_appsvc_posix_dom(void **state) -+{ -+ int ret; -+ -+ /* The domain is POSIX, the request will skip over it */ -+ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "app_svc", false); -+ pam_test_ctx->exp_pam_status = PAM_USER_UNKNOWN; -+ -+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); -+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ set_cmd_cb(test_pam_user_unknown_check); -+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, -+ pam_test_ctx->pam_cmds); -+ assert_int_equal(ret, EOK); -+ -+ ret = test_ev_loop(pam_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ -+void test_not_appsvc_posix_dom(void **state) -+{ -+ int ret; -+ -+ /* A different service than the app one can authenticate against a POSIX domain */ -+ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "not_app_svc", true); -+ -+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); -+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ set_cmd_cb(test_pam_simple_check); -+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, -+ pam_test_ctx->pam_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(pam_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ -+static int pam_test_setup_appsvc_app_dom(void **state) -+{ -+ struct sss_test_conf_param dom_params[] = { -+ { "domain_type", "application" }, -+ { NULL, NULL }, /* Sentinel */ -+ }; -+ struct sss_test_conf_param pam_params[] = { -+ { NULL, NULL }, /* Sentinel */ -+ }; -+ struct sss_test_conf_param monitor_params[] = { -+ { NULL, NULL }, /* Sentinel */ -+ }; -+ -+ -+ test_pam_setup(dom_params, pam_params, monitor_params, state); -+ pam_test_setup_common(); -+ -+ /* This config option is only read on startup, which is not executed -+ * in test, so we can't just pass in a param -+ */ -+ pam_test_ctx->pctx->app_services[0] = discard_const("app_svc"); -+ return 0; -+} -+ -+void test_appsvc_app_dom(void **state) -+{ -+ int ret; -+ -+ /* The domain is POSIX, the request will skip over it */ -+ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "app_svc", true); -+ -+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); -+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ set_cmd_cb(test_pam_simple_check); -+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, -+ pam_test_ctx->pam_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(pam_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ -+void test_not_appsvc_app_dom(void **state) -+{ -+ int ret; -+ -+ /* A different service than the app one can authenticate against a POSIX domain */ -+ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "not_app_svc", false); -+ -+ pam_test_ctx->exp_pam_status = PAM_USER_UNKNOWN; -+ -+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); -+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ set_cmd_cb(test_pam_user_unknown_check); -+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, -+ pam_test_ctx->pam_cmds); -+ assert_int_equal(ret, EOK); -+ -+ ret = test_ev_loop(pam_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ - int main(int argc, const char *argv[]) - { - int rv; -@@ -2216,6 +2363,18 @@ int main(int argc, const char *argv[]) - - cmocka_unit_test_setup_teardown(test_filter_response, - pam_test_setup, pam_test_teardown), -+ cmocka_unit_test_setup_teardown(test_appsvc_posix_dom, -+ pam_test_setup_appsvc_posix_dom, -+ pam_test_teardown), -+ cmocka_unit_test_setup_teardown(test_not_appsvc_posix_dom, -+ pam_test_setup_appsvc_posix_dom, -+ pam_test_teardown), -+ cmocka_unit_test_setup_teardown(test_appsvc_app_dom, -+ pam_test_setup_appsvc_app_dom, -+ pam_test_teardown), -+ cmocka_unit_test_setup_teardown(test_not_appsvc_app_dom, -+ pam_test_setup_appsvc_posix_dom, -+ pam_test_teardown), - }; - - /* Set debug level to invalid value so we can deside if -d 0 was used. */ --- -2.9.3 - diff --git a/SOURCES/0067-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch b/SOURCES/0067-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch new file mode 100644 index 0000000..cc19a9e --- /dev/null +++ b/SOURCES/0067-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch @@ -0,0 +1,86 @@ +From 118860519777791368520f4e92ecbf2ef60cb7db Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 16:45:45 +0100 +Subject: [PATCH 67/67] ipa: compare DNs instead of group names in + ipa_s2n_save_objects() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If group names are used to compare the current list of group memberships +returned by the server with the one from the cache some groups might end +up in the wrong result list if group names are overridden. This +ambiguity can be resolved by using the DNs of the cached objects. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit a52226c651308a0a7732544b492eb4db56b84f1d) +--- + src/providers/ipa/ipa_s2n_exop.c | 31 ++++++++++++------------------- + 1 file changed, 12 insertions(+), 19 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 49c393e9a1eb19ab683949cf633a6838274bc0fe..8b97f78620f19b0708e8a480cb72fd7f12d96dfb 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -2185,10 +2185,9 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + struct ldb_result *res; + enum sysdb_member_type type; + char **sysdb_grouplist; +- char **add_groups; + char **add_groups_dns; +- char **del_groups; + char **del_groups_dns; ++ char **groups_dns; + bool in_transaction = false; + int tret; + struct sysdb_attrs *gid_override_attrs = NULL; +@@ -2514,33 +2513,27 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + } + + if (attrs->response_type == RESP_USER_GROUPLIST) { +- ret = get_sysdb_grouplist(tmp_ctx, dom->sysdb, dom, name, +- &sysdb_grouplist); ++ ret = get_sysdb_grouplist_dn(tmp_ctx, dom->sysdb, dom, name, ++ &sysdb_grouplist); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "get_sysdb_grouplist failed.\n"); + goto done; + } + +- ret = diff_string_lists(tmp_ctx, attrs->groups, +- sysdb_grouplist, &add_groups, +- &del_groups, NULL); ++ ret = get_groups_dns(tmp_ctx, dom, attrs->groups, &groups_dns); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n"); ++ goto done; ++ } ++ ++ ret = diff_string_lists(tmp_ctx, groups_dns, ++ sysdb_grouplist, &add_groups_dns, ++ &del_groups_dns, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "diff_string_lists failed.\n"); + goto done; + } + +- ret = get_groups_dns(tmp_ctx, dom, add_groups, &add_groups_dns); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n"); +- goto done; +- } +- +- ret = get_groups_dns(tmp_ctx, dom, del_groups, &del_groups_dns); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n"); +- goto done; +- } +- + DEBUG(SSSDBG_TRACE_INTERNAL, "Updating memberships for %s\n", + name); + ret = sysdb_update_members_dn(dom, name, SYSDB_MEMBER_USER, +-- +2.14.3 + diff --git a/SOURCES/0068-SDAP-Split-out-utility-function-sdap_get_object_doma.patch b/SOURCES/0068-SDAP-Split-out-utility-function-sdap_get_object_doma.patch new file mode 100644 index 0000000..24ee010 --- /dev/null +++ b/SOURCES/0068-SDAP-Split-out-utility-function-sdap_get_object_doma.patch @@ -0,0 +1,92 @@ +From 0e5d9f481daeeaecefeb68cdc03e45a11dfd7091 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 7 Nov 2017 17:03:13 +0100 +Subject: [PATCH 68/83] SDAP: Split out utility function + sdap_get_object_domain() from sdap_object_in_domain() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The DP request that returns a domain of an entry to responder will need +this functionality in order to map the original DN of the entry found +to a domain name. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit 37fdd9dc1ad5968067f8e3c43a51ed2ac9f3b104) +--- + src/providers/ldap/sdap.c | 26 ++++++++++++++++++++------ + src/providers/ldap/sdap.h | 4 ++++ + 2 files changed, 24 insertions(+), 6 deletions(-) + +diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c +index b6b1c91cb7507ebb95cd559634a77ed44dfb5fc0..59d24fed53cc35751b5c24679e247a42f82e1d0a 100644 +--- a/src/providers/ldap/sdap.c ++++ b/src/providers/ldap/sdap.c +@@ -1673,9 +1673,9 @@ char *sdap_make_oc_list(TALLOC_CTX *mem_ctx, struct sdap_attr_map *map) + } + } + +-bool sdap_object_in_domain(struct sdap_options *opts, +- struct sysdb_attrs *obj, +- struct sss_domain_info *dom) ++struct sss_domain_info *sdap_get_object_domain(struct sdap_options *opts, ++ struct sysdb_attrs *obj, ++ struct sss_domain_info *dom) + { + errno_t ret; + const char *original_dn = NULL; +@@ -1685,7 +1685,7 @@ bool sdap_object_in_domain(struct sdap_options *opts, + if (ret) { + DEBUG(SSSDBG_FUNC_DATA, + "The group has no original DN, assuming our domain\n"); +- return true; ++ return dom; + } + + sdmatch = sdap_domain_get_by_dn(opts, original_dn); +@@ -1693,10 +1693,24 @@ bool sdap_object_in_domain(struct sdap_options *opts, + DEBUG(SSSDBG_FUNC_DATA, + "The original DN of the group cannot " + "be related to any search base\n"); +- return true; ++ return dom; + } + +- return (sdmatch->dom == dom); ++ return sdmatch->dom; ++} ++ ++bool sdap_object_in_domain(struct sdap_options *opts, ++ struct sysdb_attrs *obj, ++ struct sss_domain_info *dom) ++{ ++ struct sss_domain_info *obj_dom; ++ ++ obj_dom = sdap_get_object_domain(opts, obj, dom); ++ if (obj_dom == NULL) { ++ return false; ++ } ++ ++ return (obj_dom == dom); + } + + size_t sdap_steal_objects_in_dom(struct sdap_options *opts, +diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h +index 2ba016ff52313198287ac5196e24517333882099..8b0f1f0ce0fef59554270f0f31cfd2d5f0aa57f5 100644 +--- a/src/providers/ldap/sdap.h ++++ b/src/providers/ldap/sdap.h +@@ -644,6 +644,10 @@ size_t sdap_steal_objects_in_dom(struct sdap_options *opts, + size_t count, + bool filter); + ++struct sss_domain_info *sdap_get_object_domain(struct sdap_options *opts, ++ struct sysdb_attrs *obj, ++ struct sss_domain_info *dom); ++ + bool sdap_object_in_domain(struct sdap_options *opts, + struct sysdb_attrs *obj, + struct sss_domain_info *dom); +-- +2.14.3 + diff --git a/SOURCES/0068-SYSDB-Allow-storing-non-POSIX-users.patch b/SOURCES/0068-SYSDB-Allow-storing-non-POSIX-users.patch deleted file mode 100644 index 8ed534b..0000000 --- a/SOURCES/0068-SYSDB-Allow-storing-non-POSIX-users.patch +++ /dev/null @@ -1,152 +0,0 @@ -From ea8a4436b66877bbae1a73d11917ecdb3bf72718 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 22 Mar 2017 13:00:31 +0100 -Subject: [PATCH 68/72] SYSDB: Allow storing non-POSIX users - -Related to: -https://pagure.io/SSSD/sssd/issue/3310 - -We already do the same for groups. If the user does not have UID number -set but does have the POSIX: false attribute set, then we save the user -with zero UID and the non-POSIX flag. - -Reviewed-by: Sumit Bose ---- - src/db/sysdb_ops.c | 32 ++++++++++++++++++++-------- - src/tests/sysdb-tests.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 79 insertions(+), 9 deletions(-) - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 919f22370ff87eff2bf0bb569ca90f1ee699a61e..3cf9d903f25b9ccd506d7957c94040bdc7d658a3 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -1855,6 +1855,7 @@ int sysdb_add_user(struct sss_domain_info *domain, - struct sysdb_attrs *id_attrs; - uint32_t id; - int ret; -+ bool posix; - - if (domain->mpg) { - if (gid != 0) { -@@ -1926,7 +1927,28 @@ int sysdb_add_user(struct sss_domain_info *domain, - /* Not fatal */ - } - -- if (uid == 0) { -+ if (!attrs) { -+ attrs = sysdb_new_attrs(tmp_ctx); -+ if (!attrs) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix); -+ if (ret == ENOENT) { -+ posix = true; -+ ret = sysdb_attrs_add_bool(attrs, SYSDB_POSIX, true); -+ if (ret) { -+ DEBUG(SSSDBG_TRACE_LIBS, "Failed to add posix attribute.\n"); -+ goto done; -+ } -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_TRACE_LIBS, "Failed to get posix attribute.\n"); -+ goto done; -+ } -+ -+ if (uid == 0 && posix == true) { - ret = sysdb_get_new_id(domain, &id); - if (ret) goto done; - -@@ -1948,14 +1970,6 @@ int sysdb_add_user(struct sss_domain_info *domain, - if (ret) goto done; - } - -- if (!attrs) { -- attrs = sysdb_new_attrs(tmp_ctx); -- if (!attrs) { -- ret = ENOMEM; -- goto done; -- } -- } -- - if (!now) { - now = time(NULL); - } -diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c -index 1767dc3c734c6b2e5f74564debd603e2442f491b..6ec82ce4ca5c4f918bc9f3144c21f33b270ea47e 100644 ---- a/src/tests/sysdb-tests.c -+++ b/src/tests/sysdb-tests.c -@@ -1428,6 +1428,59 @@ START_TEST (test_sysdb_get_user_attr_subdomain) - } - END_TEST - -+START_TEST (test_sysdb_add_nonposix_user) -+{ -+ struct sysdb_test_ctx *test_ctx; -+ const char *get_attrs[] = { SYSDB_GIDNUM, -+ SYSDB_UIDNUM, -+ SYSDB_POSIX, -+ NULL }; -+ struct ldb_result *res; -+ const char *attrval; -+ const char *username = "test_sysdb_add_nonposix_user"; -+ const char *fq_name; -+ struct sysdb_attrs *user_attrs; -+ int ret; -+ uint64_t id; -+ -+ /* Setup */ -+ ret = setup_sysdb_tests(&test_ctx); -+ fail_if(ret != EOK, "Could not set up the test"); -+ -+ /* Create user */ -+ fq_name = sss_create_internal_fqname(test_ctx, username, test_ctx->domain->name); -+ fail_if(fq_name == NULL, "Failed to create fq name."); -+ -+ user_attrs = sysdb_new_attrs(test_ctx); -+ fail_if(user_attrs == NULL); -+ -+ ret = sysdb_attrs_add_bool(user_attrs, SYSDB_POSIX, false); -+ fail_if(ret != EOK, "Could not add attribute"); -+ -+ ret = sysdb_add_user(test_ctx->domain, fq_name, 0, 0, "Gecos", -+ "/home/userhome", "/bin/bash", NULL, user_attrs, 0, 0); -+ fail_if(ret != EOK, "sysdb_add_user failed."); -+ -+ /* Test */ -+ ret = sysdb_get_user_attr(test_ctx, test_ctx->domain, fq_name, -+ get_attrs, &res); -+ fail_if(ret != EOK, "Could not get user attributes."); -+ fail_if(res->count != 1, "Invalid number of entries, expected 1, got %d", -+ res->count); -+ -+ attrval = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_POSIX, NULL); -+ fail_if(strcasecmp(attrval, "false") != 0, "Got bad attribute value."); -+ -+ id = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 123); -+ fail_unless(id == 0, "Wrong UID value"); -+ -+ id = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 123); -+ fail_unless(id == 0, "Wrong GID value"); -+ -+ talloc_free(test_ctx); -+} -+END_TEST -+ - START_TEST (test_sysdb_add_group_member) - { - struct sysdb_test_ctx *test_ctx; -@@ -7044,6 +7097,9 @@ Suite *create_sysdb_suite(void) - /* Test GetUserAttr with subdomain user */ - tcase_add_test(tc_sysdb, test_sysdb_get_user_attr_subdomain); - -+ /* Test adding a non-POSIX user */ -+ tcase_add_test(tc_sysdb, test_sysdb_add_nonposix_user); -+ - /* ===== NETGROUP TESTS ===== */ - - /* Create a new netgroup */ --- -2.9.3 - diff --git a/SOURCES/0069-LDAP-Extract-the-check-whether-to-run-a-POSIX-check-.patch b/SOURCES/0069-LDAP-Extract-the-check-whether-to-run-a-POSIX-check-.patch new file mode 100644 index 0000000..1b64e0d --- /dev/null +++ b/SOURCES/0069-LDAP-Extract-the-check-whether-to-run-a-POSIX-check-.patch @@ -0,0 +1,115 @@ +From 880552cc45e55c7ef9f81423aff8fe867451d752 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Thu, 30 Nov 2017 11:47:30 +0100 +Subject: [PATCH 69/83] LDAP: Extract the check whether to run a POSIX check to + a function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This will reduce the code duplication in the following patches and will +allow to keep all the logic on one place so that when/if we change the +code in the future, we only have to change the single place. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit 8e93ebb2a6f7644c389c1d1f4e92a21c4d0b2b45) +--- + src/providers/ldap/ldap_common.c | 15 +++++++++++++++ + src/providers/ldap/ldap_common.h | 4 ++++ + src/providers/ldap/ldap_id.c | 15 ++++++--------- + src/providers/ldap/sdap_async_enum.c | 7 +++---- + 4 files changed, 28 insertions(+), 13 deletions(-) + +diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c +index 0597e91f7fade47aeb34565597c730ac406e0cfc..3eff3515d95043d4b59cb0d9953cf050355a0ca5 100644 +--- a/src/providers/ldap/ldap_common.c ++++ b/src/providers/ldap/ldap_common.c +@@ -971,3 +971,18 @@ sdap_id_ctx_new(TALLOC_CTX *mem_ctx, struct be_ctx *bectx, + + return sdap_ctx; + } ++ ++bool should_run_posix_check(struct sdap_id_ctx *ctx, ++ bool use_id_mapping, ++ bool posix_request) ++{ ++ if (use_id_mapping == false && ++ posix_request == true && ++ ctx->opts->schema_type == SDAP_SCHEMA_AD && ++ ctx->srv_opts && ++ ctx->srv_opts->posix_checked == false) { ++ return true; ++ } ++ ++ return false; ++} +diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h +index 0510b7d5ab5121bd96f699e8e59520a2a18a604f..fa7cda4df9d7334f6f0f5baccae0cba0478bfbea 100644 +--- a/src/providers/ldap/ldap_common.h ++++ b/src/providers/ldap/ldap_common.h +@@ -304,6 +304,10 @@ char *get_enterprise_principal_string_filter(TALLOC_CTX *mem_ctx, + const char *princ, + struct dp_option *sdap_basic_opts); + ++bool should_run_posix_check(struct sdap_id_ctx *ctx, ++ bool id_mapping, ++ bool posix_request); ++ + char *sdap_get_access_filter(TALLOC_CTX *mem_ctx, + const char *base_filter); + +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index e89fc6133316f684810afe4c1a0731b8a04f2931..6ab9e0aa1db3eed32deb75211ded30a4cb48ca30 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -411,11 +411,9 @@ static void users_get_connect_done(struct tevent_req *subreq) + /* If POSIX attributes have been requested with an AD server and we + * have no idea about POSIX attributes support, run a one-time check + */ +- if (state->use_id_mapping == false && +- state->non_posix == false && +- state->ctx->opts->schema_type == SDAP_SCHEMA_AD && +- state->ctx->srv_opts && +- state->ctx->srv_opts->posix_checked == false) { ++ if (should_run_posix_check(state->ctx, ++ state->use_id_mapping, ++ !state->non_posix)) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, + sdap_id_op_handle(state->op), + state->sdom->user_search_bases, +@@ -958,10 +956,9 @@ static void groups_get_connect_done(struct tevent_req *subreq) + /* If POSIX attributes have been requested with an AD server and we + * have no idea about POSIX attributes support, run a one-time check + */ +- if (state->use_id_mapping == false && +- state->ctx->opts->schema_type == SDAP_SCHEMA_AD && +- state->ctx->srv_opts && +- state->ctx->srv_opts->posix_checked == false) { ++ if (should_run_posix_check(state->ctx, ++ state->use_id_mapping, ++ !state->non_posix)) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, + sdap_id_op_handle(state->op), + state->sdom->user_search_bases, +diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c +index 91e481c4e694126900c729e86d187fba355de0b8..2cef4eb886f982ba388a34955bdd38468fe68200 100644 +--- a/src/providers/ldap/sdap_async_enum.c ++++ b/src/providers/ldap/sdap_async_enum.c +@@ -196,10 +196,9 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq) + /* If POSIX attributes have been requested with an AD server and we + * have no idea about POSIX attributes support, run a one-time check + */ +- if (use_id_mapping == false && +- state->ctx->opts->schema_type == SDAP_SCHEMA_AD && +- state->ctx->srv_opts && +- state->ctx->srv_opts->posix_checked == false) { ++ if (should_run_posix_check(state->ctx, ++ use_id_mapping, ++ true)) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, + sdap_id_op_handle(state->user_op), + state->sdom->user_search_bases, +-- +2.14.3 + diff --git a/SOURCES/0069-SYSDB-Only-generate-new-UID-in-local-domain.patch b/SOURCES/0069-SYSDB-Only-generate-new-UID-in-local-domain.patch deleted file mode 100644 index c6a76f3..0000000 --- a/SOURCES/0069-SYSDB-Only-generate-new-UID-in-local-domain.patch +++ /dev/null @@ -1,36 +0,0 @@ -From ee344275c041f68e943360c975e3356ba251cef8 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 28 Mar 2017 14:49:31 +0200 -Subject: [PATCH 69/72] SYSDB: Only generate new UID in local domain - -To avoid issues where a user with no UID but without the posix=false -flag was passed to sysdb, we only allow generating the new ID in the -local domain. This might prevent bugs where non-POSIX users would get a -UID created by sysdb which might allow accessing resources owned by that -UID. - -Reviewed-by: Sumit Bose ---- - src/db/sysdb_ops.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 3cf9d903f25b9ccd506d7957c94040bdc7d658a3..4d7b2abd8026c90aaf4e7be687102e459cf3690e 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -1422,6 +1422,12 @@ int sysdb_get_new_id(struct sss_domain_info *domain, - return ENOMEM; - } - -+ if (strcasecmp(domain->provider, "local") != 0) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Generating new ID is only supported in the local domain!\n"); -+ return ENOTSUP; -+ } -+ - base_dn = sysdb_domain_dn(tmp_ctx, domain); - if (!base_dn) { - talloc_zfree(tmp_ctx); --- -2.9.3 - diff --git a/SOURCES/0070-LDAP-Only-run-the-POSIX-check-with-a-GC-connection.patch b/SOURCES/0070-LDAP-Only-run-the-POSIX-check-with-a-GC-connection.patch new file mode 100644 index 0000000..f4be7e3 --- /dev/null +++ b/SOURCES/0070-LDAP-Only-run-the-POSIX-check-with-a-GC-connection.patch @@ -0,0 +1,95 @@ +From 405f08eabf5017cc00891fb2090be80306c8aeae Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Thu, 30 Nov 2017 12:01:51 +0100 +Subject: [PATCH 70/83] LDAP: Only run the POSIX check with a GC connection +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Previously, we used to run the POSIX check also with an LDAP connection. +This was wasteful, but worked, so the waste wasn't the biggest problem +-- the approach would only cause problems with the following patch which +uses a NULL search base to search the Global Catalog, because searching +with a SUBTREE scope and a NULL base returns a referral with an LDAP +connection. + +Instead, this patch uses a heuristics (whether the connection ignores +the offline state) to check if the connection is a POSIX one and if it +is NOT, then skips the POSIX check. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit dacfe74113dde62ddaaa7f9abf9d2b6448d89db6) +--- + src/providers/ldap/ldap_common.c | 2 ++ + src/providers/ldap/ldap_common.h | 1 + + src/providers/ldap/ldap_id.c | 2 ++ + src/providers/ldap/sdap_async_enum.c | 1 + + 4 files changed, 6 insertions(+) + +diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c +index 3eff3515d95043d4b59cb0d9953cf050355a0ca5..36e79b9d6ca23ef5e21a8b0bedc7f05db8f4fc98 100644 +--- a/src/providers/ldap/ldap_common.c ++++ b/src/providers/ldap/ldap_common.c +@@ -973,12 +973,14 @@ sdap_id_ctx_new(TALLOC_CTX *mem_ctx, struct be_ctx *bectx, + } + + bool should_run_posix_check(struct sdap_id_ctx *ctx, ++ struct sdap_id_conn_ctx *conn, + bool use_id_mapping, + bool posix_request) + { + if (use_id_mapping == false && + posix_request == true && + ctx->opts->schema_type == SDAP_SCHEMA_AD && ++ conn->ignore_mark_offline == true && + ctx->srv_opts && + ctx->srv_opts->posix_checked == false) { + return true; +diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h +index fa7cda4df9d7334f6f0f5baccae0cba0478bfbea..44dbc3fb0678412f46366321e0be836313380949 100644 +--- a/src/providers/ldap/ldap_common.h ++++ b/src/providers/ldap/ldap_common.h +@@ -305,6 +305,7 @@ char *get_enterprise_principal_string_filter(TALLOC_CTX *mem_ctx, + struct dp_option *sdap_basic_opts); + + bool should_run_posix_check(struct sdap_id_ctx *ctx, ++ struct sdap_id_conn_ctx *conn, + bool id_mapping, + bool posix_request); + +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index 6ab9e0aa1db3eed32deb75211ded30a4cb48ca30..47969a9749253721334a20f46230f7aecea64882 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -412,6 +412,7 @@ static void users_get_connect_done(struct tevent_req *subreq) + * have no idea about POSIX attributes support, run a one-time check + */ + if (should_run_posix_check(state->ctx, ++ state->conn, + state->use_id_mapping, + !state->non_posix)) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, +@@ -957,6 +958,7 @@ static void groups_get_connect_done(struct tevent_req *subreq) + * have no idea about POSIX attributes support, run a one-time check + */ + if (should_run_posix_check(state->ctx, ++ state->conn, + state->use_id_mapping, + !state->non_posix)) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, +diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c +index 2cef4eb886f982ba388a34955bdd38468fe68200..baa039d63c71cc5054e6af6538d34d04cde6b858 100644 +--- a/src/providers/ldap/sdap_async_enum.c ++++ b/src/providers/ldap/sdap_async_enum.c +@@ -197,6 +197,7 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq) + * have no idea about POSIX attributes support, run a one-time check + */ + if (should_run_posix_check(state->ctx, ++ state->user_conn, + use_id_mapping, + true)) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, +-- +2.14.3 + diff --git a/SOURCES/0070-LDAP-save-non-POSIX-users-in-application-domains.patch b/SOURCES/0070-LDAP-save-non-POSIX-users-in-application-domains.patch deleted file mode 100644 index d70a026..0000000 --- a/SOURCES/0070-LDAP-save-non-POSIX-users-in-application-domains.patch +++ /dev/null @@ -1,141 +0,0 @@ -From 3abbd7569f96a980676e0323d95301c50acdf062 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 22 Mar 2017 13:06:08 +0100 -Subject: [PATCH 70/72] LDAP: save non-POSIX users in application domains - -Related to: -https://pagure.io/SSSD/sssd/issue/3310 - -If a user being saved by the LDAP provider does not have a UID or GID -and the domain type is application, we save the user entry as non-POSIX. - -Reviewed-by: Sumit Bose ---- - src/providers/ldap/sdap_async_users.c | 72 +++++++++++++++++++++++++++-------- - 1 file changed, 57 insertions(+), 15 deletions(-) - -diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c -index 3d957ab584865f74499bc732395388a78965fe5f..265cd7e4f7929c295d5bdcfbd781221b74601f13 100644 ---- a/src/providers/ldap/sdap_async_users.c -+++ b/src/providers/ldap/sdap_async_users.c -@@ -112,6 +112,28 @@ done: - return ret; - } - -+static errno_t sdap_set_non_posix_flag(struct sysdb_attrs *attrs, -+ const char *pkey) -+{ -+ errno_t ret; -+ -+ ret = sysdb_attrs_add_uint32(attrs, pkey, 0); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to add a zero ID to a non-posix object!\n"); -+ return ret; -+ } -+ -+ ret = sysdb_attrs_add_bool(attrs, SYSDB_POSIX, false); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Error: Failed to mark objects as non-posix!\n"); -+ return ret; -+ } -+ -+ return EOK; -+} -+ - /* FIXME: support storing additional attributes */ - int sdap_save_user(TALLOC_CTX *memctx, - struct sdap_options *opts, -@@ -130,8 +152,8 @@ int sdap_save_user(TALLOC_CTX *memctx, - const char *homedir; - const char *shell; - const char *orig_dn = NULL; -- uid_t uid; -- gid_t gid; -+ uid_t uid = 0; -+ gid_t gid = 0; - struct sysdb_attrs *user_attrs; - char *upn = NULL; - size_t i; -@@ -146,6 +168,7 @@ int sdap_save_user(TALLOC_CTX *memctx, - size_t c; - char *p1; - char *p2; -+ bool is_posix = true; - - DEBUG(SSSDBG_TRACE_FUNC, "Save user\n"); - -@@ -295,19 +318,29 @@ int sdap_save_user(TALLOC_CTX *memctx, - ret = sysdb_attrs_get_uint32_t(attrs, - opts->user_map[SDAP_AT_USER_UID].sys_name, - &uid); -- if (ret != EOK) { -+ if (ret == ENOENT && dom->type == DOM_TYPE_APPLICATION) { -+ DEBUG(SSSDBG_TRACE_INTERNAL, -+ "Marking object as non-posix and setting ID=0!\n"); -+ ret = sdap_set_non_posix_flag(user_attrs, -+ opts->user_map[SDAP_AT_USER_UID].sys_name); -+ if (ret != EOK) { -+ goto done; -+ } -+ is_posix = false; -+ } else if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, -- "no uid provided for [%s] in domain [%s].\n", -+ "Cannot retrieve UID for [%s] in domain [%s].\n", - user_name, dom->name); -- ret = EINVAL; -+ ret = ERR_NO_POSIX; - goto done; - } - } -- /* check that the uid is valid for this domain */ -- if (OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) { -- DEBUG(SSSDBG_OP_FAILURE, -- "User [%s] filtered out! (uid out of range)\n", -- user_name); -+ -+ /* check that the uid is valid for this domain if the user is a POSIX one */ -+ if (is_posix == true && OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "User [%s] filtered out! (uid out of range)\n", -+ user_name); - ret = EINVAL; - goto done; - } -@@ -349,17 +382,26 @@ int sdap_save_user(TALLOC_CTX *memctx, - ret = sysdb_attrs_get_uint32_t(attrs, - opts->user_map[SDAP_AT_USER_GID].sys_name, - &gid); -- if (ret != EOK) { -+ if (ret == ENOENT && dom->type == DOM_TYPE_APPLICATION) { -+ DEBUG(SSSDBG_TRACE_INTERNAL, -+ "Marking object as non-posix and setting ID=0!\n"); -+ ret = sdap_set_non_posix_flag(attrs, -+ opts->user_map[SDAP_AT_USER_GID].sys_name); -+ if (ret != EOK) { -+ goto done; -+ } -+ is_posix = false; -+ } else if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, -- "no gid provided for [%s] in domain [%s].\n", -- user_name, dom->name); -- ret = EINVAL; -+ "Cannot retrieve GID for [%s] in domain [%s].\n", -+ user_name, dom->name); -+ ret = ERR_NO_POSIX; - goto done; - } - } - - /* check that the gid is valid for this domain */ -- if (IS_SUBDOMAIN(dom) == false && -+ if (is_posix == true && IS_SUBDOMAIN(dom) == false && - OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) { - DEBUG(SSSDBG_CRIT_FAILURE, - "User [%s] filtered out! (primary gid out of range)\n", --- -2.9.3 - diff --git a/SOURCES/0071-LDAP-Relax-search-filters-in-application-domains.patch b/SOURCES/0071-LDAP-Relax-search-filters-in-application-domains.patch deleted file mode 100644 index 73f2862..0000000 --- a/SOURCES/0071-LDAP-Relax-search-filters-in-application-domains.patch +++ /dev/null @@ -1,254 +0,0 @@ -From b2a823cf415a12416dca9ff019666906d61cfc2f Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 22 Mar 2017 13:06:14 +0100 -Subject: [PATCH 71/72] LDAP: Relax search filters in application domains - -Related to: -https://pagure.io/SSSD/sssd/issue/3310 - -If a request comes towards an application domain, we can drop the part -of the filter that asserts that the object has a valid UID/GID. Instead, -we just search by name. - -Reviewed-by: Sumit Bose ---- - src/providers/ldap/ldap_id.c | 35 ++++++++++++++++++++++++---- - src/providers/ldap/sdap_async_enum.c | 7 +++++- - src/providers/ldap/sdap_async_initgroups.c | 37 ++++++++++++++++++++++++------ - 3 files changed, 66 insertions(+), 13 deletions(-) - -diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c -index 0bee0ca8d71abece6749fdb8393b9ceacb64417d..7400dc1f57e30cc6ae5f939ffa628a1e9dd47e06 100644 ---- a/src/providers/ldap/ldap_id.c -+++ b/src/providers/ldap/ldap_id.c -@@ -56,6 +56,7 @@ struct users_get_state { - char *filter; - const char **attrs; - bool use_id_mapping; -+ bool non_posix; - - int dp_error; - int sdap_ret; -@@ -114,6 +115,10 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - state->filter_value = filter_value; - state->filter_type = filter_type; - -+ if (state->domain->type == DOM_TYPE_APPLICATION) { -+ state->non_posix = true; -+ } -+ - state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( - ctx->opts->idmap_ctx, - sdom->dom->name, -@@ -292,7 +297,13 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - } - } - -- if (state->use_id_mapping || filter_type == BE_FILTER_SECID) { -+ if (state->non_posix) { -+ state->filter = talloc_asprintf(state, -+ "(&%s(objectclass=%s)(%s=*))", -+ user_filter, -+ ctx->opts->user_map[SDAP_OC_USER].name, -+ ctx->opts->user_map[SDAP_AT_USER_NAME].name); -+ } else if (state->use_id_mapping || filter_type == BE_FILTER_SECID) { - /* When mapping IDs or looking for SIDs, we don't want to limit - * ourselves to users with a UID value. But there must be a SID to map - * from. -@@ -304,7 +315,8 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - ctx->opts->user_map[SDAP_AT_USER_NAME].name, - ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name); - } else { -- /* When not ID-mapping, make sure there is a non-NULL UID */ -+ /* When not ID-mapping or looking up POSIX users, -+ * make sure there is a non-NULL UID */ - state->filter = talloc_asprintf(state, - "(&%s(objectclass=%s)(%s=*)(&(%s=*)(!(%s=0))))", - user_filter, -@@ -380,6 +392,7 @@ static void users_get_connect_done(struct tevent_req *subreq) - * have no idea about POSIX attributes support, run a one-time check - */ - if (state->use_id_mapping == false && -+ state->non_posix == false && - state->ctx->opts->schema_type == SDAP_SCHEMA_AD && - state->ctx->srv_opts && - state->ctx->srv_opts->posix_checked == false) { -@@ -650,6 +663,7 @@ struct groups_get_state { - char *filter; - const char **attrs; - bool use_id_mapping; -+ bool non_posix; - - int dp_error; - int sdap_ret; -@@ -709,6 +723,10 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, - state->filter_value = filter_value; - state->filter_type = filter_type; - -+ if (state->domain->type == DOM_TYPE_APPLICATION) { -+ state->non_posix = true; -+ } -+ - state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( - ctx->opts->idmap_ctx, - sdom->dom->name, -@@ -827,9 +845,11 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, - goto done; - } - -- if (state->use_id_mapping || filter_type == BE_FILTER_SECID) { -- /* When mapping IDs or looking for SIDs, we don't want to limit -- * ourselves to groups with a GID value -+ if (state->non_posix -+ || state->use_id_mapping -+ || filter_type == BE_FILTER_SECID) { -+ /* When mapping IDs or looking for SIDs, or when in a non-POSIX domain, -+ * we don't want to limit ourselves to groups with a GID value - */ - - state->filter = talloc_asprintf(state, -@@ -1123,6 +1143,7 @@ struct groups_by_user_state { - int filter_type; - const char *extra_value; - const char **attrs; -+ bool non_posix; - - int dp_error; - int sdap_ret; -@@ -1204,6 +1225,10 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx, - state->domain = sdom->dom; - state->sysdb = sdom->dom->sysdb; - -+ if (state->domain->type == DOM_TYPE_APPLICATION) { -+ state->non_posix = true; -+ } -+ - ret = build_attrs_from_map(state, ctx->opts->group_map, SDAP_OPTS_GROUP, - NULL, &state->attrs, NULL); - if (ret != EOK) goto fail; -diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c -index 3f65059e18d5c8b548da0babec867d27c3a64198..91e481c4e694126900c729e86d187fba355de0b8 100644 ---- a/src/providers/ldap/sdap_async_enum.c -+++ b/src/providers/ldap/sdap_async_enum.c -@@ -717,6 +717,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx, - struct enum_groups_state *state; - int ret; - bool use_mapping; -+ bool non_posix = false; - char *oc_list; - - req = tevent_req_create(memctx, &state, struct enum_groups_state); -@@ -727,6 +728,10 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx, - state->ctx = ctx; - state->op = op; - -+ if (sdom->dom->type == DOM_TYPE_APPLICATION) { -+ non_posix = true; -+ } -+ - use_mapping = sdap_idmap_domain_has_algorithmic_mapping( - ctx->opts->idmap_ctx, - sdom->dom->name, -@@ -749,7 +754,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx, - goto fail; - } - -- if (use_mapping) { -+ if (!non_posix && use_mapping) { - /* If we're ID-mapping, check for the objectSID as well */ - state->filter = talloc_asprintf_append_buffer( - state->filter, "(%s=*)", -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index 79af7a3eda3fe8533933535c98c2b4b4698dfda2..c926ddcbefe471daa80505e139c3f19efa33b9ba 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -376,7 +376,7 @@ struct sdap_initgr_rfc2307_state { - struct sdap_handle *sh; - const char **attrs; - const char *name; -- const char *base_filter; -+ char *base_filter; - const char *orig_dn; - char *filter; - int timeout; -@@ -473,18 +473,32 @@ struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx, - } - - state->base_filter = talloc_asprintf(state, -- "(&(%s=%s)(%s)(%s=*)(&(%s=*)(!(%s=0))))", -+ "(&(%s=%s)(%s)(%s=*)", - opts->group_map[SDAP_AT_GROUP_MEMBER].name, - clean_name, oc_list, -- opts->group_map[SDAP_AT_GROUP_NAME].name, -- opts->group_map[SDAP_AT_GROUP_GID].name, -- opts->group_map[SDAP_AT_GROUP_GID].name); -+ opts->group_map[SDAP_AT_GROUP_NAME].name); - if (!state->base_filter) { - talloc_zfree(req); - return NULL; - } - talloc_zfree(clean_name); - -+ switch (domain->type) { -+ case DOM_TYPE_APPLICATION: -+ state->base_filter = talloc_asprintf_append(state->base_filter, ")"); -+ break; -+ case DOM_TYPE_POSIX: -+ state->base_filter = talloc_asprintf_append(state->base_filter, -+ "(&(%s=*)(!(%s=0))))", -+ opts->group_map[SDAP_AT_GROUP_GID].name, -+ opts->group_map[SDAP_AT_GROUP_GID].name); -+ break; -+ } -+ if (!state->base_filter) { -+ ret = ENOMEM; -+ goto done; -+ } -+ - ret = sdap_initgr_rfc2307_next_base(req); - - done: -@@ -2666,6 +2680,7 @@ struct sdap_get_initgr_state { - char *shortname; - char *filter; - int timeout; -+ bool non_posix; - - struct sysdb_attrs *orig_user; - -@@ -2724,6 +2739,10 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, - goto done; - } - -+ if (state->dom->type == DOM_TYPE_APPLICATION) { -+ state->non_posix = true; -+ } -+ - use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( - id_ctx->opts->idmap_ctx, - sdom->dom->name, -@@ -2813,7 +2832,10 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, - } - } - -- if (use_id_mapping) { -+ if (state->non_posix) { -+ state->user_base_filter = talloc_asprintf_append(state->user_base_filter, -+ ")"); -+ } else if (use_id_mapping) { - /* When mapping IDs or looking for SIDs, we don't want to limit - * ourselves to users with a UID value. But there must be a SID to map - * from. -@@ -2822,7 +2844,8 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, - "(%s=*))", - id_ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name); - } else { -- /* When not ID-mapping, make sure there is a non-NULL UID */ -+ /* When not ID-mapping or looking up app users, make sure there -+ * is a non-NULL UID */ - state->user_base_filter = talloc_asprintf_append(state->user_base_filter, - "(&(%s=*)(!(%s=0))))", - id_ctx->opts->user_map[SDAP_AT_USER_UID].name, --- -2.9.3 - diff --git a/SOURCES/0071-SDAP-Search-with-a-NULL-search-base-when-looking-up-.patch b/SOURCES/0071-SDAP-Search-with-a-NULL-search-base-when-looking-up-.patch new file mode 100644 index 0000000..5be8736 --- /dev/null +++ b/SOURCES/0071-SDAP-Search-with-a-NULL-search-base-when-looking-up-.patch @@ -0,0 +1,191 @@ +From c7003e815aca1c28953c3dc55311ffc3f2d4ab28 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Sun, 12 Nov 2017 19:24:01 +0100 +Subject: [PATCH 71/83] SDAP: Search with a NULL search base when looking up an + ID in the Global Catalog +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The posix_check request is used to determine whether domains in the forest +replicate the POSIX attributes into the Global Catalog. And since the +schema modification that replicates the attributes is not per-domain, but +per-forest, we don't need to iterate over search bases when checking for +the POSIX attribute presence. It is OK to just search with a NULL search +base (and it's what Windows clients do, too). + +Additionally, searching over the whole GC will come handy when implementing +the request that located an account's domain. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit 6ae22d9adc0b075361defc99b8f14480ba8e7b46) +--- + src/providers/ldap/ldap_id.c | 2 -- + src/providers/ldap/sdap_async.c | 51 +++++++----------------------------- + src/providers/ldap/sdap_async.h | 1 - + src/providers/ldap/sdap_async_enum.c | 1 - + 4 files changed, 10 insertions(+), 45 deletions(-) + +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index 47969a9749253721334a20f46230f7aecea64882..b5ac3a749113a281fe8a5564ac341ced0570eded 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -417,7 +417,6 @@ static void users_get_connect_done(struct tevent_req *subreq) + !state->non_posix)) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, + sdap_id_op_handle(state->op), +- state->sdom->user_search_bases, + dp_opt_get_int(state->ctx->opts->basic, + SDAP_SEARCH_TIMEOUT)); + if (subreq == NULL) { +@@ -963,7 +962,6 @@ static void groups_get_connect_done(struct tevent_req *subreq) + !state->non_posix)) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, + sdap_id_op_handle(state->op), +- state->sdom->user_search_bases, + dp_opt_get_int(state->ctx->opts->basic, + SDAP_SEARCH_TIMEOUT)); + if (subreq == NULL) { +diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c +index 246e12a1f386da1841963d5c1d1c4d2870cc1b6b..1df0b85f4bda6442d8da66784ad7424306b1f051 100644 +--- a/src/providers/ldap/sdap_async.c ++++ b/src/providers/ldap/sdap_async.c +@@ -2573,7 +2573,6 @@ int sdap_asq_search_recv(struct tevent_req *req, + } + + /* ==Posix attribute presence test================================= */ +-static errno_t sdap_posix_check_next(struct tevent_req *req); + static void sdap_posix_check_done(struct tevent_req *subreq); + static errno_t sdap_posix_check_parse(struct sdap_handle *sh, + struct sdap_msg *msg, +@@ -2583,12 +2582,10 @@ struct sdap_posix_check_state { + struct tevent_context *ev; + struct sdap_options *opts; + struct sdap_handle *sh; +- struct sdap_search_base **search_bases; + int timeout; + + const char **attrs; + const char *filter; +- size_t base_iter; + + bool has_posix; + }; +@@ -2596,10 +2593,10 @@ struct sdap_posix_check_state { + struct tevent_req * + sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev, + struct sdap_options *opts, struct sdap_handle *sh, +- struct sdap_search_base **search_bases, + int timeout) + { + struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; + struct sdap_posix_check_state *state; + errno_t ret; + +@@ -2610,7 +2607,6 @@ sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev, + state->ev = ev; + state->sh = sh; + state->opts = opts; +- state->search_bases = search_bases; + state->timeout = timeout; + + state->attrs = talloc_array(state, const char *, 4); +@@ -2634,43 +2630,26 @@ sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev, + goto fail; + } + +- ret = sdap_posix_check_next(req); +- if (ret != EOK) { +- goto fail; +- } +- +- return req; +- +-fail: +- tevent_req_error(req, ret); +- tevent_req_post(req, ev); +- return req; +-} +- +-static errno_t sdap_posix_check_next(struct tevent_req *req) +-{ +- struct tevent_req *subreq = NULL; +- struct sdap_posix_check_state *state = +- tevent_req_data(req, struct sdap_posix_check_state); +- +- DEBUG(SSSDBG_TRACE_FUNC, +- "Searching for POSIX attributes with base [%s]\n", +- state->search_bases[state->base_iter]->basedn); +- + subreq = sdap_get_generic_ext_send(state, state->ev, state->opts, + state->sh, +- state->search_bases[state->base_iter]->basedn, ++ "", + LDAP_SCOPE_SUBTREE, state->filter, + state->attrs, + NULL, NULL, 1, state->timeout, + sdap_posix_check_parse, state, + SDAP_SRCH_FLG_SIZELIMIT_SILENT); + if (subreq == NULL) { +- return ENOMEM; ++ ret = ENOMEM; ++ goto fail; + } + tevent_req_set_callback(subreq, sdap_posix_check_done, req); + +- return EOK; ++ return req; ++ ++fail: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; + } + + static errno_t sdap_posix_check_parse(struct sdap_handle *sh, +@@ -2746,16 +2725,6 @@ static void sdap_posix_check_done(struct tevent_req *subreq) + return; + } + +- state->base_iter++; +- if (state->search_bases[state->base_iter]) { +- /* There are more search bases to try */ +- ret = sdap_posix_check_next(req); +- if (ret != EOK) { +- tevent_req_error(req, ret); +- } +- return; +- } +- + /* All bases done! */ + DEBUG(SSSDBG_TRACE_LIBS, "Cycled through all bases\n"); + tevent_req_done(req); +diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h +index 6e5800b42ba4a045fa7985b09a80b6b86b8c6055..7216ba032e551196cf5258b4e58fbfc8cfe417ea 100644 +--- a/src/providers/ldap/sdap_async.h ++++ b/src/providers/ldap/sdap_async.h +@@ -269,7 +269,6 @@ int sdap_deref_search_recv(struct tevent_req *req, + struct tevent_req * + sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev, + struct sdap_options *opts, struct sdap_handle *sh, +- struct sdap_search_base **search_bases, + int timeout); + + int sdap_posix_check_recv(struct tevent_req *req, +diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c +index baa039d63c71cc5054e6af6538d34d04cde6b858..ec0c679823a8cd9820bb978f77799a3f86621271 100644 +--- a/src/providers/ldap/sdap_async_enum.c ++++ b/src/providers/ldap/sdap_async_enum.c +@@ -202,7 +202,6 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq) + true)) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, + sdap_id_op_handle(state->user_op), +- state->sdom->user_search_bases, + dp_opt_get_int(state->ctx->opts->basic, + SDAP_SEARCH_TIMEOUT)); + if (subreq == NULL) { +-- +2.14.3 + diff --git a/SOURCES/0072-KRB5-Authenticate-users-in-a-non-POSIX-domain-using-.patch b/SOURCES/0072-KRB5-Authenticate-users-in-a-non-POSIX-domain-using-.patch deleted file mode 100644 index 05693f1..0000000 --- a/SOURCES/0072-KRB5-Authenticate-users-in-a-non-POSIX-domain-using-.patch +++ /dev/null @@ -1,353 +0,0 @@ -From 3f32e79858f268ce6501de44e5158e8c12f688dd Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 22 Mar 2017 13:01:18 +0100 -Subject: [PATCH 72/72] KRB5: Authenticate users in a non-POSIX domain using a - MEMORY ccache - -Related to: -https://pagure.io/SSSD/sssd/issue/3310 - -The following changes were done to the Kerberos authentication code -in order to support authentication in a non-POSIX environment: - - delayed authentication is disabled in non-POSIX domains - - when a user logs in in a non-POSIX domain, SSSD uses a - MEMORY:$username ccache and destroys is then krb5_child finishes - so that just the numeric result is used - - krb5_child doesn't drop privileges in this configuration because - there is nothing to drop privileges to - -Reviewed-by: Sumit Bose ---- - src/providers/krb5/krb5_auth.c | 62 ++++++++++++++++------ - src/providers/krb5/krb5_auth.h | 2 + - src/providers/krb5/krb5_child.c | 32 +++++++++-- - src/providers/krb5/krb5_child_handler.c | 15 +++++- - .../krb5/krb5_delayed_online_authentication.c | 7 +++ - src/providers/krb5/krb5_init.c | 3 ++ - 6 files changed, 99 insertions(+), 22 deletions(-) - -diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c -index c2d6d7eeacc1f766024c4d629f25fd0f0be24e5e..2faf18d17a735476c20f9cc27b15be4a39cadc5c 100644 ---- a/src/providers/krb5/krb5_auth.c -+++ b/src/providers/krb5/krb5_auth.c -@@ -42,6 +42,8 @@ - #include "providers/krb5/krb5_utils.h" - #include "providers/krb5/krb5_ccache.h" - -+#define NON_POSIX_CCNAME_FMT "MEMORY:sssd_nonposix_dummy_%u" -+ - static int krb5_mod_ccname(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, -@@ -200,6 +202,7 @@ errno_t krb5_setup(TALLOC_CTX *mem_ctx, - talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup); - - kr->pd = pd; -+ kr->dom = dom; - kr->krb5_ctx = krb5_ctx; - - ret = get_krb_primary(krb5_ctx->name_to_primary, -@@ -275,8 +278,11 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, - return; - } - -- ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); -- if (ret != EOK) { -+ ret = add_user_to_delayed_online_authentication(krb5_ctx, domain, pd, uid); -+ if (ret == ENOTSUP) { -+ /* This error is not fatal */ -+ DEBUG(SSSDBG_MINOR_FAILURE, "Delayed authentication not supported\n"); -+ } else if (ret != EOK) { - /* This error is not fatal */ - DEBUG(SSSDBG_CRIT_FAILURE, - "add_user_to_delayed_online_authentication failed.\n"); -@@ -291,21 +297,43 @@ static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr, - { - const char *ccname_template; - -- ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL); -+ switch (kr->dom->type) { -+ case DOM_TYPE_POSIX: -+ ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL); - -- kr->ccname = expand_ccname_template(kr, kr, ccname_template, -- kr->krb5_ctx->illegal_path_re, true, -- be_ctx->domain->case_sensitive); -- if (kr->ccname == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n"); -- return ENOMEM; -- } -+ kr->ccname = expand_ccname_template(kr, kr, ccname_template, -+ kr->krb5_ctx->illegal_path_re, true, -+ be_ctx->domain->case_sensitive); -+ if (kr->ccname == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n"); -+ return ENOMEM; -+ } - -- kr->old_ccname = ldb_msg_find_attr_as_string(user_msg, -- SYSDB_CCACHE_FILE, NULL); -- if (kr->old_ccname == NULL) { -- DEBUG(SSSDBG_TRACE_LIBS, -- "No ccache file for user [%s] found.\n", kr->pd->user); -+ kr->old_ccname = ldb_msg_find_attr_as_string(user_msg, -+ SYSDB_CCACHE_FILE, NULL); -+ if (kr->old_ccname == NULL) { -+ DEBUG(SSSDBG_TRACE_LIBS, -+ "No ccache file for user [%s] found.\n", kr->pd->user); -+ } -+ break; -+ case DOM_TYPE_APPLICATION: -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Domain type application, will use in-memory ccache\n"); -+ /* We don't care about using cryptographic randomness, just -+ * a non-predictable ccname, so using rand() here is fine -+ */ -+ kr->ccname = talloc_asprintf(kr, -+ NON_POSIX_CCNAME_FMT, -+ rand() % UINT_MAX); -+ if (kr->ccname == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n"); -+ return ENOMEM; -+ } -+ -+ break; -+ default: -+ DEBUG(SSSDBG_FATAL_FAILURE, "Unsupported domain type\n"); -+ return EINVAL; - } - - return EOK; -@@ -617,7 +645,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, - kr->uid = sss_view_ldb_msg_find_attr_as_uint64(state->domain, - res->msgs[0], - SYSDB_UIDNUM, 0); -- if (kr->uid == 0) { -+ if (kr->uid == 0 && state->domain->type == DOM_TYPE_POSIX) { - DEBUG(SSSDBG_CONF_SETTINGS, - "UID for user [%s] not known.\n", pd->user); - ret = ENOENT; -@@ -627,7 +655,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, - kr->gid = sss_view_ldb_msg_find_attr_as_uint64(state->domain, - res->msgs[0], - SYSDB_GIDNUM, 0); -- if (kr->gid == 0) { -+ if (kr->gid == 0 && state->domain->type == DOM_TYPE_POSIX) { - DEBUG(SSSDBG_CONF_SETTINGS, - "GID for user [%s] not known.\n", pd->user); - ret = ENOENT; -diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h -index 75ad916e79b29043120543ab3c4c1bd27e09d913..8ad3aeff21e58f9055ae144eaa450992c6391ba6 100644 ---- a/src/providers/krb5/krb5_auth.h -+++ b/src/providers/krb5/krb5_auth.h -@@ -50,6 +50,7 @@ - struct krb5child_req { - struct pam_data *pd; - struct krb5_ctx *krb5_ctx; -+ struct sss_domain_info *dom; - - const char *ccname; - const char *old_ccname; -@@ -118,6 +119,7 @@ parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len, - struct krb5_child_response **_res); - - errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, -+ struct sss_domain_info *domain, - struct pam_data *pd, - uid_t uid); - errno_t init_delayed_online_authentication(struct krb5_ctx *krb5_ctx, -diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c -index a4128dda6b0861a95dba223047d66c4158b1afb6..cbbc892bee0365892ac66d3654c974d325166b60 100644 ---- a/src/providers/krb5/krb5_child.c -+++ b/src/providers/krb5/krb5_child.c -@@ -80,6 +80,7 @@ struct krb5_req { - char *ccname; - char *keytab; - bool validate; -+ bool posix_domain; - bool send_pac; - bool use_enterprise_princ; - char *fast_ccname; -@@ -102,6 +103,16 @@ struct krb5_req { - static krb5_context krb5_error_ctx; - #define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error) - -+static errno_t k5c_become_user(uid_t uid, gid_t gid, bool is_posix) -+{ -+ if (is_posix == false) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Will not drop privileges for a non-POSIX user\n"); -+ return EOK; -+ } -+ return become_user(uid, gid); -+} -+ - static krb5_error_code set_lifetime_options(struct cli_opts *cli_opts, - krb5_get_init_creds_opt *options) - { -@@ -1561,6 +1572,15 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - DEBUG(SSSDBG_CONF_SETTINGS, "TGT validation is disabled.\n"); - } - -+ /* In a non-POSIX environment, we only care about the return code from -+ * krb5_child, so let's not even attempt to create the ccache -+ */ -+ if (kr->posix_domain == false) { -+ DEBUG(SSSDBG_TRACE_LIBS, -+ "Finished authentication in a non-POSIX domain\n"); -+ goto done; -+ } -+ - /* If kr->ccname is cache collection (DIR:/...), we want to work - * directly with file ccache (DIR::/...), but cache collection - * should be returned back to back end. -@@ -2146,6 +2166,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, - size_t p = 0; - uint32_t len; - uint32_t validate; -+ uint32_t posix_domain; - uint32_t send_pac; - uint32_t use_enterprise_princ; - struct pam_data *pd; -@@ -2167,6 +2188,8 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, - SAFEALIGN_COPY_UINT32_CHECK(&kr->gid, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&validate, buf + p, size, &p); - kr->validate = (validate == 0) ? false : true; -+ SAFEALIGN_COPY_UINT32_CHECK(&posix_domain, buf + p, size, &p); -+ kr->posix_domain = (posix_domain == 0) ? false : true; - SAFEALIGN_COPY_UINT32_CHECK(offline, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&send_pac, buf + p, size, &p); - kr->send_pac = (send_pac == 0) ? false : true; -@@ -2331,6 +2354,7 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx, - krb5_context ctx, - uid_t fast_uid, - gid_t fast_gid, -+ bool posix_domain, - struct cli_opts *cli_opts, - const char *primary, - const char *realm, -@@ -2420,7 +2444,7 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx, - /* Try to carry on */ - } - -- kerr = become_user(fast_uid, fast_gid); -+ kerr = k5c_become_user(fast_uid, fast_gid, posix_domain); - if (kerr != 0) { - DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed: %d\n", kerr); - exit(1); -@@ -2572,7 +2596,7 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand) - } - - kerr = check_fast_ccache(kr, kr->ctx, kr->fast_uid, kr->fast_gid, -- kr->cli_opts, -+ kr->posix_domain, kr->cli_opts, - fast_principal, fast_principal_realm, - kr->keytab, &kr->fast_ccname); - if (kerr != 0) { -@@ -2773,7 +2797,7 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline) - * the user who is logging in. The same applies to the offline case - * the user who is logging in. The same applies to the offline case. - */ -- kerr = become_user(kr->uid, kr->gid); -+ kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain); - if (kerr != 0) { - DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n"); - return kerr; -@@ -3075,7 +3099,7 @@ int main(int argc, const char *argv[]) - if ((sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN - && sss_authtok_get_type(kr->pd->authtok) - != SSS_AUTHTOK_TYPE_SC_KEYPAD)) { -- kerr = become_user(kr->uid, kr->gid); -+ kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain); - if (kerr != 0) { - DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n"); - ret = EFAULT; -diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c -index 680e67b089fcb32280352af24aae35af133a52f3..87e79a06e917aadb622455bccfc2e9c6769f70c2 100644 ---- a/src/providers/krb5/krb5_child_handler.c -+++ b/src/providers/krb5/krb5_child_handler.c -@@ -107,6 +107,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, - uint32_t validate; - uint32_t send_pac; - uint32_t use_enterprise_principal; -+ uint32_t posix_domain; - size_t username_len = 0; - errno_t ret; - -@@ -131,6 +132,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr, - break; - } - -+ switch (kr->dom->type) { -+ case DOM_TYPE_POSIX: -+ posix_domain = 1; -+ break; -+ case DOM_TYPE_APPLICATION: -+ posix_domain = 0; -+ break; -+ default: -+ return EINVAL; -+ } -+ - if (kr->pd->cmd == SSS_CMD_RENEW || kr->is_offline) { - use_enterprise_principal = false; - } else { -@@ -151,7 +163,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, - kr->pd->cmd == SSS_CMD_RENEW || - kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || - kr->pd->cmd == SSS_PAM_CHAUTHTOK) { -- buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + -+ buf->size += 5*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + - sss_authtok_get_size(kr->pd->authtok); - - buf->size += sizeof(uint32_t); -@@ -182,6 +194,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->uid, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->gid, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &validate, &rp); -+ SAFEALIGN_COPY_UINT32(&buf->data[rp], &posix_domain, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->is_offline, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &send_pac, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &use_enterprise_principal, &rp); -diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c -index bf2ef775573ba6bad79a99ad43b5d9748516e794..1cb7eade0e4cb9afbc4d031a07b3519ba08456d6 100644 ---- a/src/providers/krb5/krb5_delayed_online_authentication.c -+++ b/src/providers/krb5/krb5_delayed_online_authentication.c -@@ -234,6 +234,7 @@ static void delayed_online_authentication_callback(void *private_data) - } - - errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, -+ struct sss_domain_info *domain, - struct pam_data *pd, - uid_t uid) - { -@@ -242,6 +243,12 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, - hash_value_t value; - struct pam_data *new_pd; - -+ if (domain->type != DOM_TYPE_POSIX) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Domain type does not support delayed authentication\n"); -+ return ENOTSUP; -+ } -+ - if (krb5_ctx->deferred_auth_ctx == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Missing context for delayed online authentication.\n"); -diff --git a/src/providers/krb5/krb5_init.c b/src/providers/krb5/krb5_init.c -index 12c8dfcc49af75de619ec0858aaff81504698273..66ae68fb4773af3987f2062246bc6493107c74d5 100644 ---- a/src/providers/krb5/krb5_init.c -+++ b/src/providers/krb5/krb5_init.c -@@ -136,6 +136,9 @@ errno_t sssm_krb5_init(TALLOC_CTX *mem_ctx, - return ENOMEM; - } - -+ /* Only needed to generate random ccache names for non-POSIX domains */ -+ srand(time(NULL) * getpid()); -+ - ret = sss_krb5_get_options(ctx, be_ctx->cdb, be_ctx->conf_path, &ctx->opts); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get krb5 options [%d]: %s\n", --- -2.9.3 - diff --git a/SOURCES/0072-SDAP-Rename-sdap_posix_check-to-sdap_gc_posix_check.patch b/SOURCES/0072-SDAP-Rename-sdap_posix_check-to-sdap_gc_posix_check.patch new file mode 100644 index 0000000..3335d35 --- /dev/null +++ b/SOURCES/0072-SDAP-Rename-sdap_posix_check-to-sdap_gc_posix_check.patch @@ -0,0 +1,251 @@ +From ada45cd38a73b1b196db459849fcc19781bc06fc Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 6 Dec 2017 16:26:15 +0100 +Subject: [PATCH 72/83] SDAP: Rename sdap_posix_check to sdap_gc_posix_check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Because searching the LDAP port of Active Directory server with a NULL +search base yields an error: + https://technet.microsoft.com/en-us/library/cc755809(v=ws.10).aspx +we changed the POSIX check request to only run against a GC connection +in a previous patch. To make it clearer to the caller that this request +should only be used with a GC connection, this patch renames the +request. + +There are no functional changes in this patch. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit ba8a92bbd59f189bd1323dd0c4010cdfc694be35) +--- + src/providers/ldap/ldap_id.c | 20 +++++++-------- + src/providers/ldap/sdap_async.c | 48 ++++++++++++++++++------------------ + src/providers/ldap/sdap_async.h | 16 ++++++++---- + src/providers/ldap/sdap_async_enum.c | 10 ++++---- + 4 files changed, 50 insertions(+), 44 deletions(-) + +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index b5ac3a749113a281fe8a5564ac341ced0570eded..3824f8f9aa8d2892664f1182376bedf6fb8627f6 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -415,10 +415,10 @@ static void users_get_connect_done(struct tevent_req *subreq) + state->conn, + state->use_id_mapping, + !state->non_posix)) { +- subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, +- sdap_id_op_handle(state->op), +- dp_opt_get_int(state->ctx->opts->basic, +- SDAP_SEARCH_TIMEOUT)); ++ subreq = sdap_gc_posix_check_send(state, state->ev, state->ctx->opts, ++ sdap_id_op_handle(state->op), ++ dp_opt_get_int(state->ctx->opts->basic, ++ SDAP_SEARCH_TIMEOUT)); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; +@@ -441,7 +441,7 @@ static void users_get_posix_check_done(struct tevent_req *subreq) + struct users_get_state *state = tevent_req_data(req, + struct users_get_state); + +- ret = sdap_posix_check_recv(subreq, &has_posix); ++ ret = sdap_gc_posix_check_recv(subreq, &has_posix); + talloc_zfree(subreq); + if (ret != EOK) { + /* We can only finish the id_op on error as the connection +@@ -960,10 +960,10 @@ static void groups_get_connect_done(struct tevent_req *subreq) + state->conn, + state->use_id_mapping, + !state->non_posix)) { +- subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, +- sdap_id_op_handle(state->op), +- dp_opt_get_int(state->ctx->opts->basic, +- SDAP_SEARCH_TIMEOUT)); ++ subreq = sdap_gc_posix_check_send(state, state->ev, state->ctx->opts, ++ sdap_id_op_handle(state->op), ++ dp_opt_get_int(state->ctx->opts->basic, ++ SDAP_SEARCH_TIMEOUT)); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; +@@ -985,7 +985,7 @@ static void groups_get_posix_check_done(struct tevent_req *subreq) + struct groups_get_state *state = tevent_req_data(req, + struct groups_get_state); + +- ret = sdap_posix_check_recv(subreq, &has_posix); ++ ret = sdap_gc_posix_check_recv(subreq, &has_posix); + talloc_zfree(subreq); + if (ret != EOK) { + /* We can only finish the id_op on error as the connection +diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c +index 1df0b85f4bda6442d8da66784ad7424306b1f051..a9bea4f80903aeb9d0fdb4d2b8f2acb36d81d6fe 100644 +--- a/src/providers/ldap/sdap_async.c ++++ b/src/providers/ldap/sdap_async.c +@@ -2573,12 +2573,12 @@ int sdap_asq_search_recv(struct tevent_req *req, + } + + /* ==Posix attribute presence test================================= */ +-static void sdap_posix_check_done(struct tevent_req *subreq); +-static errno_t sdap_posix_check_parse(struct sdap_handle *sh, +- struct sdap_msg *msg, +- void *pvt); ++static void sdap_gc_posix_check_done(struct tevent_req *subreq); ++static errno_t sdap_gc_posix_check_parse(struct sdap_handle *sh, ++ struct sdap_msg *msg, ++ void *pvt); + +-struct sdap_posix_check_state { ++struct sdap_gc_posix_check_state { + struct tevent_context *ev; + struct sdap_options *opts; + struct sdap_handle *sh; +@@ -2591,16 +2591,16 @@ struct sdap_posix_check_state { + }; + + struct tevent_req * +-sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev, +- struct sdap_options *opts, struct sdap_handle *sh, +- int timeout) ++sdap_gc_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev, ++ struct sdap_options *opts, struct sdap_handle *sh, ++ int timeout) + { + struct tevent_req *req = NULL; + struct tevent_req *subreq = NULL; +- struct sdap_posix_check_state *state; ++ struct sdap_gc_posix_check_state *state; + errno_t ret; + +- req = tevent_req_create(memctx, &state, struct sdap_posix_check_state); ++ req = tevent_req_create(memctx, &state, struct sdap_gc_posix_check_state); + if (req == NULL) { + return NULL; + } +@@ -2636,13 +2636,13 @@ sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev, + LDAP_SCOPE_SUBTREE, state->filter, + state->attrs, + NULL, NULL, 1, state->timeout, +- sdap_posix_check_parse, state, ++ sdap_gc_posix_check_parse, state, + SDAP_SRCH_FLG_SIZELIMIT_SILENT); + if (subreq == NULL) { + ret = ENOMEM; + goto fail; + } +- tevent_req_set_callback(subreq, sdap_posix_check_done, req); ++ tevent_req_set_callback(subreq, sdap_gc_posix_check_done, req); + + return req; + +@@ -2652,13 +2652,13 @@ fail: + return req; + } + +-static errno_t sdap_posix_check_parse(struct sdap_handle *sh, +- struct sdap_msg *msg, +- void *pvt) ++static errno_t sdap_gc_posix_check_parse(struct sdap_handle *sh, ++ struct sdap_msg *msg, ++ void *pvt) + { + struct berval **vals = NULL; +- struct sdap_posix_check_state *state = +- talloc_get_type(pvt, struct sdap_posix_check_state); ++ struct sdap_gc_posix_check_state *state = ++ talloc_get_type(pvt, struct sdap_gc_posix_check_state); + char *dn; + char *endptr; + +@@ -2700,12 +2700,12 @@ done: + return EOK; + } + +-static void sdap_posix_check_done(struct tevent_req *subreq) ++static void sdap_gc_posix_check_done(struct tevent_req *subreq) + { + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); +- struct sdap_posix_check_state *state = +- tevent_req_data(req, struct sdap_posix_check_state); ++ struct sdap_gc_posix_check_state *state = ++ tevent_req_data(req, struct sdap_gc_posix_check_state); + errno_t ret; + + ret = sdap_get_generic_ext_recv(subreq, NULL, NULL, NULL); +@@ -2730,11 +2730,11 @@ static void sdap_posix_check_done(struct tevent_req *subreq) + tevent_req_done(req); + } + +-int sdap_posix_check_recv(struct tevent_req *req, +- bool *_has_posix) ++int sdap_gc_posix_check_recv(struct tevent_req *req, ++ bool *_has_posix) + { +- struct sdap_posix_check_state *state = tevent_req_data(req, +- struct sdap_posix_check_state); ++ struct sdap_gc_posix_check_state *state = tevent_req_data(req, ++ struct sdap_gc_posix_check_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + +diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h +index 7216ba032e551196cf5258b4e58fbfc8cfe417ea..26f13e38bf6dff08a8cd0e6b3b5282effda80c9e 100644 +--- a/src/providers/ldap/sdap_async.h ++++ b/src/providers/ldap/sdap_async.h +@@ -266,13 +266,19 @@ int sdap_deref_search_recv(struct tevent_req *req, + size_t *reply_count, + struct sdap_deref_attrs ***reply); + ++/* ++ * This request should only be ran against a Global Catalog connection ++ * because it uses a NULL search base to search all domains in the forest, ++ * which would return an error with an LDAP port: ++ * https://technet.microsoft.com/en-us/library/cc755809(v=ws.10).aspx ++ */ + struct tevent_req * +-sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev, +- struct sdap_options *opts, struct sdap_handle *sh, +- int timeout); ++sdap_gc_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev, ++ struct sdap_options *opts, struct sdap_handle *sh, ++ int timeout); + +-int sdap_posix_check_recv(struct tevent_req *req, +- bool *_has_posix); ++int sdap_gc_posix_check_recv(struct tevent_req *req, ++ bool *_has_posix); + + struct tevent_req * + sdap_sd_search_send(TALLOC_CTX *memctx, +diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c +index ec0c679823a8cd9820bb978f77799a3f86621271..ea9d51adc7f94145cd7e689893bf7fd81028c5bb 100644 +--- a/src/providers/ldap/sdap_async_enum.c ++++ b/src/providers/ldap/sdap_async_enum.c +@@ -200,10 +200,10 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq) + state->user_conn, + use_id_mapping, + true)) { +- subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, +- sdap_id_op_handle(state->user_op), +- dp_opt_get_int(state->ctx->opts->basic, +- SDAP_SEARCH_TIMEOUT)); ++ subreq = sdap_gc_posix_check_send(state, state->ev, state->ctx->opts, ++ sdap_id_op_handle(state->user_op), ++ dp_opt_get_int(state->ctx->opts->basic, ++ SDAP_SEARCH_TIMEOUT)); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; +@@ -233,7 +233,7 @@ static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq) + struct sdap_dom_enum_ex_state *state = tevent_req_data(req, + struct sdap_dom_enum_ex_state); + +- ret = sdap_posix_check_recv(subreq, &has_posix); ++ ret = sdap_gc_posix_check_recv(subreq, &has_posix); + talloc_zfree(subreq); + if (ret != EOK && ret != ERR_NO_POSIX) { + /* We can only finish the id_op on error as the connection +-- +2.14.3 + diff --git a/SOURCES/0073-DP-Create-a-new-handler-function-getAccountDomain.patch b/SOURCES/0073-DP-Create-a-new-handler-function-getAccountDomain.patch new file mode 100644 index 0000000..72a0f99 --- /dev/null +++ b/SOURCES/0073-DP-Create-a-new-handler-function-getAccountDomain.patch @@ -0,0 +1,455 @@ +From 1bed72e4faa2734b0eef6a107b2dc24bf052e576 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 30 Oct 2017 20:50:41 +0100 +Subject: [PATCH 73/83] DP: Create a new handler function getAccountDomain() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adds a new method getAccountDomain() which is a bit similar to +getAccountInfo, except it doesn't fetch, parse and store the entry, but +just returns the domain or a subdomain the entry was found in. + +At the moment, the method only supports requests by ID. + +A default handler is provided (and in this patch used by all the +domains) which returns ERR_GET_ACCT_DOM_NOT_SUPPORTED. This return +code should be evaluated by the responder so that this DP method is +not called again, because it's not supported by the back end type. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit c0f9f5a0f6d71a1596ee3cef549b4b02295313c3) +--- + src/providers/ad/ad_init.c | 4 + + src/providers/data_provider/dp.h | 20 ++++ + src/providers/data_provider/dp_custom_data.h | 6 ++ + src/providers/data_provider/dp_iface.c | 3 +- + src/providers/data_provider/dp_iface.h | 17 ++++ + src/providers/data_provider/dp_iface.xml | 7 ++ + src/providers/data_provider/dp_iface_generated.c | 31 +++++++ + src/providers/data_provider/dp_iface_generated.h | 5 + + src/providers/data_provider/dp_target_id.c | 113 +++++++++++++++++++++++ + src/providers/files/files_init.c | 6 ++ + src/providers/ipa/ipa_init.c | 4 + + src/providers/ldap/ldap_init.c | 4 + + src/providers/proxy/proxy_init.c | 4 + + src/util/util_errors.c | 1 + + src/util/util_errors.h | 1 + + 15 files changed, 225 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c +index e62025d4acd24844a5c7082d00c597516f35de16..7efb6aa71cbd2551422c87e0b0c5c1fe91390375 100644 +--- a/src/providers/ad/ad_init.c ++++ b/src/providers/ad/ad_init.c +@@ -510,6 +510,10 @@ errno_t sssm_ad_id_init(TALLOC_CTX *mem_ctx, + sdap_online_check_handler_send, sdap_online_check_handler_recv, id_ctx->sdap_id_ctx, + struct sdap_id_ctx, void, struct dp_reply_std); + ++ dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER, ++ default_account_domain_send, default_account_domain_recv, NULL, ++ void, struct dp_get_acct_domain_data, struct dp_reply_std); ++ + return EOK; + } + +diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h +index aa5b781158c54545b26034602bb25db46b189e87..ceb49da53b88142924e1792c6f64a22ec369677b 100644 +--- a/src/providers/data_provider/dp.h ++++ b/src/providers/data_provider/dp.h +@@ -82,6 +82,7 @@ enum dp_methods { + DPM_HOSTID_HANDLER, + DPM_DOMAINS_HANDLER, + DPM_SESSION_HANDLER, ++ DPM_ACCT_DOMAIN_HANDLER, + + DPM_REFRESH_ACCESS_RULES, + +@@ -179,4 +180,23 @@ void dp_sbus_reset_users_memcache(struct data_provider *provider); + void dp_sbus_reset_groups_memcache(struct data_provider *provider); + void dp_sbus_reset_initgr_memcache(struct data_provider *provider); + ++/* ++ * A dummy handler for DPM_ACCT_DOMAIN_HANDLER. ++ * ++ * Its purpose is to always return ERR_GET_ACCT_DOM_NOT_SUPPORTED ++ * which the responder should evaluate as "this back end does not ++ * support locating entries' domain" and never call ++ * DPM_ACCT_DOMAIN_HANDLER again ++ * ++ * This request cannot fail, except for critical errors like OOM. ++ */ ++struct tevent_req * ++default_account_domain_send(TALLOC_CTX *mem_ctx, ++ void *unused_ctx, ++ struct dp_get_acct_domain_data *data, ++ struct dp_req_params *params); ++errno_t default_account_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct dp_reply_std *data); ++ + #endif /* _DP_H_ */ +diff --git a/src/providers/data_provider/dp_custom_data.h b/src/providers/data_provider/dp_custom_data.h +index d9de288b62f4f6763ceb205dc596876cfc58bf6c..7c64bde4513961e79200e852c7277f77e064d5a3 100644 +--- a/src/providers/data_provider/dp_custom_data.h ++++ b/src/providers/data_provider/dp_custom_data.h +@@ -43,6 +43,12 @@ struct dp_subdomains_data { + const char *domain_hint; + }; + ++struct dp_get_acct_domain_data { ++ uint32_t entry_type; ++ uint32_t filter_type; ++ const char *filter_value; ++}; ++ + struct dp_id_data { + uint32_t entry_type; + uint32_t filter_type; +diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c +index 28d70e686f63a3572ac595f493aa1d59436c563f..124be0048f38a93d06561ff7b0d1916838587103 100644 +--- a/src/providers/data_provider/dp_iface.c ++++ b/src/providers/data_provider/dp_iface.c +@@ -33,7 +33,8 @@ struct iface_dp iface_dp = { + .autofsHandler = dp_autofs_handler, + .hostHandler = dp_host_handler, + .getDomains = dp_subdomains_handler, +- .getAccountInfo = dp_get_account_info_handler ++ .getAccountInfo = dp_get_account_info_handler, ++ .getAccountDomain = dp_get_account_domain_handler, + }; + + struct iface_dp_backend iface_dp_backend = { +diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h +index 759b9e6c9eb7f53836ae0b641b34e6c31e65779f..0a2f81eb5c108aa7596c974157b0dfafb041869f 100644 +--- a/src/providers/data_provider/dp_iface.h ++++ b/src/providers/data_provider/dp_iface.h +@@ -58,6 +58,23 @@ errno_t dp_subdomains_handler(struct sbus_request *sbus_req, + void *dp_cli, + const char *domain_hint); + ++/* ++ * Return a domain the account belongs to. ++ * ++ * The request uses the dp_reply_std structure for reply, with the following ++ * semantics: ++ * - DP_ERR_OK - it is expected that the string message contains the domain name ++ * the entry was found in. A 'negative' reply where the ++ * request returns DP_ERR_OK, but no domain should be treated ++ * as authoritative, as if the entry does not exist. ++ * - DP_ERR_* - the string message contains error string that corresponds ++ * to the errno field in dp_reply_std(). ++ */ ++errno_t dp_get_account_domain_handler(struct sbus_request *sbus_req, ++ void *dp_cli, ++ uint32_t entry_type, ++ const char *filter); ++ + /* org.freedesktop.sssd.DataProvider.Backend */ + errno_t dp_backend_is_online(struct sbus_request *sbus_req, + void *dp_cli, +diff --git a/src/providers/data_provider/dp_iface.xml b/src/providers/data_provider/dp_iface.xml +index 2bfa9dfa7e9d02d2d12c3358967f6969438a97a2..c2431850bca4baa529fb18e0480e781308b12dd6 100644 +--- a/src/providers/data_provider/dp_iface.xml ++++ b/src/providers/data_provider/dp_iface.xml +@@ -79,5 +79,12 @@ + + + ++ ++ ++ ++ ++ ++ ++ + + +diff --git a/src/providers/data_provider/dp_iface_generated.c b/src/providers/data_provider/dp_iface_generated.c +index 11ee2e24a69cc8d4d19fdbeed613e76081aef15d..4d093444536b15d8a17f7e507b93948e1df6ffee 100644 +--- a/src/providers/data_provider/dp_iface_generated.c ++++ b/src/providers/data_provider/dp_iface_generated.c +@@ -313,6 +313,30 @@ int iface_dp_getAccountInfo_finish(struct sbus_request *req, uint16_t arg_dp_err + DBUS_TYPE_INVALID); + } + ++/* arguments for org.freedesktop.sssd.dataprovider.getAccountDomain */ ++const struct sbus_arg_meta iface_dp_getAccountDomain__in[] = { ++ { "entry_type", "u" }, ++ { "filter", "s" }, ++ { NULL, } ++}; ++ ++/* arguments for org.freedesktop.sssd.dataprovider.getAccountDomain */ ++const struct sbus_arg_meta iface_dp_getAccountDomain__out[] = { ++ { "dp_error", "q" }, ++ { "error", "u" }, ++ { "domain_name", "s" }, ++ { NULL, } ++}; ++ ++int iface_dp_getAccountDomain_finish(struct sbus_request *req, uint16_t arg_dp_error, uint32_t arg_error, const char *arg_domain_name) ++{ ++ return sbus_request_return_and_finish(req, ++ DBUS_TYPE_UINT16, &arg_dp_error, ++ DBUS_TYPE_UINT32, &arg_error, ++ DBUS_TYPE_STRING, &arg_domain_name, ++ DBUS_TYPE_INVALID); ++} ++ + /* methods for org.freedesktop.sssd.dataprovider */ + const struct sbus_method_meta iface_dp__methods[] = { + { +@@ -357,6 +381,13 @@ const struct sbus_method_meta iface_dp__methods[] = { + offsetof(struct iface_dp, getAccountInfo), + invoke_uusss_method, + }, ++ { ++ "getAccountDomain", /* name */ ++ iface_dp_getAccountDomain__in, ++ iface_dp_getAccountDomain__out, ++ offsetof(struct iface_dp, getAccountDomain), ++ invoke_us_method, ++ }, + { NULL, } + }; + +diff --git a/src/providers/data_provider/dp_iface_generated.h b/src/providers/data_provider/dp_iface_generated.h +index 541a90b0b5a5bc0a346cbd04974d33c8bb0983c5..b629ec77487328a41615f3ca7e812088730f40c4 100644 +--- a/src/providers/data_provider/dp_iface_generated.h ++++ b/src/providers/data_provider/dp_iface_generated.h +@@ -38,6 +38,7 @@ + #define IFACE_DP_HOSTHANDLER "hostHandler" + #define IFACE_DP_GETDOMAINS "getDomains" + #define IFACE_DP_GETACCOUNTINFO "getAccountInfo" ++#define IFACE_DP_GETACCOUNTDOMAIN "getAccountDomain" + + /* ------------------------------------------------------------------------ + * DBus handlers +@@ -110,6 +111,7 @@ struct iface_dp { + int (*hostHandler)(struct sbus_request *req, void *data, uint32_t arg_dp_flags, const char *arg_name, const char *arg_alias); + int (*getDomains)(struct sbus_request *req, void *data, const char *arg_domain_hint); + int (*getAccountInfo)(struct sbus_request *req, void *data, uint32_t arg_dp_flags, uint32_t arg_entry_type, const char *arg_filter, const char *arg_domain, const char *arg_extra); ++ int (*getAccountDomain)(struct sbus_request *req, void *data, uint32_t arg_entry_type, const char *arg_filter); + }; + + /* finish function for autofsHandler */ +@@ -124,6 +126,9 @@ int iface_dp_getDomains_finish(struct sbus_request *req, uint16_t arg_dp_error, + /* finish function for getAccountInfo */ + int iface_dp_getAccountInfo_finish(struct sbus_request *req, uint16_t arg_dp_error, uint32_t arg_error, const char *arg_error_message); + ++/* finish function for getAccountDomain */ ++int iface_dp_getAccountDomain_finish(struct sbus_request *req, uint16_t arg_dp_error, uint32_t arg_error, const char *arg_domain_name); ++ + /* ------------------------------------------------------------------------ + * DBus Interface Metadata + * +diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c +index 820a6574cb3a224cce4b7d8286af306f234454a3..11a36e9ce9b1aefcabb04dfe51395b6f4e4bc899 100644 +--- a/src/providers/data_provider/dp_target_id.c ++++ b/src/providers/data_provider/dp_target_id.c +@@ -490,3 +490,116 @@ done: + + return ret; + } ++ ++static bool ++check_and_parse_acct_domain_filter(struct dp_get_acct_domain_data *data, ++ const char *filter) ++{ ++ /* We will use sizeof() to determine the length of a string so we don't ++ * call strlen over and over again with each request. Not a bottleneck, ++ * but unnecessary and simple to avoid. */ ++ static struct { ++ const char *name; ++ size_t lenght; ++ uint32_t type; ++ } types[] = {FILTER_TYPE("idnumber", BE_FILTER_IDNUM), ++ {0, 0, 0}}; ++ int i; ++ ++ if (SBUS_IS_STRING_EMPTY(filter)) { ++ return false; ++ } ++ ++ for (i = 0; types[i].name != NULL; i++) { ++ if (strncmp(filter, types[i].name, types[i].lenght) == 0) { ++ data->filter_type = types[i].type; ++ data->filter_value = SBUS_SET_STRING(&filter[types[i].lenght]); ++ return true; ++ } ++ } ++ ++ if (strcmp(filter, ENUM_INDICATOR) == 0) { ++ data->filter_type = BE_FILTER_ENUM; ++ data->filter_value = NULL; ++ return true; ++ } ++ ++ return false; ++} ++ ++errno_t dp_get_account_domain_handler(struct sbus_request *sbus_req, ++ void *dp_cli, ++ uint32_t entry_type, ++ const char *filter) ++{ ++ struct dp_get_acct_domain_data *data; ++ const char *key = NULL; ++ errno_t ret; ++ ++ data = talloc_zero(sbus_req, struct dp_get_acct_domain_data); ++ if (data == NULL) { ++ return ENOMEM; ++ } ++ data->entry_type = entry_type; ++ ++ if (!check_and_parse_acct_domain_filter(data, filter)) { ++ ret = EINVAL; ++ goto done; ++ } ++ ++ dp_req_with_reply(dp_cli, NULL, "AccountDomain", key, sbus_req, ++ DPT_ID, DPM_ACCT_DOMAIN_HANDLER, 0, data, ++ dp_req_reply_std, struct dp_reply_std); ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(data); ++ } ++ ++ return ret; ++} ++ ++struct default_account_domain_state { ++ struct dp_reply_std reply; ++}; ++ ++struct tevent_req * ++default_account_domain_send(TALLOC_CTX *mem_ctx, ++ void *unused_ctx, ++ struct dp_get_acct_domain_data *data, ++ struct dp_req_params *params) ++{ ++ struct default_account_domain_state *state; ++ struct tevent_req *req; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct default_account_domain_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ dp_reply_std_set(&state->reply, ++ DP_ERR_DECIDE, ERR_GET_ACCT_DOM_NOT_SUPPORTED, ++ NULL); ++ tevent_req_done(req); ++ tevent_req_post(req, params->ev); ++ return req; ++} ++ ++errno_t default_account_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct dp_reply_std *data) ++{ ++ struct default_account_domain_state *state = NULL; ++ ++ state = tevent_req_data(req, struct default_account_domain_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *data = state->reply; ++ ++ return EOK; ++} +diff --git a/src/providers/files/files_init.c b/src/providers/files/files_init.c +index b91dfbac9bf9d4b678ebdfa6b1cb0971b4477dd9..8e5cd4cf913b79653616120d6ed6540e62ade932 100644 +--- a/src/providers/files/files_init.c ++++ b/src/providers/files/files_init.c +@@ -88,5 +88,11 @@ int sssm_files_id_init(TALLOC_CTX *mem_ctx, + ctx, struct files_id_ctx, + struct dp_id_data, struct dp_reply_std); + ++ dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER, ++ default_account_domain_send, ++ default_account_domain_recv, ++ NULL, void, ++ struct dp_get_acct_domain_data, struct dp_reply_std); ++ + return EOK; + } +diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c +index f335d51fd65959d256c54a5d92c594a24e895b7c..754e5315c3a7f84ac2901986ecdda73e4dad26bc 100644 +--- a/src/providers/ipa/ipa_init.c ++++ b/src/providers/ipa/ipa_init.c +@@ -754,6 +754,10 @@ errno_t sssm_ipa_id_init(TALLOC_CTX *mem_ctx, + sdap_online_check_handler_send, sdap_online_check_handler_recv, id_ctx->sdap_id_ctx, + struct sdap_id_ctx, void, struct dp_reply_std); + ++ dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER, ++ default_account_domain_send, default_account_domain_recv, NULL, ++ void, struct dp_get_acct_domain_data, struct dp_reply_std); ++ + return EOK; + } + +diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c +index 43d905893081c31ed659fd1ef8343f965bdc5af0..c0ede8941ee8480c2ec4765f89d12e903edcf012 100644 +--- a/src/providers/ldap/ldap_init.c ++++ b/src/providers/ldap/ldap_init.c +@@ -531,6 +531,10 @@ errno_t sssm_ldap_id_init(TALLOC_CTX *mem_ctx, + sdap_online_check_handler_send, sdap_online_check_handler_recv, id_ctx, + struct sdap_id_ctx, void, struct dp_reply_std); + ++ dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER, ++ default_account_domain_send, default_account_domain_recv, NULL, ++ void, struct dp_get_acct_domain_data, struct dp_reply_std); ++ + return EOK; + } + +diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c +index 7c9d3dafbdf1f9448cc8f8b473aea15cf4206afc..7d997cb16ee62f10f4b86c9c3ab373a48676fe75 100644 +--- a/src/providers/proxy/proxy_init.c ++++ b/src/providers/proxy/proxy_init.c +@@ -351,6 +351,10 @@ errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx, + proxy_account_info_handler_send, proxy_account_info_handler_recv, ctx, + struct proxy_id_ctx, struct dp_id_data, struct dp_reply_std); + ++ dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER, ++ default_account_domain_send, default_account_domain_recv, NULL, ++ void, struct dp_get_acct_domain_data, struct dp_reply_std); ++ + ret = EOK; + + done: +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 5a92a2dcf6e65f93bc9732cebf562756357123b6..9a9ba3f3063cab4afb538c3a58527a2d2ed3fffd 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -115,6 +115,7 @@ struct err_string error_to_str[] = { + { "Unable to initialize SSL" }, /* ERR_SSL_FAILURE */ + { "Unable to verify peer" }, /* ERR_UNABLE_TO_VERIFY_PEER */ + { "Unable to resolve host" }, /* ERR_UNABLE_TO_RESOLVE_HOST */ ++ { "GetAccountDomain() not supported" }, /* ERR_GET_ACCT_DOM_NOT_SUPPORTED */ + { "ERR_LAST" } /* ERR_LAST */ + }; + +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index 509ccb805fb97e59f9da0ea2f991ece2f2030ca4..5ee9862c3f2f60c078693b1b85a40f15436e818c 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -137,6 +137,7 @@ enum sssd_errors { + ERR_SSL_FAILURE, + ERR_UNABLE_TO_VERIFY_PEER, + ERR_UNABLE_TO_RESOLVE_HOST, ++ ERR_GET_ACCT_DOM_NOT_SUPPORTED, + ERR_LAST /* ALWAYS LAST */ + }; + +-- +2.14.3 + diff --git a/SOURCES/0073-KCM-Fix-off-by-one-error-in-secrets-key-parsing.patch b/SOURCES/0073-KCM-Fix-off-by-one-error-in-secrets-key-parsing.patch deleted file mode 100644 index 0530278..0000000 --- a/SOURCES/0073-KCM-Fix-off-by-one-error-in-secrets-key-parsing.patch +++ /dev/null @@ -1,211 +0,0 @@ -From 088be07a9e5aae54379a7f98e9e4615cd4451501 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 29 Mar 2017 22:49:09 +0200 -Subject: [PATCH 73/90] KCM: Fix off-by-one error in secrets key parsing -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When parsing the secrets key, the code tried to protect against malformed keys -or keys that are too short, but it did an error - the UUID stringified -form is 36 bytes long, so the UUID_STR_SIZE is 37 because UUID_STR_SIZE -accounts for the null terminator. - -But the code, that was trying to assert that there are two characters after -the UUID string (separator and at least a single character for the name) -didn't take the NULL terminator (which strlen() doesn't return) into -account and ended up rejecting all ccaches whose name is only a single -character. - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 7d73049884e3a96ca3b00b5bd4104f4edd6287ab) ---- - src/responder/kcm/kcmsrv_ccache_json.c | 43 +++++++++------- - src/tests/cmocka/test_kcm_json_marshalling.c | 75 ++++++++++++++++++++++++++++ - 2 files changed, 101 insertions(+), 17 deletions(-) - -diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c -index 40b64861c209206d6f60ccd0843857edee24a844..8199bc613e4204859438e1cd820f3f4b2123dd7e 100644 ---- a/src/responder/kcm/kcmsrv_ccache_json.c -+++ b/src/responder/kcm/kcmsrv_ccache_json.c -@@ -109,6 +109,28 @@ static const char *sec_key_create(TALLOC_CTX *mem_ctx, - "%s%c%s", uuid_str, SEC_KEY_SEPARATOR, name); - } - -+static bool sec_key_valid(const char *sec_key) -+{ -+ if (sec_key == NULL) { -+ return false; -+ } -+ -+ if (strlen(sec_key) < UUID_STR_SIZE + 1) { -+ /* One char for separator (at UUID_STR_SIZE, because strlen doesn't -+ * include the '\0', but UUID_STR_SIZE does) and at least one for -+ * the name */ -+ DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); -+ return false; -+ } -+ -+ if (sec_key[UUID_STR_SIZE - 1] != SEC_KEY_SEPARATOR) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n"); -+ return false; -+ } -+ -+ return true; -+} -+ - static errno_t sec_key_parse(TALLOC_CTX *mem_ctx, - const char *sec_key, - const char **_name, -@@ -116,9 +138,7 @@ static errno_t sec_key_parse(TALLOC_CTX *mem_ctx, - { - char uuid_str[UUID_STR_SIZE]; - -- if (strlen(sec_key) < UUID_STR_SIZE + 2) { -- /* One char for separator and at least one for the name */ -- DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); -+ if (!sec_key_valid(sec_key)) { - return EINVAL; - } - -@@ -143,14 +163,7 @@ errno_t sec_key_get_uuid(const char *sec_key, - { - char uuid_str[UUID_STR_SIZE]; - -- if (strlen(sec_key) < UUID_STR_SIZE + 2) { -- /* One char for separator and at least one for the name */ -- DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); -- return EINVAL; -- } -- -- if (sec_key[UUID_STR_SIZE-1] != SEC_KEY_SEPARATOR) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n"); -+ if (!sec_key_valid(sec_key)) { - return EINVAL; - } - -@@ -162,9 +175,7 @@ errno_t sec_key_get_uuid(const char *sec_key, - - const char *sec_key_get_name(const char *sec_key) - { -- if (strlen(sec_key) < UUID_STR_SIZE + 2) { -- /* One char for separator and at least one for the name */ -- DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); -+ if (!sec_key_valid(sec_key)) { - return NULL; - } - -@@ -174,9 +185,7 @@ const char *sec_key_get_name(const char *sec_key) - bool sec_key_match_name(const char *sec_key, - const char *name) - { -- if (strlen(sec_key) < UUID_STR_SIZE + 2) { -- /* One char for separator and at least one for the name */ -- DEBUG(SSSDBG_MINOR_FAILURE, "Key %s is too short\n", sec_key); -+ if (!sec_key_valid(sec_key) || name == NULL) { - return false; - } - -diff --git a/src/tests/cmocka/test_kcm_json_marshalling.c b/src/tests/cmocka/test_kcm_json_marshalling.c -index 8eff2f501066c70a8730cd3d4dc41b92d7a03e4c..108eaf55628029a6de8c23cd6486bdccc42c0364 100644 ---- a/src/tests/cmocka/test_kcm_json_marshalling.c -+++ b/src/tests/cmocka/test_kcm_json_marshalling.c -@@ -32,6 +32,12 @@ - - #define TEST_CREDS "TESTCREDS" - -+#define TEST_UUID_STR "5f8f296b-02be-4e86-9235-500e82354186" -+#define TEST_SEC_KEY_ONEDIGIT TEST_UUID_STR"-0" -+#define TEST_SEC_KEY_MULTIDIGITS TEST_UUID_STR"-123456" -+ -+#define TEST_SEC_KEY_NOSEP TEST_UUID_STR"+0" -+ - const struct kcm_ccdb_ops ccdb_mem_ops; - const struct kcm_ccdb_ops ccdb_sec_ops; - -@@ -188,6 +194,72 @@ static void test_kcm_ccache_marshall_unmarshall(void **state) - assert_int_equal(ret, EOK); - - assert_cc_equal(cc, cc2); -+ -+ /* This key is exactly one byte shorter than it should be */ -+ ret = sec_kv_to_ccache(test_ctx, -+ TEST_UUID_STR"-", -+ (const char *) data, -+ &owner, -+ &cc2); -+ assert_int_equal(ret, EINVAL); -+} -+ -+void test_sec_key_get_uuid(void **state) -+{ -+ errno_t ret; -+ uuid_t uuid; -+ char str_uuid[UUID_STR_SIZE]; -+ -+ uuid_clear(uuid); -+ ret = sec_key_get_uuid(TEST_SEC_KEY_ONEDIGIT, uuid); -+ assert_int_equal(ret, EOK); -+ uuid_unparse(uuid, str_uuid); -+ assert_string_equal(TEST_UUID_STR, str_uuid); -+ -+ ret = sec_key_get_uuid(TEST_SEC_KEY_NOSEP, uuid); -+ assert_int_equal(ret, EINVAL); -+ -+ ret = sec_key_get_uuid(TEST_UUID_STR, uuid); -+ assert_int_equal(ret, EINVAL); -+ -+ ret = sec_key_get_uuid(NULL, uuid); -+ assert_int_equal(ret, EINVAL); -+} -+ -+void test_sec_key_get_name(void **state) -+{ -+ const char *name; -+ -+ name = sec_key_get_name(TEST_SEC_KEY_ONEDIGIT); -+ assert_non_null(name); -+ assert_string_equal(name, "0"); -+ -+ name = sec_key_get_name(TEST_SEC_KEY_MULTIDIGITS); -+ assert_non_null(name); -+ assert_string_equal(name, "123456"); -+ -+ name = sec_key_get_name(TEST_UUID_STR); -+ assert_null(name); -+ -+ name = sec_key_get_name(TEST_SEC_KEY_NOSEP); -+ assert_null(name); -+ -+ name = sec_key_get_name(NULL); -+ assert_null(name); -+} -+ -+void test_sec_key_match_name(void **state) -+{ -+ assert_true(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, "0")); -+ assert_true(sec_key_match_name(TEST_SEC_KEY_MULTIDIGITS, "123456")); -+ -+ assert_false(sec_key_match_name(TEST_SEC_KEY_MULTIDIGITS, "0")); -+ assert_false(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, "123456")); -+ -+ assert_false(sec_key_match_name(TEST_UUID_STR, "0")); -+ assert_false(sec_key_match_name(TEST_SEC_KEY_NOSEP, "0")); -+ assert_false(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, NULL)); -+ assert_false(sec_key_match_name(NULL, "0")); - } - - int main(int argc, const char *argv[]) -@@ -205,6 +277,9 @@ int main(int argc, const char *argv[]) - cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall, - setup_kcm_marshalling, - teardown_kcm_marshalling), -+ cmocka_unit_test(test_sec_key_get_uuid), -+ cmocka_unit_test(test_sec_key_get_name), -+ cmocka_unit_test(test_sec_key_match_name), - }; - - /* Set debug level to invalid value so we can deside if -d 0 was used. */ --- -2.9.3 - diff --git a/SOURCES/0074-AD-Implement-a-real-getAccountDomain-handler-for-the.patch b/SOURCES/0074-AD-Implement-a-real-getAccountDomain-handler-for-the.patch new file mode 100644 index 0000000..980917f --- /dev/null +++ b/SOURCES/0074-AD-Implement-a-real-getAccountDomain-handler-for-the.patch @@ -0,0 +1,553 @@ +From 427a1f162e0ceb97e4e9491f81048646bd144910 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 7 Nov 2017 17:01:34 +0100 +Subject: [PATCH 74/83] AD: Implement a real getAccountDomain handler for the + AD provider +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +After this patch, the AD provider drops the default getAccountDomain +handler in favor of the handler added in this patch. + +The handler first checks if the domain is eligible for locating +the domain of an ID with the help of the Global Catalog at all, which +only happens if: + - the Global Catalog is enabled + - POSIX IDs are used, not ID-mapping + - the Global catalog contains some POSIX IDs + +If all these hold true, then the Global Catalog is searched with +an empty search base, which searches the whole GC. If a single entry +is returned, its original DN is converted to a domain name and returned. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit 095844d6b48aef483c33e5a369a405ae686e044d) +--- + src/providers/ad/ad_id.c | 469 +++++++++++++++++++++++++++++++++++++++++++++ + src/providers/ad/ad_id.h | 10 + + src/providers/ad/ad_init.c | 4 +- + 3 files changed, 481 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index e14ada386f16851a65097952c85e57b7acda14aa..0b8f49819405c7dbbfa18b5359f7743441dc65e5 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -27,6 +27,7 @@ + #include "providers/ad/ad_pac.h" + #include "providers/ldap/sdap_async_enum.h" + #include "providers/ldap/sdap_idmap.h" ++#include "providers/ldap/sdap_async.h" + + static void + disable_gc(struct ad_options *ad_options) +@@ -1076,3 +1077,471 @@ ad_enumeration_recv(struct tevent_req *req) + return EOK; + } + ++static errno_t ad_get_account_domain_prepare_search(struct tevent_req *req); ++static errno_t ad_get_account_domain_connect_retry(struct tevent_req *req); ++static void ad_get_account_domain_connect_done(struct tevent_req *subreq); ++static void ad_get_account_domain_posix_check_done(struct tevent_req *subreq); ++static void ad_get_account_domain_search(struct tevent_req *req); ++static void ad_get_account_domain_search_done(struct tevent_req *subreq); ++static void ad_get_account_domain_evaluate(struct tevent_req *req); ++ ++struct ad_get_account_domain_state { ++ struct tevent_context *ev; ++ struct ad_id_ctx *id_ctx; ++ struct sdap_id_ctx *sdap_id_ctx; ++ struct sdap_domain *sdom; ++ uint32_t entry_type; ++ uint32_t filter_type; ++ char *clean_filter; ++ ++ bool twopass; ++ ++ struct sdap_search_base **search_bases; ++ size_t base_iter; ++ const char *base_filter; ++ char *filter; ++ const char **attrs; ++ int dp_error; ++ struct dp_reply_std reply; ++ struct sdap_id_op *op; ++ struct sysdb_attrs **objects; ++ size_t count; ++ ++ const char *found_domain_name; ++}; ++ ++struct tevent_req * ++ad_get_account_domain_send(TALLOC_CTX *mem_ctx, ++ struct ad_id_ctx *id_ctx, ++ struct dp_get_acct_domain_data *data, ++ struct dp_req_params *params) ++{ ++ struct ad_get_account_domain_state *state; ++ struct tevent_req *req; ++ errno_t ret; ++ bool use_id_mapping; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ad_get_account_domain_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ state->ev = params->ev; ++ state->id_ctx = id_ctx; ++ state->sdap_id_ctx = id_ctx->sdap_id_ctx; ++ state->entry_type = data->entry_type & BE_REQ_TYPE_MASK; ++ state->filter_type = data->filter_type; ++ state->attrs = talloc_array(state, const char *, 2); ++ if (state->attrs == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ state->attrs[0] = "objectclass"; ++ state->attrs[1] = NULL; ++ ++ if (params->be_ctx->domain->mpg == true ++ || state->entry_type == BE_REQ_USER_AND_GROUP) { ++ state->twopass = true; ++ if (state->entry_type == BE_REQ_USER_AND_GROUP) { ++ state->entry_type = BE_REQ_GROUP; ++ } ++ } ++ ++ /* The get-account-domain request only works with GC */ ++ if (dp_opt_get_bool(id_ctx->ad_options->basic, AD_ENABLE_GC) == false) { ++ DEBUG(SSSDBG_CONF_SETTINGS, ++ "Global catalog support is not enabled, " ++ "cannot locate the account domain\n"); ++ ret = ERR_GET_ACCT_DOM_NOT_SUPPORTED; ++ goto immediately; ++ } ++ ++ state->sdom = sdap_domain_get(id_ctx->sdap_id_ctx->opts, ++ params->be_ctx->domain); ++ if (state->sdom == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find sdap_domain\n"); ++ ret = EIO; ++ goto immediately; ++ } ++ ++ /* Currently we only support locating the account domain ++ * if ID mapping is disabled. With ID mapping enabled, we can ++ * already shortcut the 'real' ID request ++ */ ++ use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( ++ state->sdap_id_ctx->opts->idmap_ctx, ++ state->sdom->dom->name, ++ state->sdom->dom->domain_id); ++ if (use_id_mapping == true) { ++ DEBUG(SSSDBG_CONF_SETTINGS, ++ "No point in locating domain with GC if ID-mapping " ++ "is enabled\n"); ++ ret = ERR_GET_ACCT_DOM_NOT_SUPPORTED; ++ goto immediately; ++ } ++ ++ ret = sss_filter_sanitize(state, data->filter_value, &state->clean_filter); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot sanitize filter [%d]: %s\n", ret, sss_strerror(ret)); ++ goto immediately; ++ } ++ ++ ret = ad_get_account_domain_prepare_search(req); ++ if (ret != EOK) { ++ goto immediately; ++ } ++ ++ /* FIXME - should gc_ctx always default to ignore_offline on creation ++ * time rather than setting the flag on first use? ++ */ ++ id_ctx->gc_ctx->ignore_mark_offline = true; ++ state->op = sdap_id_op_create(state, id_ctx->gc_ctx->conn_cache); ++ if (state->op == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n"); ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ ret = ad_get_account_domain_connect_retry(req); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Connection error"); ++ goto immediately; ++ } ++ ++ return req; ++ ++immediately: ++ dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL); ++ ++ /* TODO For backward compatibility we always return EOK to DP now. */ ++ tevent_req_done(req); ++ tevent_req_post(req, params->ev); ++ ++ return req; ++} ++ ++static errno_t ad_get_account_domain_prepare_search(struct tevent_req *req) ++{ ++ struct ad_get_account_domain_state *state = tevent_req_data(req, ++ struct ad_get_account_domain_state); ++ const char *attr_name = NULL; ++ const char *objectclass = NULL; ++ ++ switch (state->entry_type) { ++ case BE_REQ_USER: ++ state->search_bases = state->sdom->user_search_bases; ++ attr_name = state->sdap_id_ctx->opts->user_map[SDAP_AT_USER_UID].name; ++ objectclass = state->sdap_id_ctx->opts->user_map[SDAP_OC_USER].name; ++ break; ++ case BE_REQ_GROUP: ++ state->search_bases = state->sdom->group_search_bases; ++ attr_name = state->sdap_id_ctx->opts->group_map[SDAP_AT_GROUP_GID].name; ++ objectclass = state->sdap_id_ctx->opts->group_map[SDAP_OC_GROUP].name; ++ break; ++ default: ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Unsupported request type %X\n", ++ state->entry_type & BE_REQ_TYPE_MASK); ++ return EINVAL; ++ } ++ ++ switch (state->filter_type) { ++ case BE_FILTER_IDNUM: ++ break; ++ default: ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Unsupported filter type %X\n", state->filter_type); ++ return EINVAL; ++ } ++ ++ talloc_zfree(state->base_filter); ++ state->base_filter = talloc_asprintf(state, ++ "(&(%s=%s)(objectclass=%s))", ++ attr_name, ++ state->clean_filter, ++ objectclass); ++ if (state->base_filter == NULL) { ++ return ENOMEM; ++ } ++ ++ return EOK; ++} ++ ++static errno_t ad_get_account_domain_connect_retry(struct tevent_req *req) ++{ ++ struct ad_get_account_domain_state *state = tevent_req_data(req, ++ struct ad_get_account_domain_state); ++ struct tevent_req *subreq; ++ errno_t ret; ++ ++ subreq = sdap_id_op_connect_send(state->op, state, &ret); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(subreq, ad_get_account_domain_connect_done, req); ++ return ret; ++} ++ ++static void ad_get_account_domain_connect_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ad_get_account_domain_state *state = tevent_req_data(req, ++ struct ad_get_account_domain_state); ++ int dp_error = DP_ERR_FATAL; ++ errno_t ret; ++ ++ ret = sdap_id_op_connect_recv(subreq, &dp_error); ++ talloc_zfree(subreq); ++ ++ if (ret != EOK) { ++ state->dp_error = dp_error; ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* If POSIX attributes have been requested with an AD server and we ++ * have no idea about POSIX attributes support, run a one-time check ++ */ ++ if (state->sdap_id_ctx->srv_opts && ++ state->sdap_id_ctx->srv_opts->posix_checked == false) { ++ subreq = sdap_gc_posix_check_send(state, ++ state->ev, ++ state->sdap_id_ctx->opts, ++ sdap_id_op_handle(state->op), ++ dp_opt_get_int( ++ state->sdap_id_ctx->opts->basic, ++ SDAP_SEARCH_TIMEOUT)); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, ad_get_account_domain_posix_check_done, req); ++ return; ++ } ++ ++ ad_get_account_domain_search(req); ++} ++ ++static void ad_get_account_domain_posix_check_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ad_get_account_domain_state *state = tevent_req_data(req, ++ struct ad_get_account_domain_state); ++ int dp_error = DP_ERR_FATAL; ++ bool has_posix; ++ errno_t ret; ++ errno_t ret2; ++ ++ ret = sdap_gc_posix_check_recv(subreq, &has_posix); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ /* We can only finish the id_op on error as the connection ++ * is re-used by the real search ++ */ ++ ret2 = sdap_id_op_done(state->op, ret, &dp_error); ++ if (dp_error == DP_ERR_OK && ret2 != EOK) { ++ /* retry */ ++ ret = ad_get_account_domain_connect_retry(req); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ } ++ return; ++ } ++ ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->sdap_id_ctx->srv_opts->posix_checked = true; ++ ++ /* ++ * If the GC has no POSIX attributes, there is nothing we can do. ++ * Return an error and let the responders disable the functionality ++ * from now on. ++ */ ++ if (has_posix == false) { ++ DEBUG(SSSDBG_CONF_SETTINGS, ++ "The Global Catalog has no POSIX attributes\n"); ++ ++ disable_gc(state->id_ctx->ad_options); ++ dp_reply_std_set(&state->reply, ++ DP_ERR_DECIDE, ERR_GET_ACCT_DOM_NOT_SUPPORTED, ++ NULL); ++ tevent_req_done(req); ++ return; ++ } ++ ++ ad_get_account_domain_search(req); ++} ++ ++static void ad_get_account_domain_search(struct tevent_req *req) ++{ ++ struct ad_get_account_domain_state *state = tevent_req_data(req, ++ struct ad_get_account_domain_state); ++ struct tevent_req *subreq; ++ ++ talloc_zfree(state->filter); ++ state->filter = sdap_combine_filters(state, state->base_filter, ++ state->search_bases[state->base_iter]->filter); ++ if (state->filter == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ subreq = sdap_get_generic_send(state, state->ev, state->sdap_id_ctx->opts, ++ sdap_id_op_handle(state->op), ++ "", ++ LDAP_SCOPE_SUBTREE, ++ state->filter, ++ state->attrs, NULL, 0, ++ dp_opt_get_int(state->sdap_id_ctx->opts->basic, ++ SDAP_SEARCH_TIMEOUT), ++ false); ++ ++ if (subreq == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n"); ++ tevent_req_error(req, EIO); ++ return; ++ } ++ ++ tevent_req_set_callback(subreq, ad_get_account_domain_search_done, req); ++} ++ ++static void ad_get_account_domain_search_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ad_get_account_domain_state *state = tevent_req_data(req, ++ struct ad_get_account_domain_state); ++ size_t count; ++ struct sysdb_attrs **objects; ++ errno_t ret; ++ ++ ret = sdap_get_generic_recv(subreq, state, ++ &count, &objects); ++ talloc_zfree(subreq); ++ if (ret) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Search returned %zu results.\n", count); ++ ++ if (count > 0) { ++ size_t copied; ++ ++ state->objects = ++ talloc_realloc(state, ++ state->objects, ++ struct sysdb_attrs *, ++ state->count + count + 1); ++ if (!state->objects) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ copied = sdap_steal_objects_in_dom(state->sdap_id_ctx->opts, ++ state->objects, ++ state->count, ++ NULL, ++ objects, count, ++ false); ++ ++ state->count += copied; ++ state->objects[state->count] = NULL; ++ } ++ ++ /* Even though we search with an empty search base (=across all domains) ++ * the reason we iterate over search bases is that the search bases can ++ * also contain a filter which might restrict the IDs we find ++ */ ++ state->base_iter++; ++ if (state->search_bases[state->base_iter]) { ++ /* There are more search bases to try */ ++ ad_get_account_domain_search(req); ++ return; ++ } ++ ++ /* No more searches, evaluate results */ ++ ad_get_account_domain_evaluate(req); ++} ++ ++static void ad_get_account_domain_evaluate(struct tevent_req *req) ++{ ++ struct ad_get_account_domain_state *state = tevent_req_data(req, ++ struct ad_get_account_domain_state); ++ struct sss_domain_info *obj_dom; ++ errno_t ret; ++ ++ if (state->count == 0) { ++ if (state->twopass ++ && state->entry_type != BE_REQ_USER) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Retrying search\n"); ++ ++ state->entry_type = BE_REQ_USER; ++ state->base_iter = 0; ++ ret = ad_get_account_domain_prepare_search(req); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot retry search\n"); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ ad_get_account_domain_search(req); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Not found\n"); ++ dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ERR_NOT_FOUND, NULL); ++ tevent_req_done(req); ++ return; ++ } else if (state->count > 1) { ++ /* FIXME: If more than one entry was found, return error for now ++ * as the account requsts have no way of returning multiple ++ * messages back until we switch to the rdp_* requests ++ * from the responder side ++ */ ++ DEBUG(SSSDBG_OP_FAILURE, "Multiple entries found, error!\n"); ++ dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ERANGE, NULL); ++ tevent_req_done(req); ++ return; ++ } ++ ++ /* Exactly one entry was found */ ++ obj_dom = sdap_get_object_domain(state->sdap_id_ctx->opts, ++ state->objects[0], ++ state->sdom->dom); ++ if (obj_dom == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not match entry with domain!\n"); ++ dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ERR_NOT_FOUND, NULL); ++ tevent_req_done(req); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ "Found object in domain %s\n", obj_dom->name); ++ dp_reply_std_set(&state->reply, DP_ERR_DECIDE, EOK, obj_dom->name); ++ tevent_req_done(req); ++} ++ ++errno_t ad_get_account_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct dp_reply_std *data) ++{ ++ struct ad_get_account_domain_state *state = NULL; ++ ++ state = tevent_req_data(req, struct ad_get_account_domain_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *data = state->reply; ++ ++ return EOK; ++} +diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h +index 145fdc8f2dfdeda5a17b0ce5892a547da934c244..5154393c5f125f472c92155006aac14d04bbca1a 100644 +--- a/src/providers/ad/ad_id.h ++++ b/src/providers/ad/ad_id.h +@@ -54,4 +54,14 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx, + errno_t + ad_enumeration_recv(struct tevent_req *req); + ++struct tevent_req * ++ad_get_account_domain_send(TALLOC_CTX *mem_ctx, ++ struct ad_id_ctx *id_ctx, ++ struct dp_get_acct_domain_data *data, ++ struct dp_req_params *params); ++ ++errno_t ad_get_account_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct dp_reply_std *data); ++ + #endif /* AD_ID_H_ */ +diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c +index 7efb6aa71cbd2551422c87e0b0c5c1fe91390375..22a3ecf7e5a020da88b6c9164f5999d13a9aa5e3 100644 +--- a/src/providers/ad/ad_init.c ++++ b/src/providers/ad/ad_init.c +@@ -511,8 +511,8 @@ errno_t sssm_ad_id_init(TALLOC_CTX *mem_ctx, + struct sdap_id_ctx, void, struct dp_reply_std); + + dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER, +- default_account_domain_send, default_account_domain_recv, NULL, +- void, struct dp_get_acct_domain_data, struct dp_reply_std); ++ ad_get_account_domain_send, ad_get_account_domain_recv, id_ctx, ++ struct ad_id_ctx, struct dp_get_acct_domain_data, struct dp_reply_std); + + return EOK; + } +-- +2.14.3 + diff --git a/SOURCES/0074-tcurl-add-support-for-ssl-and-raw-output.patch b/SOURCES/0074-tcurl-add-support-for-ssl-and-raw-output.patch deleted file mode 100644 index 6351c10..0000000 --- a/SOURCES/0074-tcurl-add-support-for-ssl-and-raw-output.patch +++ /dev/null @@ -1,1478 +0,0 @@ -From 2ca9a394063baac075e05b14fcc6c027027ab8f9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Fri, 24 Feb 2017 10:40:43 +0100 -Subject: [PATCH 74/90] tcurl: add support for ssl and raw output - -At first, this patch separates curl_easy handle from the multi-handle -processing and makes it encapsulated in custom tcurl_request structure. -This allows us to separate protocol initialization from its asynchonous -logic which gives us the ability to set different options for each -request without over-extending the parameter list. - -In this patch we implement options for peer verification for TLS-enabled -protocols and to return response with body and headers together. - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit 300b9e9217ee1ed8d845ed2370c5ccf5c87afb36) ---- - src/tests/tcurl_test_tool.c | 41 +- - src/util/tev_curl.c | 992 +++++++++++++++++++++++++------------------- - src/util/tev_curl.h | 172 +++++++- - src/util/util_errors.c | 4 + - src/util/util_errors.h | 4 + - 5 files changed, 755 insertions(+), 458 deletions(-) - -diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c -index 2af950ebb76a22bdf4a6dfd58442b10486e64293..9a6266f89131ffd3a561e857af85df9854c44949 100644 ---- a/src/tests/tcurl_test_tool.c -+++ b/src/tests/tcurl_test_tool.c -@@ -42,9 +42,7 @@ static void request_done(struct tevent_req *req) - struct tool_ctx *tool_ctx = tevent_req_callback_data(req, - struct tool_ctx); - -- tool_ctx->error = tcurl_http_recv(tool_ctx, req, -- &http_code, -- &outbuf); -+ tool_ctx->error = tcurl_request_recv(tool_ctx, req, &outbuf, &http_code); - talloc_zfree(req); - - if (tool_ctx->error != EOK) { -@@ -87,16 +85,17 @@ int main(int argc, const char *argv[]) - "The path to the HTTP server socket", NULL }, - { "get", 'g', POPT_ARG_NONE, NULL, 'g', "Perform a HTTP GET (default)", NULL }, - { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, -- { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, - { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, -+ { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, - { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Print response code and body", NULL }, - POPT_TABLEEND - }; - - struct tevent_req *req; - struct tevent_context *ev; -- enum tcurl_http_request req_type = TCURL_HTTP_GET; -+ enum tcurl_http_method method = TCURL_HTTP_GET; - struct tcurl_ctx *ctx; -+ struct tcurl_request *tcurl_req; - struct tool_ctx *tool_ctx; - - const char *urls[MAXREQ] = { 0 }; -@@ -111,16 +110,16 @@ int main(int argc, const char *argv[]) - while ((opt = poptGetNextOpt(pc)) > 0) { - switch (opt) { - case 'g': -- req_type = TCURL_HTTP_GET; -+ method = TCURL_HTTP_GET; - break; - case 'p': -- req_type = TCURL_HTTP_PUT; -- break; -- case 'd': -- req_type = TCURL_HTTP_DELETE; -+ method = TCURL_HTTP_PUT; - break; - case 'o': -- req_type = TCURL_HTTP_POST; -+ method = TCURL_HTTP_POST; -+ break; -+ case 'd': -+ method = TCURL_HTTP_DELETE; - break; - case 'v': - pc_verbose = 1; -@@ -146,7 +145,7 @@ int main(int argc, const char *argv[]) - } - - while ((extra_arg_ptr = poptGetArg(pc)) != NULL) { -- switch (req_type) { -+ switch(method) { - case TCURL_HTTP_GET: - case TCURL_HTTP_DELETE: - case TCURL_HTTP_POST: -@@ -203,14 +202,16 @@ int main(int argc, const char *argv[]) - } - - for (size_t i = 0; i < n_reqs; i++) { -- req = tcurl_http_send(tool_ctx, ev, ctx, -- req_type, -- socket_path, -- urls[i], -- headers, -- inbufs[i], -- 5); -- if (req == NULL) { -+ tcurl_req = tcurl_http(tool_ctx, method, socket_path, -+ urls[i], headers, inbufs[i]); -+ if (tcurl_req == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to create TCURL request\n"); -+ talloc_zfree(tool_ctx); -+ return 1; -+ } -+ -+ req = tcurl_request_send(tool_ctx, ev, ctx, tcurl_req, 10); -+ if (ctx == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, "Could not create request\n"); - talloc_zfree(tool_ctx); - return 1; -diff --git a/src/util/tev_curl.c b/src/util/tev_curl.c -index 645d1182d10f825f209f48e0ba7e6804dde1971c..c155f4c038d4215933ee30d41c694ad4a14ae132 100644 ---- a/src/util/tev_curl.c -+++ b/src/util/tev_curl.c -@@ -34,8 +34,8 @@ - #include "util/util.h" - #include "util/tev_curl.h" - --#define IOBUF_CHUNK 1024 --#define IOBUF_MAX 4096 -+#define TCURL_IOBUF_CHUNK 1024 -+#define TCURL_IOBUF_MAX 4096 - - static bool global_is_curl_initialized; - -@@ -71,39 +71,12 @@ struct tcurl_sock { - struct tevent_fd *fde; /* tevent tracker of the fd events */ - }; - --/** -- * @brief A state of one curl transfer -- * -- * Intentionally breaking the tevent coding style here and making the struct available -- * in the whole module so that the structure is available to curl callbacks that -- * need to access the state of the transfer. -- * -- * @see handle_curlmsg_done() -- */ --struct tcurl_http_state { -- /* Input parameters */ -- struct tcurl_ctx *tctx; -- const char *socket_path; -- const char *url; -- int timeout; -- struct sss_iobuf *inbuf; -- -- /* Internal state */ -- CURL *http_handle; -- struct curl_slist *curl_headers; -- -- /* Output data */ -- struct sss_iobuf *outbuf; -- long http_code; --}; -+static void tcurl_request_done(struct tevent_req *req, -+ errno_t process_error, -+ int response_code); - - static errno_t curl_code2errno(CURLcode crv) - { -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "curl error %d: %s\n", crv, curl_easy_strerror(crv)); -- } -- - switch (crv) { - /* HTTP error does not fail the whole request, just returns the error - * separately -@@ -121,6 +94,47 @@ static errno_t curl_code2errno(CURLcode crv) - return ENOMEM; - case CURLE_OPERATION_TIMEDOUT: - return ETIMEDOUT; -+ case CURLE_SSL_ISSUER_ERROR: -+ case CURLE_SSL_CACERT_BADFILE: -+ case CURLE_SSL_CACERT: -+ case CURLE_SSL_CERTPROBLEM: -+ return ERR_INVALID_CERT; -+ -+ case CURLE_SSL_CRL_BADFILE: -+ case CURLE_SSL_SHUTDOWN_FAILED: -+ case CURLE_SSL_ENGINE_INITFAILED: -+ case CURLE_USE_SSL_FAILED: -+ case CURLE_SSL_CIPHER: -+ case CURLE_SSL_ENGINE_SETFAILED: -+ case CURLE_SSL_ENGINE_NOTFOUND: -+ case CURLE_SSL_CONNECT_ERROR: -+ return ERR_SSL_FAILURE; -+ case CURLE_PEER_FAILED_VERIFICATION: -+ return ERR_UNABLE_TO_VERIFY_PEER; -+ case CURLE_COULDNT_RESOLVE_HOST: -+ return ERR_UNABLE_TO_RESOLVE_HOST; -+ default: -+ break; -+ } -+ -+ return EIO; -+} -+ -+static errno_t curlm_code2errno(CURLcode crv) -+{ -+ switch (crv) { -+ case CURLM_OK: -+ return EOK; -+ case CURLM_BAD_SOCKET: -+ return EPIPE; -+ case CURLM_OUT_OF_MEMORY: -+ return ENOMEM; -+ case CURLM_BAD_HANDLE: -+ case CURLM_BAD_EASY_HANDLE: -+ case CURLM_UNKNOWN_OPTION: -+ return EINVAL; -+ case CURLM_INTERNAL_ERROR: -+ return ERR_INTERNAL; - default: - break; - } -@@ -145,22 +159,6 @@ static errno_t tcurl_global_init(void) - return EOK; - } - --static const char *http_req2str(enum tcurl_http_request req) --{ -- switch (req) { -- case TCURL_HTTP_GET: -- return "GET"; -- case TCURL_HTTP_PUT: -- return "PUT"; -- case TCURL_HTTP_DELETE: -- return "DELETE"; -- case TCURL_HTTP_POST: -- return "POST"; -- } -- -- return "Uknown request type"; --} -- - static int curl2tev_flags(int curlflags) - { - int flags = 0; -@@ -185,9 +183,9 @@ static void handle_curlmsg_done(CURLMsg *message) - CURL *easy_handle; - CURLcode crv; - struct tevent_req *req; -+ long response_code = 0; - char *done_url; - errno_t ret; -- struct tcurl_http_state *state; - - easy_handle = message->easy_handle; - if (easy_handle == NULL) { -@@ -198,9 +196,8 @@ static void handle_curlmsg_done(CURLMsg *message) - if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) { - crv = curl_easy_getinfo(easy_handle, CURLINFO_EFFECTIVE_URL, &done_url); - if (crv != CURLE_OK) { -- DEBUG(SSSDBG_MINOR_FAILURE, -- "Cannot get CURLINFO_EFFECTIVE_URL [%d]: %s\n", -- crv, curl_easy_strerror(crv)); -+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot get CURLINFO_EFFECTIVE_URL " -+ "[%d]: %s\n", crv, curl_easy_strerror(crv)); - /* not fatal since we need this only for debugging */ - } else { - DEBUG(SSSDBG_TRACE_FUNC, "Handled %s\n", done_url); -@@ -209,38 +206,32 @@ static void handle_curlmsg_done(CURLMsg *message) - - crv = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, (void *) &req); - if (crv != CURLE_OK) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Cannot get CURLINFO_PRIVATE [%d]: %s\n", -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get CURLINFO_PRIVATE [%d]: %s\n", - crv, curl_easy_strerror(crv)); -- return; -- } -- -- state = tevent_req_data(req, struct tcurl_http_state); -- if (state == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "BUG: request has no state\n"); -- tevent_req_error(req, EFAULT); -- return; -+ ret = curl_code2errno(crv); -+ goto done; - } - - ret = curl_code2errno(message->data.result); - if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "curl operation failed [%d]: %s\n", ret, sss_strerror(ret)); -- tevent_req_error(req, ret); -- return; -+ DEBUG(SSSDBG_OP_FAILURE, "CURL operation failed [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; - } - -- /* If there was no fatal error, let's read the HTTP error code and mark -- * the request as done -- */ -- crv = curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &state->http_code); -+ /* If there was no fatal error, let's read the response code -+ * and mark the request as done */ -+ crv = curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &response_code); - if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, "Cannot get HTTP status code\n"); -- tevent_req_error(req, EFAULT); -- return; -+ DEBUG(SSSDBG_OP_FAILURE, "Cannot get response code\n"); -+ ret = curl_code2errno(crv); -+ goto done; - } - -- tevent_req_done(req); -+ ret = EOK; -+ -+done: -+ tcurl_request_done(req, ret, response_code); - } - - static void process_curl_activity(struct tcurl_ctx *tctx) -@@ -551,346 +542,42 @@ fail: - return NULL; - } - --static errno_t tcurl_add_headers(struct tcurl_http_state *state, -- const char *headers[]); -- --static errno_t tcurl_set_options(struct tcurl_http_state *state, -- struct tevent_req *req, -- enum tcurl_http_request req_type); -- --static int tcurl_http_cleanup_handle(TALLOC_CTX *ptr); -- --static size_t tcurl_http_write_data(char *ptr, -- size_t size, -- size_t nmemb, -- void *userdata); -- --static size_t tcurl_http_read_data(void *ptr, -- size_t size, -- size_t nmemb, -- void *userdata); -- --struct tevent_req *tcurl_http_send(TALLOC_CTX *mem_ctx, -- struct tevent_context *ev, -- struct tcurl_ctx *tctx, -- enum tcurl_http_request req_type, -- const char *socket_path, -- const char *url, -- const char *headers[], -- struct sss_iobuf *req_data, -- int timeout) --{ -- errno_t ret; -- struct tevent_req *req; -- struct tcurl_http_state *state; -- -- req = tevent_req_create(mem_ctx, &state, struct tcurl_http_state); -- if (req == NULL) { -- return NULL; -- } -- -- state->tctx = tctx; -- state->socket_path = socket_path; -- state->url = url; -- state->inbuf = req_data; -- state->timeout = timeout; -- -- state->outbuf = sss_iobuf_init_empty(state, IOBUF_CHUNK, IOBUF_MAX); -- if (state->outbuf == NULL) { -- ret = ENOMEM; -- goto fail; -- } -- -- DEBUG(SSSDBG_TRACE_FUNC, -- "HTTP request %s for URL %s\n", http_req2str(req_type), url); -- talloc_set_destructor((TALLOC_CTX *) state, tcurl_http_cleanup_handle); -- -- /* All transfer share the same multi handle, but each trasfer has its own -- * easy handle we can use to set per-transfer options -- */ -- state->http_handle = curl_easy_init(); -- if (state->http_handle == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "curl_easy_init failed\n"); -- ret = EIO; -- goto fail; -- } -- -- ret = tcurl_add_headers(state, headers); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Failed to set CURL headers [%d]: %s\n", ret, sss_strerror(ret)); -- goto fail; -- } -- -- ret = tcurl_set_options(state, req, req_type); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Failed to set CURL options [%d]: %s\n", ret, sss_strerror(ret)); -- goto fail; -- } -- -- /* Pass control to the curl handling which will mark the request as -- * done -- */ -- curl_multi_add_handle(tctx->multi_handle, state->http_handle); -- -- return req; -- --fail: -- tevent_req_error(req, ret); -- tevent_req_post(req, ev); -- return req; --} -- --static int tcurl_http_cleanup_handle(TALLOC_CTX *ptr) --{ -- struct tcurl_http_state *state = talloc_get_type(ptr, struct tcurl_http_state); -- -- if (state == NULL) { -- return 0; -- } -- -- /* it is safe to pass NULL here */ -- curl_multi_remove_handle(state->tctx->multi_handle, state->http_handle); -- curl_slist_free_all(state->curl_headers); -- curl_easy_cleanup(state->http_handle); -- return 0; --} -- --static errno_t tcurl_add_headers(struct tcurl_http_state *state, -- const char *headers[]) --{ -- if (headers == NULL) { -- return EOK; -- } -- -- /* The headers will be freed later in tcurl_http_cleanup_handle */ -- for (int i = 0; headers[i] != NULL; i++) { -- state->curl_headers = curl_slist_append(state->curl_headers, headers[i]); -- if (state->curl_headers == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add header %s\n", headers[i]); -- return ENOMEM; -- } -- } -- -- /* Add a dummy header to suppress libcurl adding Expect 100-continue which -- * was causing libcurl to always wait for the internal timeout when sending -- * a PUT/PATCH request -- */ -- state->curl_headers = curl_slist_append(state->curl_headers, "Expect:"); -- if (state->curl_headers == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add the dummy expect header\n"); -- return ENOMEM; -- } -- -- return EOK; --} -- --static errno_t tcurl_set_common_options(struct tcurl_http_state *state, -- struct tevent_req *req) --{ -- CURLcode crv; -- -- crv = curl_easy_setopt(state->http_handle, -- CURLOPT_HTTPHEADER, -- state->curl_headers); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set HTTP headers [%d]: %s\n", -- crv, curl_easy_strerror(crv)); -- return EIO; -- } -- -- crv = curl_easy_setopt(state->http_handle, -- CURLOPT_UNIX_SOCKET_PATH, -- state->socket_path); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set UNIX socket path %s [%d]: %s\n", -- state->socket_path, crv, curl_easy_strerror(crv)); -- return EIO; -- } -- -- crv = curl_easy_setopt(state->http_handle, CURLOPT_URL, state->url); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set URL %s [%d]: %s\n", -- state->url, crv, curl_easy_strerror(crv)); -- return EIO; -- } -- -- crv = curl_easy_setopt(state->http_handle, CURLOPT_PRIVATE, req); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set private data [%d]: %s\n", -- crv, curl_easy_strerror(crv)); -- return EIO; -- } -- -- if (state->timeout > 0) { -- crv = curl_easy_setopt(state->http_handle, -- CURLOPT_TIMEOUT, -- state->timeout); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set timeout [%d]: %s\n", -- crv, curl_easy_strerror(crv)); -- return EIO; -- } -- } -- -- return EOK; --} -- --static errno_t tcurl_set_write_options(struct tcurl_http_state *state) --{ -- CURLcode crv; -- -- crv = curl_easy_setopt(state->http_handle, -- CURLOPT_WRITEFUNCTION, -- tcurl_http_write_data); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set write function [%d]: %s\n", -- crv, curl_easy_strerror(crv)); -- return EIO; -- } -- -- crv = curl_easy_setopt(state->http_handle, -- CURLOPT_WRITEDATA, -- state->outbuf); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set write data [%d]: %s\n", -- crv, curl_easy_strerror(crv)); -- return EIO; -- } -- -- return EOK; --} -- --static errno_t tcurl_set_read_options(struct tcurl_http_state *state) --{ -- CURLcode crv; -- -- crv = curl_easy_setopt(state->http_handle, -- CURLOPT_READFUNCTION, -- tcurl_http_read_data); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set read function [%d]: %s\n", -- crv, curl_easy_strerror(crv)); -- return EIO; -- } -- -- crv = curl_easy_setopt(state->http_handle, -- CURLOPT_READDATA, -- state->inbuf); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set read data [%d]: %s\n", -- crv, curl_easy_strerror(crv)); -- return EIO; -- } -- -- return EOK; --} -- --static errno_t tcurl_set_options(struct tcurl_http_state *state, -- struct tevent_req *req, -- enum tcurl_http_request req_type) --{ -- CURLcode crv; -- errno_t ret; -- -- ret = tcurl_set_common_options(state, req); -- if (ret != EOK) { -- return ret; -- } -- -- ret = tcurl_set_write_options(state); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Failed to set write callbacks [%d]: %s\n", -- ret, sss_strerror(ret)); -- return ret; -- } -- -- switch (req_type) { -- case TCURL_HTTP_POST: -- crv = curl_easy_setopt(state->http_handle, -- CURLOPT_CUSTOMREQUEST, -- "POST"); -- break; -- case TCURL_HTTP_PUT: -- /* CURLOPT_UPLOAD enables HTTP_PUT */ -- crv = curl_easy_setopt(state->http_handle, -- CURLOPT_UPLOAD, -- 1L); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set the uplodad option [%d]: %s\n", -- crv, curl_easy_strerror(crv)); -- return EIO; -- } -- -- /* Causes libcurl to add a sane Content-Length header */ -- crv = curl_easy_setopt(state->http_handle, -- CURLOPT_INFILESIZE_LARGE, -- (curl_off_t) sss_iobuf_get_size(state->inbuf)); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set CURLOPT_INFILESIZE_LARGE [%d]: %s\n", -- crv, curl_easy_strerror(crv)); -- return EIO; -- } -- -- ret = tcurl_set_read_options(state); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Failed to set write callbacks [%d]: %s\n", -- ret, sss_strerror(ret)); -- return ret; -- } -- break; -- case TCURL_HTTP_GET: -- /* GET just needs the write callbacks, nothing to do here.. */ -- break; -- case TCURL_HTTP_DELETE: -- crv = curl_easy_setopt(state->http_handle, -- CURLOPT_CUSTOMREQUEST, -- "DELETE"); -- if (crv != CURLE_OK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Failed to set the uplodad option [%d]: %s\n", -- crv, curl_easy_strerror(crv)); -- return EIO; -- } -- break; -- default: -- return EFAULT; -- } -- -- return EOK; --} -- --static size_t tcurl_http_write_data(char *ptr, -- size_t size, -- size_t nmemb, -- void *userdata) -+#define tcurl_set_option(tcurl_req, option, value) \ -+({ \ -+ CURLcode __curl_code; \ -+ errno_t __ret; \ -+ \ -+ __curl_code = curl_easy_setopt((tcurl_req)->curl_easy_handle, \ -+ (option), (value)); \ -+ if (__curl_code == CURLE_OK) { \ -+ __ret = EOK; \ -+ } else { \ -+ DEBUG(SSSDBG_OP_FAILURE, "Failed to set CURL option %s [%d]: %s\n", \ -+ #option, __curl_code, curl_easy_strerror(__curl_code)); \ -+ __ret = curl_code2errno(__curl_code); \ -+ } \ -+ __ret; \ -+}) -+ -+static size_t tcurl_write_data(char *ptr, -+ size_t size, -+ size_t nmemb, -+ void *userdata) - { - errno_t ret; - size_t realsize = size * nmemb; -- struct sss_iobuf *outbuf = talloc_get_type(userdata, struct sss_iobuf); -+ struct sss_iobuf *outbuf; -+ -+ outbuf = talloc_get_type(userdata, struct sss_iobuf); - - DEBUG(SSSDBG_TRACE_INTERNAL, "---> begin libcurl data\n"); - DEBUG(SSSDBG_TRACE_INTERNAL, "%s\n", ptr); - DEBUG(SSSDBG_TRACE_INTERNAL, "<--- end libcurl data\n"); - -- ret = sss_iobuf_write_len(outbuf, (uint8_t *) ptr, realsize); -+ ret = sss_iobuf_write_len(outbuf, (uint8_t *)ptr, realsize); - if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Failed to write data to buffer [%d]: %s\n", ret, sss_strerror(ret)); -+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to write data to buffer [%d]: %s\n", -+ ret, sss_strerror(ret)); - /* zero signifies an EOF */ - return 0; - } -@@ -898,14 +585,16 @@ static size_t tcurl_http_write_data(char *ptr, - return realsize; - } - --static size_t tcurl_http_read_data(void *ptr, -- size_t size, -- size_t nmemb, -- void *userdata) -+static size_t tcurl_read_data(void *ptr, -+ size_t size, -+ size_t nmemb, -+ void *userdata) - { - errno_t ret; - size_t readbytes; -- struct sss_iobuf *inbuf = (struct sss_iobuf *) userdata; -+ struct sss_iobuf *inbuf; -+ -+ inbuf = talloc_get_type(userdata, struct sss_iobuf); - - if (inbuf == NULL) { - return CURL_READFUNC_ABORT; -@@ -919,22 +608,487 @@ static size_t tcurl_http_read_data(void *ptr, - return readbytes; - } - --int tcurl_http_recv(TALLOC_CTX *mem_ctx, -- struct tevent_req *req, -- int *_http_code, -- struct sss_iobuf **_outbuf) -+ -+struct tcurl_request { -+ CURL *curl_easy_handle; -+ -+ struct sss_iobuf *body; -+ struct curl_slist *headers; -+ -+ const char *url; -+ const char *socket; -+ -+ /* Associated tcurl context if this request is in progress. */ -+ struct tcurl_ctx *tcurl_ctx; -+}; -+ -+struct tcurl_request_state { -+ struct tcurl_request *tcurl_req; -+ struct sss_iobuf *response; -+ int response_code; -+}; -+ -+struct tevent_req * -+tcurl_request_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct tcurl_ctx *tcurl_ctx, -+ struct tcurl_request *tcurl_req, -+ long int timeout) - { -- struct tcurl_http_state *state = tevent_req_data(req, struct tcurl_http_state); -+ struct tcurl_request_state *state; -+ struct tevent_req *req; -+ CURLMcode curl_code; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct tcurl_request_state); -+ if (req == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); -+ return NULL; -+ } -+ -+ DEBUG(SSSDBG_TRACE_FUNC, "Sending TCURL request for %s, at socket %s\n", -+ tcurl_req->url == NULL ? "" : tcurl_req->url, -+ tcurl_req->socket == NULL ? "" : tcurl_req->socket); -+ -+ state->tcurl_req = talloc_steal(state, tcurl_req); -+ -+ state->response = sss_iobuf_init_empty(state, TCURL_IOBUF_CHUNK, TCURL_IOBUF_MAX); -+ if (state->response == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_PRIVATE, req); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_TIMEOUT, timeout); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_WRITEFUNCTION, tcurl_write_data); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_WRITEDATA, state->response); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ if (tcurl_req->body != NULL) { -+ ret = tcurl_set_option(tcurl_req, CURLOPT_READFUNCTION, tcurl_read_data); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_READDATA, tcurl_req->body); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ -+ curl_code = curl_multi_add_handle(tcurl_ctx->multi_handle, -+ tcurl_req->curl_easy_handle); -+ if (curl_code != CURLM_OK) { -+ ret = curlm_code2errno(curl_code); -+ goto done; -+ } -+ -+ tcurl_req->tcurl_ctx = tcurl_ctx; -+ -+ ret = EAGAIN; -+ -+done: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ tevent_req_post(req, ev); -+ } else if (ret != EAGAIN) { -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ } -+ -+ return req; -+} -+ -+static void tcurl_request_done(struct tevent_req *req, -+ errno_t process_error, -+ int response_code) -+{ -+ struct tcurl_request_state *state; -+ -+ DEBUG(SSSDBG_TRACE_FUNC, "TCURL request finished [%d]: %s\n", -+ process_error, sss_strerror(process_error)); -+ -+ if (req == NULL) { -+ /* To handle case where we fail to obtain request from private data. */ -+ DEBUG(SSSDBG_MINOR_FAILURE, "No tevent request provided!\n"); -+ return; -+ } -+ -+ state = tevent_req_data(req, struct tcurl_request_state); -+ -+ curl_multi_remove_handle(state->tcurl_req->tcurl_ctx->multi_handle, -+ state->tcurl_req->curl_easy_handle); -+ -+ /* This request is no longer associated with tcurl context. */ -+ state->tcurl_req->tcurl_ctx = NULL; -+ -+ if (process_error != EOK) { -+ tevent_req_error(req, process_error); -+ return; -+ } -+ -+ state->response_code = response_code; -+ -+ tevent_req_done(req); -+ return; -+} -+ -+errno_t tcurl_request_recv(TALLOC_CTX *mem_ctx, -+ struct tevent_req *req, -+ struct sss_iobuf **_response, -+ int *_response_code) -+{ -+ struct tcurl_request_state *state; -+ state = tevent_req_data(req, struct tcurl_request_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - -- if (_http_code != NULL) { -- *_http_code = state->http_code; -+ if (_response != NULL) { -+ *_response = talloc_steal(mem_ctx, state->response); - } - -- if (_outbuf != NULL) { -- *_outbuf = talloc_steal(mem_ctx, state->outbuf); -+ if (_response_code != NULL) { -+ *_response_code = state->response_code; -+ } -+ -+ return EOK; -+} -+ -+static struct curl_slist * -+tcurl_add_header(struct curl_slist *slist, const char *header) -+{ -+ struct curl_slist *new; -+ -+ new = curl_slist_append(slist, header); -+ if (new == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add header %s\n", header); -+ if (slist != NULL) { -+ curl_slist_free_all(slist); -+ } -+ -+ return NULL; -+ } -+ -+ return new; -+} -+ -+static errno_t -+tcurl_construct_headers(const char **headers, -+ struct curl_slist **_slist) -+{ -+ struct curl_slist *slist = NULL; -+ int i; -+ -+ if (headers == NULL || headers[0] == NULL) { -+ *_slist = NULL; -+ return EOK; -+ } -+ -+ for (i = 0; headers[i] != NULL; i++) { -+ slist = tcurl_add_header(slist, headers[i]); -+ if (slist == NULL) { -+ return ENOMEM; -+ } -+ } -+ -+ /* Add a dummy header to suppress libcurl adding Expect 100-continue which -+ * was causing libcurl to always wait for the internal timeout when sending -+ * a PUT/POST request because secrets responder does not implement this. -+ */ -+ slist = tcurl_add_header(slist, "Expect: "); -+ if (slist == NULL) { -+ return ENOMEM; -+ } -+ -+ *_slist = slist; -+ -+ return EOK; -+} -+ -+static int -+tcurl_request_destructor(struct tcurl_request *tcurl_req) -+{ -+ if (tcurl_req->tcurl_ctx != NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "Terminating TCURL request...\n"); -+ curl_multi_remove_handle(tcurl_req->tcurl_ctx->multi_handle, -+ tcurl_req->curl_easy_handle); -+ } -+ -+ if (tcurl_req->headers != NULL) { -+ curl_slist_free_all(tcurl_req->headers); -+ } -+ -+ if (tcurl_req->curl_easy_handle != NULL) { -+ curl_easy_cleanup(tcurl_req->curl_easy_handle); - } - - return 0; - } -+ -+static struct tcurl_request * -+tcurl_request_create(TALLOC_CTX *mem_ctx, -+ const char *socket_path, -+ const char *url, -+ const char **headers, -+ struct sss_iobuf *body) -+{ -+ struct tcurl_request *tcurl_req; -+ errno_t ret; -+ -+ tcurl_req = talloc_zero(mem_ctx, struct tcurl_request); -+ if (tcurl_req == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); -+ return NULL; -+ } -+ -+ if (url == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "URL cannot be NULL!\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ /* Setup a curl easy handle. This handle contains state for the request -+ * and is later associated with curl multi handle which performs -+ * asynchronous processing. */ -+ tcurl_req->curl_easy_handle = curl_easy_init(); -+ if (tcurl_req->curl_easy_handle == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize curl easy handle!\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ tcurl_req->url = talloc_strdup(tcurl_req, url); -+ if (tcurl_req->url == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ if (socket_path != NULL) { -+ tcurl_req->socket = talloc_strdup(tcurl_req, socket_path); -+ if (tcurl_req->socket == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ ret = tcurl_construct_headers(headers, &tcurl_req->headers); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to construct headers [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ tcurl_req->body = body; -+ -+ talloc_set_destructor(tcurl_req, tcurl_request_destructor); -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_URL, url); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ if (socket_path != NULL) { -+ ret = tcurl_set_option(tcurl_req, CURLOPT_UNIX_SOCKET_PATH, socket_path); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ -+ if (body != NULL) { -+ /* Curl will tell the underlying protocol about incoming data length. -+ * In case of HTTP it will add a sane Content-Length header. */ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_INFILESIZE_LARGE, -+ (curl_off_t)sss_iobuf_get_size(body)); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ -+ ret = EOK; -+ -+done: -+ if (ret != EOK) { -+ talloc_free(tcurl_req); -+ return NULL; -+ } -+ -+ return tcurl_req; -+} -+ -+struct tcurl_request *tcurl_http(TALLOC_CTX *mem_ctx, -+ enum tcurl_http_method method, -+ const char *socket_path, -+ const char *url, -+ const char **headers, -+ struct sss_iobuf *body) -+{ -+ struct tcurl_request *tcurl_req; -+ errno_t ret; -+ -+ tcurl_req = tcurl_request_create(mem_ctx, socket_path, url, headers, body); -+ if (tcurl_req == NULL) { -+ return NULL; -+ } -+ -+ /* Set HTTP specific options. */ -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_HTTPHEADER, tcurl_req->headers); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ switch (method) { -+ case TCURL_HTTP_GET: -+ /* Nothing to do here. GET is default. */ -+ break; -+ case TCURL_HTTP_PUT: -+ ret = tcurl_set_option(tcurl_req, CURLOPT_UPLOAD, 1L); -+ if (ret != EOK) { -+ goto done; -+ } -+ break; -+ case TCURL_HTTP_POST: -+ ret = tcurl_set_option(tcurl_req, CURLOPT_CUSTOMREQUEST, "POST"); -+ if (ret != EOK) { -+ goto done; -+ } -+ break; -+ case TCURL_HTTP_DELETE: -+ ret = tcurl_set_option(tcurl_req, CURLOPT_CUSTOMREQUEST, "DELETE"); -+ if (ret != EOK) { -+ goto done; -+ } -+ break; -+ } -+ -+ ret = EOK; -+ -+done: -+ if (ret != EOK) { -+ talloc_free(tcurl_req); -+ return NULL; -+ } -+ -+ return tcurl_req; -+} -+ -+struct tevent_req *tcurl_http_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct tcurl_ctx *tcurl_ctx, -+ enum tcurl_http_method method, -+ const char *socket_path, -+ const char *url, -+ const char **headers, -+ struct sss_iobuf *body, -+ int timeout) -+{ -+ struct tcurl_request *tcurl_req; -+ struct tevent_req *req; -+ -+ tcurl_req = tcurl_http(mem_ctx, method, socket_path, url, headers, body); -+ if (tcurl_req == NULL) { -+ return NULL; -+ } -+ -+ req = tcurl_request_send(mem_ctx, ev, tcurl_ctx, tcurl_req, timeout); -+ if (req == NULL) { -+ talloc_free(tcurl_req); -+ } -+ -+ return req; -+} -+ -+errno_t tcurl_http_recv(TALLOC_CTX *mem_ctx, -+ struct tevent_req *req, -+ int *_http_code, -+ struct sss_iobuf **_response) -+{ -+ return tcurl_request_recv(mem_ctx, req, _response, _http_code); -+} -+ -+errno_t tcurl_req_enable_rawoutput(struct tcurl_request *tcurl_req) -+{ -+ return tcurl_set_option(tcurl_req, CURLOPT_HEADER, 1L); -+} -+ -+errno_t tcurl_req_verify_peer(struct tcurl_request *tcurl_req, -+ const char *capath, -+ const char *cacert, -+ bool verify_peer, -+ bool verify_host) -+{ -+ errno_t ret; -+ -+ long peer = verify_peer ? 1L : 0L; -+ long host = verify_host ? 2L : 0L; -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_SSL_VERIFYPEER, peer); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_SSL_VERIFYHOST, host); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ if (capath != NULL) { -+ ret = tcurl_set_option(tcurl_req, CURLOPT_CAPATH, capath); -+ if (ret != EOK) { -+ return ret; -+ } -+ } -+ -+ if (cacert != NULL) { -+ ret = tcurl_set_option(tcurl_req, CURLOPT_CAINFO, cacert); -+ if (ret != EOK) { -+ return ret; -+ } -+ } -+ -+ return EOK; -+} -+ -+errno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req, -+ const char *cert, -+ const char *key) -+{ -+ errno_t ret; -+ -+ if (cert == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "You must specify client certificate!\n"); -+ return EINVAL; -+ } -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_SSLCERT, cert); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ if (key != NULL) { -+ /* If client's private key is in separate file. */ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_SSLKEY, key); -+ if (ret != EOK) { -+ return ret; -+ } -+ } -+ -+ return EOK; -+} -diff --git a/src/util/tev_curl.h b/src/util/tev_curl.h -index 444eb286e09d189b4588e2b2152b5202df3914d8..933abcb9b531412737e8fcf391644d828b125cf8 100644 ---- a/src/util/tev_curl.h -+++ b/src/util/tev_curl.h -@@ -27,14 +27,16 @@ - - #include "util/sss_iobuf.h" - -+struct tcurl_request; -+ - /** -- * @brief Supported HTTP requests -+ * @brief Supported HTTP methods - */ --enum tcurl_http_request { -+enum tcurl_http_method { - TCURL_HTTP_GET, - TCURL_HTTP_PUT, -- TCURL_HTTP_DELETE, - TCURL_HTTP_POST, -+ TCURL_HTTP_DELETE, - }; - - /** -@@ -46,16 +48,95 @@ struct tcurl_ctx *tcurl_init(TALLOC_CTX *mem_ctx, - struct tevent_context *ev); - - /** -+ * @brief Run a single asynchronous TCURL request. -+ * -+ * If the libcurl processing succeeds but we obtain a protocol error we still -+ * mark the tevent request as successful. The protocol error is return from -+ * @tcurl_request_recv as an output parameter. -+ * -+ * @param[in] mem_ctx The talloc context that owns the request -+ * @param[in] ev Event loop context -+ * @param[in] tctx Use tcurl_init to get this context -+ * @param[in] tcurl_req TCURL request -+ * @param[in] timeout The request timeout in seconds. Use 0 if you want -+ * to use the default libcurl timeout. -+ * -+ * @returns A tevent request or NULL on allocation error. On other errors, we -+ * try to set the errno as event error code and run it to completion so that -+ * the programmer can use tcurl_request_recv to read the error code. -+ * -+ * @see tcurl_init -+ * @see tcurl_http -+ * @see tcurl_request_recv -+ */ -+struct tevent_req * -+tcurl_request_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct tcurl_ctx *tcurl_ctx, -+ struct tcurl_request *tcurl_req, -+ long int timeout); -+ -+/** -+ * @brief Receive a result of a single asynchronous TCURL request. -+ * -+ * @param[in] mem_ctx The talloc context that owns the response -+ * @param[in] req The request previously obtained with tcurl_request_send -+ * @param[out] _response Response to the request -+ * @param[out] _response_code Protocol response code (may indicate a protocl error) -+ * -+ * @returns The error code of the curl request (not the HTTP code!) -+ */ -+errno_t tcurl_request_recv(TALLOC_CTX *mem_ctx, -+ struct tevent_req *req, -+ struct sss_iobuf **_response, -+ int *_response_code); -+ -+/** -+ * @brief Create a HTTP request. -+ * -+ * Use this if you need better control over the request options. -+ * -+ * Headers are a NULL-terminated array of strings such as: -+ * static const char *headers[] = { -+ * "Content-type: application/octet-stream", -+ * NULL, -+ * }; -+ * -+ * @param[in] mem_ctx The talloc context that owns the tcurl_request -+ * @param[in] method TCURL HTTP method -+ * @param[in] socket_path The path to the UNIX socket to forward the -+ * request to, may be NULL. -+ * @param[in] url The request URL, cannot be NULL. -+ * @param[in] headers A NULL-terminated array of strings to use -+ * as additional HTTP headers. Pass NULL if you -+ * don't need any additional headers. -+ * @param[in] body The HTTP request input data. For some request -+ * types like DELETE, this is OK to leave as NULL. -+ * -+ * @returns A tcurl_request that can be later started with tcurl_request_send -+ * or NULL on error. -+ * -+ * @see tcurl_init -+ * @see tcurl_request_send -+ * @see tcurl_request_recv -+ */ -+struct tcurl_request *tcurl_http(TALLOC_CTX *mem_ctx, -+ enum tcurl_http_method method, -+ const char *socket_path, -+ const char *url, -+ const char **headers, -+ struct sss_iobuf *body); -+ -+/** - * @brief Run a single asynchronous HTTP request. - * -- * Currently only UNIX sockets at socket_path are supported. -+ * Use this if you do not need control over additional request options. - * - * If the request runs into completion, but reports a failure with HTTP return - * code, the request will be marked as done. Only if the request cannot run at - * all (if e.g. the socket is unreachable), the request will fail completely. - * -- * Headers are a NULL-terminated -- * array of strings such as: -+ * Headers are a NULL-terminated array of strings such as: - * static const char *headers[] = { - * "Content-type: application/octet-stream", - * NULL, -@@ -63,15 +144,15 @@ struct tcurl_ctx *tcurl_init(TALLOC_CTX *mem_ctx, - * - * @param[in] mem_ctx The talloc context that owns the iobuf - * @param[in] ev Event loop context -- * @param[in] tctx Use tcurl_init to get this context -- * @param[in] req_type The request type -+ * @param[in] tcurl_ctx Use tcurl_init to get this context -+ * @param[in] method HTTP method - * @param[in] socket_path The path to the UNIX socket to forward the -- * request to -- * @param[in] url The request URL -+ * request to, may be NULL. -+ * @param[in] url The request URL, cannot be NULL. - * @param[in] headers A NULL-terminated array of strings to use - * as additional HTTP headers. Pass NULL if you - * don't need any additional headers. -- * @param[in] req_data The HTTP request input data. For some request -+ * @param[in] body The HTTP request input data. For some request - * types like DELETE, this is OK to leave as NULL. - * @param[in] timeout The request timeout in seconds. Use 0 if you want - * to use the default libcurl timeout. -@@ -85,12 +166,12 @@ struct tcurl_ctx *tcurl_init(TALLOC_CTX *mem_ctx, - */ - struct tevent_req *tcurl_http_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, -- struct tcurl_ctx *tctx, -- enum tcurl_http_request req_type, -+ struct tcurl_ctx *tcurl_ctx, -+ enum tcurl_http_method method, - const char *socket_path, - const char *url, -- const char *headers[], -- struct sss_iobuf *req_data, -+ const char **headers, -+ struct sss_iobuf *body, - int timeout); - - /** -@@ -104,9 +185,62 @@ struct tevent_req *tcurl_http_send(TALLOC_CTX *mem_ctx, - * - * @returns The error code of the curl request (not the HTTP code!) - */ --int tcurl_http_recv(TALLOC_CTX *mem_ctx, -- struct tevent_req *req, -- int *_http_code, -- struct sss_iobuf **_outbuf); -+errno_t tcurl_http_recv(TALLOC_CTX *mem_ctx, -+ struct tevent_req *req, -+ int *_http_code, -+ struct sss_iobuf **_response); -+ -+/** -+ * @brief We are usually interested only in the reply body without protocol -+ * headers. Call this function on tcurl_request, if you want to include -+ * complete protocol response in the output buffer. -+ * -+ * @param[in] tcurl_request -+ * -+ * @returns errno code -+ * -+ * @see tcurl_http -+ */ -+errno_t tcurl_req_enable_rawoutput(struct tcurl_request *tcurl_req); -+ -+/** -+ * @brief TLS is enabled automatically by providing an URL that points to -+ * TLS-enabled protocol such as https. If you want to provide different -+ * path to CA directory or disable peer/hostname check explicitly, use -+ * this function on tcurl_request. -+ * -+ * @param[in] tcurl_request -+ * @param[in] capath Path to directory containing installed CA certificates. -+ * If not set, libcurl default is used. -+ * @param[ing cacert CA certificate. If NULL it is found in @capath. -+ * @param[in] verify_peer If false, the peer certificate is not verified. -+ * @param[in] verify_host If false, the host name provided in remote -+ * certificate may differ from the actual host name. -+ * -+ * @returns errno code -+ * -+ * @see tcurl_http -+ */ -+errno_t tcurl_req_verify_peer(struct tcurl_request *tcurl_req, -+ const char *capath, -+ const char *cacert, -+ bool verify_peer, -+ bool verify_host); -+/** -+ * @brief Some server require client verification during TLS setup. You can -+ * provide path to client's certificate file. If this file does not contain -+ * private key, you can specify a different file the holds the private key. -+ * -+ * @param[in] tcurl_request -+ * @param[in] cert Path to client's certificate. -+ * @param[in] key Path to client's private key. -+ * -+ * @returns errno code -+ * -+ * @see tcurl_http -+ */ -+errno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req, -+ const char *cert, -+ const char *key); - - #endif /* __TEV_CURL_H */ -diff --git a/src/util/util_errors.c b/src/util/util_errors.c -index 60c2f439b3e39b1dbff353e429114cb5a3070052..466a3b4062f39b29d831a5d8a62dc8d576eb2e97 100644 ---- a/src/util/util_errors.c -+++ b/src/util/util_errors.c -@@ -111,6 +111,10 @@ struct err_string error_to_str[] = { - { "Credential cache name not allowed" }, /* ERR_KCM_WRONG_CCNAME_FORMAT */ - { "Cannot encode a JSON object to string" }, /* ERR_JSON_ENCODING */ - { "Cannot decode a JSON object from string" }, /* ERR_JSON_DECODING */ -+ { "Invalid certificate provided" }, /* ERR_INVALID_CERT */ -+ { "Unable to initialize SSL" }, /* ERR_SSL_FAILURE */ -+ { "Unable to verify peer" }, /* ERR_UNABLE_TO_VERIFY_PEER */ -+ { "Unable to resolve host" }, /* ERR_UNABLE_TO_RESOLVE_HOST */ - { "ERR_LAST" } /* ERR_LAST */ - }; - -diff --git a/src/util/util_errors.h b/src/util/util_errors.h -index 4e9da814702e2cd46edc52fd5c2ae5f640602609..2f90c0a5d65325a431a8e4d9a480170808c9198e 100644 ---- a/src/util/util_errors.h -+++ b/src/util/util_errors.h -@@ -133,6 +133,10 @@ enum sssd_errors { - ERR_KCM_WRONG_CCNAME_FORMAT, - ERR_JSON_ENCODING, - ERR_JSON_DECODING, -+ ERR_INVALID_CERT, -+ ERR_SSL_FAILURE, -+ ERR_UNABLE_TO_VERIFY_PEER, -+ ERR_UNABLE_TO_RESOLVE_HOST, - ERR_LAST /* ALWAYS LAST */ - }; - --- -2.9.3 - diff --git a/SOURCES/0075-RESP-Expose-DP-method-getAccountDomain-to-responders.patch b/SOURCES/0075-RESP-Expose-DP-method-getAccountDomain-to-responders.patch new file mode 100644 index 0000000..208b5dd --- /dev/null +++ b/SOURCES/0075-RESP-Expose-DP-method-getAccountDomain-to-responders.patch @@ -0,0 +1,239 @@ +From cac78825ba2fcb2efcd7ff2e58b562b370bbb28c Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 30 Oct 2017 20:51:40 +0100 +Subject: [PATCH 75/83] RESP: Expose DP method getAccountDomain() to responders +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adds a tevent request that calls the getAccountDomain DP method. +This request will be used by responders to locate an object's domain. + +At the moment, only looking up UIDs and GIDs is supported. + +Internally, until we switch to the rdp_ interface everywhere, this +interface hooks into the sss_dp_issue_request(). When we switch to +the rdp_ interface, we'll be able to provide a nicer method parameters +as well. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit 95fd82a4d7b50e64fed6906bc5345f271e8247d9) +--- + src/responder/common/responder.h | 36 +++++++ + src/responder/common/responder_get_domains.c | 155 +++++++++++++++++++++++++++ + 2 files changed, 191 insertions(+) + +diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h +index 9a57df558994c418d440eabf4a29f69c4a47faa5..9400e4b60d9fc77c23710174e4c00a83f6395985 100644 +--- a/src/responder/common/responder.h ++++ b/src/responder/common/responder.h +@@ -375,6 +375,42 @@ struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx, + + errno_t sss_dp_get_domains_recv(struct tevent_req *req); + ++/* ++ * Call a getAccountDomain request ++ * ++ * Only requests by ID are supported. ++ * ++ * @param mem_ctx Parent memory context ++ * @param rctx Responder context ++ * @param domain The SSSD domain we're querying. The response can ++ * be either NULL or come from any of domain's subdomains ++ * or domain itself ++ * @param type Either SSS_DP_USER or SSS_DP_GROUP, other types ++ * are not supported at the moment ++ * @param opt_id The ID number we're trying to locate ++ * ++ * @return A tevent request or NULL if allocating the request fails. ++ */ ++struct tevent_req *sss_dp_get_account_domain_send(TALLOC_CTX *mem_ctx, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ enum sss_dp_acct_type type, ++ uint32_t opt_id); ++ ++/* Receive a getAccountDomain request result ++ * ++ * @param mem_ctx The memory context that will own the contents of _domain ++ * @param req The request that had finished ++ * @para _domain Either NULL (the request did not match any domain) or ++ * a string that corresponds to either the input domain ++ * or any of its subdomains ++ * ++ * @return EOK on success, errno otherwise ++ */ ++errno_t sss_dp_get_account_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ char **_domain); ++ + errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resp_ctx *rctx, +diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c +index 4955af064040e03372e9a47fb264499d9a23b828..d69bce2300580beb42d3af8e66ff467db890f284 100644 +--- a/src/responder/common/responder_get_domains.c ++++ b/src/responder/common/responder_get_domains.c +@@ -642,3 +642,158 @@ errno_t sss_parse_inp_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + + return state->error; + } ++ ++/* ========== Get domain of an ccount ================= */ ++struct sss_dp_get_account_domain_info { ++ struct sss_domain_info *dom; ++ enum sss_dp_acct_type type; ++ uint32_t opt_id; ++}; ++ ++static DBusMessage *sss_dp_get_account_domain_msg(void *pvt); ++ ++struct tevent_req *sss_dp_get_account_domain_send(TALLOC_CTX *mem_ctx, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *dom, ++ enum sss_dp_acct_type type, ++ uint32_t opt_id) ++{ ++ struct tevent_req *req; ++ struct sss_dp_get_account_domain_info *info; ++ struct sss_dp_req_state *state; ++ char *key; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct sss_dp_req_state); ++ if (!req) { ++ return NULL; ++ } ++ ++ info = talloc_zero(state, struct sss_dp_get_account_domain_info); ++ if (info == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ info->type = type; ++ info->opt_id = opt_id; ++ info->dom = dom; ++ ++ key = talloc_asprintf(state, "%d: %"SPRIuid"@%s", type, opt_id, dom->name); ++ if (key == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ ret = sss_dp_issue_request(state, rctx, key, dom, ++ sss_dp_get_account_domain_msg, ++ info, req); ++ talloc_free(key); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not issue DP request [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediately; ++ } ++ ++ return req; ++ ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, rctx->ev); ++ return req; ++} ++ ++static DBusMessage * ++sss_dp_get_account_domain_msg(void *pvt) ++{ ++ DBusMessage *msg; ++ dbus_bool_t dbret; ++ struct sss_dp_get_account_domain_info *info; ++ uint32_t entry_type; ++ char *filter; ++ ++ info = talloc_get_type(pvt, struct sss_dp_get_account_domain_info); ++ ++ switch (info->type) { ++ case SSS_DP_USER: ++ entry_type = BE_REQ_USER; ++ break; ++ case SSS_DP_GROUP: ++ entry_type = BE_REQ_GROUP; ++ break; ++ case SSS_DP_USER_AND_GROUP: ++ entry_type = BE_REQ_USER_AND_GROUP; ++ break; ++ default: ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Unsupported lookup type %X for this request\n", info->type); ++ return NULL; ++ } ++ ++ filter = talloc_asprintf(info, "idnumber=%u", info->opt_id); ++ if (!filter) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n"); ++ return NULL; ++ } ++ ++ msg = dbus_message_new_method_call(NULL, ++ DP_PATH, ++ IFACE_DP, ++ IFACE_DP_GETACCOUNTDOMAIN); ++ if (msg == NULL) { ++ talloc_free(filter); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n"); ++ return NULL; ++ } ++ ++ /* create the message */ ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Creating request for [%s][%#x][%s][%s:-]\n", ++ info->dom->name, entry_type, be_req2str(entry_type), filter); ++ ++ dbret = dbus_message_append_args(msg, ++ DBUS_TYPE_UINT32, &entry_type, ++ DBUS_TYPE_STRING, &filter, ++ DBUS_TYPE_INVALID); ++ talloc_free(filter); ++ if (!dbret) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n"); ++ dbus_message_unref(msg); ++ return NULL; ++ } ++ ++ return msg; ++} ++ ++errno_t sss_dp_get_account_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ char **_domain) ++{ ++ errno_t ret; ++ dbus_uint16_t err_maj; ++ dbus_uint32_t err_min; ++ char *msg; ++ ++ ret = sss_dp_req_recv(mem_ctx, req, &err_maj, &err_min, &msg); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not get account info [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ if (err_maj != DP_ERR_OK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Data Provider Error: %u, %u\n", ++ (unsigned int)err_maj, (unsigned int)err_min); ++ talloc_free(msg); ++ return err_min ? err_min : EIO; ++ } ++ ++ *_domain = msg; ++ return EOK; ++} +-- +2.14.3 + diff --git a/SOURCES/0075-tcurl-test-refactor-so-new-options-can-be-added-more.patch b/SOURCES/0075-tcurl-test-refactor-so-new-options-can-be-added-more.patch deleted file mode 100644 index bcea2c6..0000000 --- a/SOURCES/0075-tcurl-test-refactor-so-new-options-can-be-added-more.patch +++ /dev/null @@ -1,438 +0,0 @@ -From a886247bcdb1c551486c34a8d4eccd046a11382f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Fri, 24 Feb 2017 12:23:01 +0100 -Subject: [PATCH 75/90] tcurl test: refactor so new options can be added more - easily - -Just to make the tool a little bit nicer and more flexible. - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit b800a6d09244359959404aca81c6796a58cafbcb) ---- - src/tests/tcurl_test_tool.c | 334 +++++++++++++++++++++++++++----------------- - 1 file changed, 209 insertions(+), 125 deletions(-) - -diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c -index 9a6266f89131ffd3a561e857af85df9854c44949..e5fc9705db415650d849b89c3d18e41574b7e28b 100644 ---- a/src/tests/tcurl_test_tool.c -+++ b/src/tests/tcurl_test_tool.c -@@ -28,26 +28,39 @@ - - struct tool_ctx { - bool verbose; -- -- errno_t error; - bool done; - - size_t nreqs; - }; - -+struct tool_options { -+ int debug; -+ int verbose; -+ -+ enum tcurl_http_method method; -+ const char *socket_path; -+}; -+ - static void request_done(struct tevent_req *req) - { -- int http_code; -+ struct tool_ctx *tool_ctx; - struct sss_iobuf *outbuf; -- struct tool_ctx *tool_ctx = tevent_req_callback_data(req, -- struct tool_ctx); -+ int http_code; -+ errno_t ret; - -- tool_ctx->error = tcurl_request_recv(tool_ctx, req, &outbuf, &http_code); -+ tool_ctx = tevent_req_callback_data(req, struct tool_ctx); -+ -+ ret = tcurl_request_recv(tool_ctx, req, &outbuf, &http_code); - talloc_zfree(req); - -- if (tool_ctx->error != EOK) { -- DEBUG(SSSDBG_FATAL_FAILURE, "HTTP request failed: %d\n", tool_ctx->error); -+ tool_ctx->nreqs--; -+ if (tool_ctx->nreqs == 0) { - tool_ctx->done = true; -+ } -+ -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "HTTP request failed [%d]: %s\n", -+ ret, sss_strerror(ret)); - return; - } else if (tool_ctx->verbose) { - printf("Request HTTP code: %d\n", http_code); -@@ -55,167 +68,171 @@ static void request_done(struct tevent_req *req) - (const char *) sss_iobuf_get_data(outbuf)); - talloc_zfree(outbuf); - } -- -- tool_ctx->nreqs--; -- if (tool_ctx->nreqs == 0) { -- tool_ctx->done = true; -- } - } - --int main(int argc, const char *argv[]) -+static errno_t -+parse_options(poptContext pc, struct tool_options *opts) - { - int opt; -- poptContext pc; -- -- int pc_debug = 0; -- int pc_verbose = 0; -- const char *socket_path = NULL; -- const char *extra_arg_ptr; -- -- static const char *headers[] = { -- "Content-type: application/octet-stream", -- NULL, -- }; -- -- struct poptOption long_options[] = { -- POPT_AUTOHELP -- { "debug", '\0', POPT_ARG_INT, &pc_debug, 0, -- "The debug level to run with", NULL }, -- { "socket-path", 's', POPT_ARG_STRING, &socket_path, 0, -- "The path to the HTTP server socket", NULL }, -- { "get", 'g', POPT_ARG_NONE, NULL, 'g', "Perform a HTTP GET (default)", NULL }, -- { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, -- { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, -- { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, -- { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Print response code and body", NULL }, -- POPT_TABLEEND -- }; -- -- struct tevent_req *req; -- struct tevent_context *ev; -- enum tcurl_http_method method = TCURL_HTTP_GET; -- struct tcurl_ctx *ctx; -- struct tcurl_request *tcurl_req; -- struct tool_ctx *tool_ctx; -- -- const char *urls[MAXREQ] = { 0 }; -- struct sss_iobuf **inbufs; -- -- size_t n_reqs = 0; -- -- debug_prg_name = argv[0]; -- pc = poptGetContext(NULL, argc, argv, long_options, 0); -- poptSetOtherOptionHelp(pc, "HTTPDATA"); - - while ((opt = poptGetNextOpt(pc)) > 0) { - switch (opt) { - case 'g': -- method = TCURL_HTTP_GET; -+ opts->method = TCURL_HTTP_GET; - break; - case 'p': -- method = TCURL_HTTP_PUT; -+ opts->method = TCURL_HTTP_PUT; - break; - case 'o': -- method = TCURL_HTTP_POST; -+ opts->method = TCURL_HTTP_POST; - break; - case 'd': -- method = TCURL_HTTP_DELETE; -- break; -- case 'v': -- pc_verbose = 1; -+ opts->method = TCURL_HTTP_DELETE; - break; - default: - DEBUG(SSSDBG_FATAL_FAILURE, "Unexpected option\n"); -- return 1; -+ return EINVAL; - } - } - -- DEBUG_CLI_INIT(pc_debug); -- -- tool_ctx = talloc_zero(NULL, struct tool_ctx); -- if (tool_ctx == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Could not init tool context\n"); -- return 1; -+ if (opt != -1) { -+ poptPrintUsage(pc, stderr, 0); -+ fprintf(stderr, "%s", poptStrerror(opt)); -+ return EINVAL; - } - -- inbufs = talloc_zero_array(tool_ctx, struct sss_iobuf *, MAXREQ); -- if (inbufs == NULL) { -- talloc_zfree(tool_ctx); -- return 1; -+ return EOK; -+} -+ -+static errno_t -+prepare_requests(TALLOC_CTX *mem_ctx, -+ poptContext pc, -+ struct tool_options *opts, -+ struct tcurl_request ***_requests, -+ size_t *_num_requests) -+{ -+ struct tcurl_request **requests; -+ const char *arg; -+ const char *url; -+ struct sss_iobuf *body; -+ errno_t ret; -+ size_t i; -+ -+ static const char *headers[] = { -+ "Content-type: application/octet-stream", -+ NULL, -+ }; -+ -+ requests = talloc_zero_array(mem_ctx, struct tcurl_request *, MAXREQ + 1); -+ if (requests == NULL) { -+ return ENOMEM; - } - -- while ((extra_arg_ptr = poptGetArg(pc)) != NULL) { -- switch(method) { -+ i = 0; -+ while ((arg = poptGetArg(pc)) != NULL) { -+ if (i >= MAXREQ) { -+ fprintf(stderr, _("Too many requests!\n")); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ switch (opts->method) { - case TCURL_HTTP_GET: - case TCURL_HTTP_DELETE: -- case TCURL_HTTP_POST: -- urls[n_reqs++] = extra_arg_ptr; -+ url = arg; -+ body = NULL; - break; - case TCURL_HTTP_PUT: -- if (urls[n_reqs] == NULL) { -- urls[n_reqs] = extra_arg_ptr; -- } else { -- inbufs[n_reqs] = sss_iobuf_init_readonly( -- inbufs, -- (uint8_t *) discard_const(extra_arg_ptr), -- strlen(extra_arg_ptr)); -- if (inbufs[n_reqs] == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Could not init input buffer\n"); -- talloc_zfree(tool_ctx); -- return 1; -- } -- n_reqs++; -+ case TCURL_HTTP_POST: -+ url = arg; -+ -+ arg = poptGetArg(pc); -+ if (arg == NULL) { -+ body = NULL; -+ break; -+ } -+ -+ body = sss_iobuf_init_readonly(requests, -+ discard_const_p(uint8_t, arg), -+ strlen(arg)); -+ if (body == NULL) { -+ ret = ENOMEM; -+ goto done; - } - break; -+ default: -+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid method!\n"); -+ ret = EINVAL; -+ goto done; - } -+ -+ requests[i] = tcurl_http(requests, opts->method, opts->socket_path, -+ url, headers, body); -+ if (requests[i] == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ i++; - } - -- if (opt != -1) { -- poptPrintUsage(pc, stderr, 0); -- fprintf(stderr, "%s", poptStrerror(opt)); -- talloc_zfree(tool_ctx); -- return 1; -+ *_requests = requests; -+ *_num_requests = i; -+ -+ ret = EOK; -+ -+done: -+ if (ret != EOK) { -+ talloc_free(requests); - } - -- if (!socket_path) { -- DEBUG(SSSDBG_FATAL_FAILURE, "Please specify the socket path\n"); -- poptPrintUsage(pc, stderr, 0); -- talloc_zfree(tool_ctx); -- return 1; -+ return ret; -+} -+ -+static errno_t -+run_requests(struct tool_ctx *tool_ctx, -+ struct tcurl_request **requests) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct tcurl_ctx *tcurl_ctx; -+ struct tevent_context *ev; -+ struct tevent_req *req; -+ errno_t ret; -+ int i; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); -+ return ENOMEM; - } - -- tool_ctx->nreqs = n_reqs; -- tool_ctx->verbose = !!pc_verbose; -+ if (requests == NULL || requests[0] == NULL) { -+ ret = EOK; -+ goto done; -+ } - -- ev = tevent_context_init(tool_ctx); -+ ev = tevent_context_init(tmp_ctx); - if (ev == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Could not init tevent context\n"); -- talloc_zfree(tool_ctx); -- return 1; -+ ret = ENOMEM; -+ goto done; - } - -- ctx = tcurl_init(tool_ctx, ev); -- if (ctx == NULL) { -+ tcurl_ctx = tcurl_init(tmp_ctx, ev); -+ if (tcurl_ctx == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, "Could not init tcurl context\n"); -- talloc_zfree(tool_ctx); -- return 1; -+ ret = ENOMEM; -+ goto done; - } - -- for (size_t i = 0; i < n_reqs; i++) { -- tcurl_req = tcurl_http(tool_ctx, method, socket_path, -- urls[i], headers, inbufs[i]); -- if (tcurl_req == NULL) { -- DEBUG(SSSDBG_FATAL_FAILURE, "Unable to create TCURL request\n"); -- talloc_zfree(tool_ctx); -- return 1; -+ for (i = 0; requests[i] != NULL; i++) { -+ req = tcurl_request_send(tmp_ctx, ev, tcurl_ctx, requests[i], 5); -+ if (req == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not create tevent request\n"); -+ ret = ENOMEM; -+ goto done; - } - -- req = tcurl_request_send(tool_ctx, ev, ctx, tcurl_req, 10); -- if (ctx == NULL) { -- DEBUG(SSSDBG_FATAL_FAILURE, "Could not create request\n"); -- talloc_zfree(tool_ctx); -- return 1; -- } - tevent_req_set_callback(req, request_done, tool_ctx); - } - -@@ -226,11 +243,78 @@ int main(int argc, const char *argv[]) - if (tool_ctx->nreqs > 0) { - DEBUG(SSSDBG_FATAL_FAILURE, - "The tool finished with some pending requests, fail!\n"); -- talloc_zfree(tool_ctx); -- return 1; -+ ret = EEXIST; -+ goto done; - } - -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ struct tool_options opts = { 0 }; -+ struct tool_ctx *tool_ctx; -+ struct tcurl_request **requests; -+ poptContext pc; -+ errno_t ret; -+ -+ struct poptOption long_options[] = { -+ POPT_AUTOHELP -+ { "debug", '\0', POPT_ARG_INT, &opts.debug, 0, "The debug level to run with", NULL }, -+ { "socket-path", 's', POPT_ARG_STRING, &opts.socket_path, 0, "The path to the HTTP server socket", NULL }, -+ { "get", 'g', POPT_ARG_NONE, NULL, 'g', "Perform a HTTP GET (default)", NULL }, -+ { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, -+ { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, -+ { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, -+ { "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL }, -+ POPT_TABLEEND -+ }; -+ -+ pc = poptGetContext(NULL, argc, argv, long_options, 0); -+ poptSetOtherOptionHelp(pc, "[URL HTTPDATA]*"); -+ -+ tool_ctx = talloc_zero(NULL, struct tool_ctx); -+ if (tool_ctx == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not init tool context\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = parse_options(pc, &opts); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to parse options [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ DEBUG_CLI_INIT(opts.debug); -+ tool_ctx->verbose = opts.verbose; -+ -+ ret = prepare_requests(tool_ctx, pc, &opts, &requests, &tool_ctx->nreqs); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to prepare requests [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ ret = run_requests(tool_ctx, requests); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to issue requests [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+done: - talloc_free(tool_ctx); - poptFreeContext(pc); -- return 0; -+ -+ if (ret != EOK) { -+ return EXIT_FAILURE; -+ } -+ -+ return EXIT_SUCCESS; - } --- -2.9.3 - diff --git a/SOURCES/0076-NEGCACHE-Add-API-for-setting-and-checking-locate-acc.patch b/SOURCES/0076-NEGCACHE-Add-API-for-setting-and-checking-locate-acc.patch new file mode 100644 index 0000000..4d554a2 --- /dev/null +++ b/SOURCES/0076-NEGCACHE-Add-API-for-setting-and-checking-locate-acc.patch @@ -0,0 +1,371 @@ +From 72fdce0007af1baa0504c2d11be8b19e1a3296f1 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 6 Nov 2017 10:09:16 +0100 +Subject: [PATCH 76/83] NEGCACHE: Add API for setting and checking + locate-account-domain requests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Extends the negative cache API with several request getsetters: + - sss_ncache_set/check_domain_locate_type - check if this request + type supports locating account domain or set that this request + type does not support the locator. + + - sss_ncache_set/check_locate_gid/uid - check if it is time to call + the locator again or set that the locator should not be called + for IDs again for the duration of the negative cache. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit 07452697a67902dc6876d2f40d364cf1eadf2431) +--- + src/responder/common/negcache.c | 155 +++++++++++++++++++++++++++++++++++++++ + src/responder/common/negcache.h | 64 ++++++++++++++++ + src/tests/cmocka/test_negcache.c | 75 +++++++++++++++++++ + 3 files changed, 294 insertions(+) + +diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c +index b751d89ee9e67eea32ec4ed0935fcd67d3e92f47..bd3c9d36805adc5cca5621c815576ac21cfbec38 100644 +--- a/src/responder/common/negcache.c ++++ b/src/responder/common/negcache.c +@@ -37,6 +37,8 @@ + #define NC_GID_PREFIX NC_ENTRY_PREFIX"GID" + #define NC_SID_PREFIX NC_ENTRY_PREFIX"SID" + #define NC_CERT_PREFIX NC_ENTRY_PREFIX"CERT" ++#define NC_DOMAIN_ACCT_LOCATE_PREFIX NC_ENTRY_PREFIX"DOM_LOCATE" ++#define NC_DOMAIN_ACCT_LOCATE_TYPE_PREFIX NC_ENTRY_PREFIX"DOM_LOCATE_TYPE" + + struct sss_nc_ctx { + struct tdb_context *tdb; +@@ -665,6 +667,159 @@ int sss_ncache_set_cert(struct sss_nc_ctx *ctx, bool permanent, + return ret; + } + ++static char *domain_lookup_type_str(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *dom, ++ const char *lookup_type) ++{ ++ return talloc_asprintf(mem_ctx, ++ "%s/%s/%s", ++ NC_DOMAIN_ACCT_LOCATE_TYPE_PREFIX, ++ dom->name, ++ lookup_type); ++} ++ ++int sss_ncache_set_domain_locate_type(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ const char *lookup_type) ++{ ++ char *str; ++ int ret; ++ ++ str = domain_lookup_type_str(ctx, dom, lookup_type); ++ if (!str) return ENOMEM; ++ ++ /* Permanent cache is always used here, because whether the lookup ++ * type (getgrgid, getpwuid, ..) supports locating an entry's domain ++ * doesn't change ++ */ ++ ret = sss_ncache_set_str(ctx, str, true, false); ++ talloc_free(str); ++ return ret; ++} ++ ++int sss_ncache_check_domain_locate_type(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ const char *lookup_type) ++{ ++ char *str; ++ int ret; ++ ++ str = domain_lookup_type_str(ctx, dom, lookup_type); ++ if (!str) return ENOMEM; ++ ++ ret = sss_ncache_check_str(ctx, str); ++ talloc_free(str); ++ return ret; ++} ++ ++static char *locate_gid_str(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *dom, ++ gid_t gid) ++{ ++ return talloc_asprintf(mem_ctx, ++ "%s/%s/%s/%"SPRIgid, ++ NC_DOMAIN_ACCT_LOCATE_PREFIX, ++ NC_GID_PREFIX, ++ dom->name, ++ gid); ++} ++ ++int sss_ncache_set_locate_gid(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ gid_t gid) ++{ ++ char *str; ++ int ret; ++ ++ if (dom == NULL) { ++ return EINVAL; ++ } ++ ++ str = locate_gid_str(ctx, dom, gid); ++ if (str == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sss_ncache_set_str(ctx, str, false, false); ++ talloc_free(str); ++ return ret; ++} ++ ++int sss_ncache_check_locate_gid(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ gid_t gid) ++{ ++ char *str; ++ int ret; ++ ++ if (dom == NULL) { ++ return EINVAL; ++ } ++ ++ str = locate_gid_str(ctx, dom, gid); ++ if (str == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sss_ncache_check_str(ctx, str); ++ talloc_free(str); ++ return ret; ++} ++ ++static char *locate_uid_str(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ uid_t uid) ++{ ++ return talloc_asprintf(ctx, ++ "%s/%s/%s/%"SPRIuid, ++ NC_DOMAIN_ACCT_LOCATE_PREFIX, ++ NC_UID_PREFIX, ++ dom->name, ++ uid); ++} ++ ++int sss_ncache_set_locate_uid(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ uid_t uid) ++{ ++ char *str; ++ int ret; ++ ++ if (dom == NULL) { ++ return EINVAL; ++ } ++ ++ str = locate_uid_str(ctx, dom, uid); ++ if (str == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sss_ncache_set_str(ctx, str, false, false); ++ talloc_free(str); ++ return ret; ++} ++ ++int sss_ncache_check_locate_uid(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ uid_t uid) ++{ ++ char *str; ++ int ret; ++ ++ if (dom == NULL) { ++ return EINVAL; ++ } ++ ++ str = locate_uid_str(ctx, dom, uid); ++ if (str == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sss_ncache_check_str(ctx, str); ++ talloc_free(str); ++ return ret; ++} ++ + static int delete_permanent(struct tdb_context *tdb, + TDB_DATA key, TDB_DATA data, void *state) + { +diff --git a/src/responder/common/negcache.h b/src/responder/common/negcache.h +index 782ec140fb7dfe3ec82bed8d25290c0f7b8a36ea..2ed38e5b9a64d3393513ea2110a7c6fcb7675623 100644 +--- a/src/responder/common/negcache.h ++++ b/src/responder/common/negcache.h +@@ -80,6 +80,70 @@ int sss_ncache_set_service_name(struct sss_nc_ctx *ctx, bool permanent, + int sss_ncache_set_service_port(struct sss_nc_ctx *ctx, bool permanent, + struct sss_domain_info *dom, + uint16_t port, const char *proto); ++/* ++ * Mark the lookup_type as not supporting the negative cache. This ++ * would be used by the corresponding checker to avoid needless ++ * subsequent calls to the locator for configurations that do not ++ * support the locator plugin. ++ * ++ * @param ctx The negative cache ++ * @param dom The top-level domain. It is expected that the caller ++ * would use the top-level domain head here, because ++ * this negative cache is "per-request-type" which is the ++ * same for all subdomains of a domain ++ * @param lookup_type Lookup type, e.g. getpwuid, getgrnam. ++ * ++ * @return EOK on success, errno on failure. ++ */ ++int sss_ncache_set_domain_locate_type(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ const char *lookup_type); ++/* ++ * Check if the lookup_type supports the domain locator request. ++ * ++ * @param ctx The negative cache ++ * @param dom The top-level domain. It is expected that the caller ++ * would use the top-level domain head here, because ++ * this negative cache is "per-request-type" which is the ++ * same for all subdomains of a domain ++ * @param lookup_type Lookup type, e.g. getpwuid, getgrnam. ++ * ++ * @return ENOENT if the request supports the locator (or we ++ * haven't checked yet), EEXIST if the request does ++ * not support the domain locator request. ++ */ ++int sss_ncache_check_domain_locate_type(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ const char *key); ++ ++/* ++ * Call these two functions to mark a GID as checked until the negative ++ * cache expires. This function is used to avoid a situation where ++ * GID would be found in a subsequent domain, so any request that ++ * searches for this GID again (even if it was cached) would first ++ * run the locator again. ++ * ++ * While this negative cache entry is valid, it is expected that ++ * the negatively cached entries in the domain's GID negative ++ * cache (if any) are valid ++ * ++ * The sss_ncache_set_locate_gid() is called by the locator request ++ * when it finishes, the sss_ncache_check_locate_gid() is called ++ * by the caller of the locator request to find if the locator ++ * should be called at all. ++ */ ++int sss_ncache_set_locate_gid(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ gid_t gid); ++int sss_ncache_check_locate_gid(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ gid_t gid); ++int sss_ncache_check_locate_uid(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ uid_t uid); ++int sss_ncache_set_locate_uid(struct sss_nc_ctx *ctx, ++ struct sss_domain_info *dom, ++ uid_t uid); + + int sss_ncache_reset_permanent(struct sss_nc_ctx *ctx); + int sss_ncache_reset_users(struct sss_nc_ctx *ctx); +diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c +index ba39f778d5ddc6a4e1708aef66fc2aa1c809f150..a0210928bd60e364c60717c8b37b2405730f34ab 100644 +--- a/src/tests/cmocka/test_negcache.c ++++ b/src/tests/cmocka/test_negcache.c +@@ -883,6 +883,77 @@ static void test_sss_ncache_reset(void **state) + assert_int_equal(ret, ENOENT); + } + ++static void test_sss_ncache_locate_uid_gid(void **state) ++{ ++ uid_t uid; ++ gid_t gid; ++ int ret; ++ struct test_state *ts; ++ struct sss_domain_info *dom; ++ struct sss_domain_info *dom2; ++ ++ ts = talloc_get_type_abort(*state, struct test_state); ++ ++ uid = getuid(); ++ gid = getgid(); ++ ++ dom = talloc(ts, struct sss_domain_info); ++ assert_non_null(dom); ++ dom->name = discard_const_p(char, TEST_DOM_NAME); ++ ++ dom2 = talloc(ts, struct sss_domain_info); ++ assert_non_null(dom2); ++ dom2->name = discard_const_p(char, TEST_DOM_NAME"2"); ++ ++ ret = sss_ncache_check_locate_gid(ts->ctx, dom, gid); ++ assert_int_equal(ret, ENOENT); ++ ret = sss_ncache_check_locate_uid(ts->ctx, dom, uid); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = sss_ncache_set_locate_gid(ts->ctx, dom, gid); ++ assert_int_equal(ret, EOK); ++ ret = sss_ncache_set_locate_uid(ts->ctx, dom, uid); ++ assert_int_equal(ret, EOK); ++ ++ ret = sss_ncache_check_locate_gid(ts->ctx, dom, gid); ++ assert_int_equal(ret, EEXIST); ++ ret = sss_ncache_check_locate_uid(ts->ctx, dom, uid); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = sss_ncache_check_locate_gid(ts->ctx, dom2, gid); ++ assert_int_equal(ret, ENOENT); ++ ret = sss_ncache_check_locate_uid(ts->ctx, dom2, uid); ++ assert_int_equal(ret, ENOENT); ++} ++ ++static void test_sss_ncache_domain_locate_type(void **state) ++{ ++ int ret; ++ struct test_state *ts; ++ struct sss_domain_info *dom; ++ struct sss_domain_info *dom2; ++ ++ ts = talloc_get_type_abort(*state, struct test_state); ++ ++ dom = talloc(ts, struct sss_domain_info); ++ assert_non_null(dom); ++ dom->name = discard_const_p(char, TEST_DOM_NAME); ++ ++ dom2 = talloc(ts, struct sss_domain_info); ++ assert_non_null(dom2); ++ dom2->name = discard_const_p(char, TEST_DOM_NAME"2"); ++ ++ ret = sss_ncache_check_domain_locate_type(ts->ctx, dom, "foo"); ++ assert_int_equal(ret, ENOENT); ++ ret = sss_ncache_set_domain_locate_type(ts->ctx, dom, "foo"); ++ assert_int_equal(ret, EOK); ++ ret = sss_ncache_check_domain_locate_type(ts->ctx, dom, "foo"); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = sss_ncache_check_domain_locate_type(ts->ctx, dom2, "foo"); ++ assert_int_equal(ret, ENOENT); ++} ++ + int main(void) + { + int rv; +@@ -909,6 +980,10 @@ int main(void) + setup, teardown), + cmocka_unit_test_setup_teardown(test_sss_ncache_reset, + setup, teardown), ++ cmocka_unit_test_setup_teardown(test_sss_ncache_locate_uid_gid, ++ setup, teardown), ++ cmocka_unit_test_setup_teardown(test_sss_ncache_domain_locate_type, ++ setup, teardown), + }; + + tests_set_cwd(); +-- +2.14.3 + diff --git a/SOURCES/0076-tcurl-test-add-support-for-raw-output.patch b/SOURCES/0076-tcurl-test-add-support-for-raw-output.patch deleted file mode 100644 index 3004adc..0000000 --- a/SOURCES/0076-tcurl-test-add-support-for-raw-output.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 961abf2d35e296fe2b12b2b48c5d3fc67c0bc779 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Fri, 24 Feb 2017 12:23:22 +0100 -Subject: [PATCH 76/90] tcurl test: add support for raw output - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit 36e49a842e257ac9bde71728ee3bef4299b6e6e2) ---- - src/tests/tcurl_test_tool.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c -index e5fc9705db415650d849b89c3d18e41574b7e28b..7d3bc19f0ec7e118e251247536d25c58fe009f54 100644 ---- a/src/tests/tcurl_test_tool.c -+++ b/src/tests/tcurl_test_tool.c -@@ -36,6 +36,7 @@ struct tool_ctx { - struct tool_options { - int debug; - int verbose; -+ int raw; - - enum tcurl_http_method method; - const char *socket_path; -@@ -173,6 +174,13 @@ prepare_requests(TALLOC_CTX *mem_ctx, - goto done; - } - -+ if (opts->raw) { -+ ret = tcurl_req_enable_rawoutput(requests[i]); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ - i++; - } - -@@ -270,6 +278,7 @@ int main(int argc, const char *argv[]) - { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, - { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, - { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, -+ { "raw", 'r', POPT_ARG_NONE, &opts.raw, '\0', "Print raw protocol output", NULL }, - { "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL }, - POPT_TABLEEND - }; --- -2.9.3 - diff --git a/SOURCES/0077-TESTS-Add-tests-for-the-object-by-id-cache_req-inter.patch b/SOURCES/0077-TESTS-Add-tests-for-the-object-by-id-cache_req-inter.patch new file mode 100644 index 0000000..178e22e --- /dev/null +++ b/SOURCES/0077-TESTS-Add-tests-for-the-object-by-id-cache_req-inter.patch @@ -0,0 +1,439 @@ +From 9a4c06ddf5ec8d610f49acf5d3e231d36b37c50b Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Sun, 19 Nov 2017 17:25:02 +0100 +Subject: [PATCH 77/83] TESTS: Add tests for the object-by-id cache_req + interface +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This interface will be extended in later patches, but had no tests at +all. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit 6cd367da68ff56eb48b8b4167dbdd5e53992d194) +--- + src/tests/cmocka/test_responder_cache_req.c | 385 ++++++++++++++++++++++++++++ + 1 file changed, 385 insertions(+) + +diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c +index 80086232fd437876c2b190fb972c2ee3194d9efd..f075480a019e476407a3081a795c3c289455aca8 100644 +--- a/src/tests/cmocka/test_responder_cache_req.c ++++ b/src/tests/cmocka/test_responder_cache_req.c +@@ -197,6 +197,18 @@ static void cache_req_object_by_sid_test_done(struct tevent_req *req) + ctx->tctx->done = true; + } + ++static void cache_req_object_by_id_test_done(struct tevent_req *req) ++{ ++ struct cache_req_test_ctx *ctx = NULL; ++ ++ ctx = tevent_req_callback_data(req, struct cache_req_test_ctx); ++ ++ ctx->tctx->error = cache_req_object_by_id_recv(ctx, req, &ctx->result); ++ talloc_zfree(req); ++ ++ ctx->tctx->done = true; ++} ++ + static void prepare_user(struct sss_domain_info *domain, + struct test_user *user, + uint64_t timeout, +@@ -417,6 +429,33 @@ static void run_object_by_sid(struct cache_req_test_ctx *test_ctx, + talloc_free(req_mem_ctx); + } + ++static void run_object_by_id(struct cache_req_test_ctx *test_ctx, ++ struct sss_domain_info *domain, ++ id_t id, ++ const char **attrs, ++ int cache_refresh_percent, ++ errno_t exp_ret) ++{ ++ TALLOC_CTX *req_mem_ctx; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req_mem_ctx = talloc_new(global_talloc_context); ++ check_leaks_push(req_mem_ctx); ++ ++ req = cache_req_object_by_id_send(req_mem_ctx, test_ctx->tctx->ev, ++ test_ctx->rctx, test_ctx->ncache, cache_refresh_percent, ++ (domain == NULL ? NULL : domain->name), id, attrs); ++ assert_non_null(req); ++ tevent_req_set_callback(req, cache_req_object_by_id_test_done, test_ctx); ++ ++ ret = test_ev_loop(test_ctx->tctx); ++ assert_int_equal(ret, exp_ret); ++ assert_true(check_leaks_pop(req_mem_ctx)); ++ ++ talloc_free(req_mem_ctx); ++} ++ + struct tevent_req * + __wrap_sss_dp_get_account_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, +@@ -2132,6 +2171,334 @@ void test_object_by_sid_group_multiple_domains_notfound(void **state) + assert_true(test_ctx->dp_called); + } + ++void test_object_by_id_user_cache_valid(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Setup user. */ ++ prepare_user(test_ctx->tctx->dom, &users[0], 1000, time(NULL)); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK); ++ check_user(test_ctx, &users[0], test_ctx->tctx->dom); ++} ++ ++void test_object_by_id_user_cache_expired(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Setup user. */ ++ prepare_user(test_ctx->tctx->dom, &users[0], -1000, time(NULL)); ++ ++ /* Mock values. */ ++ /* DP should be contacted */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ mock_account_recv_simple(); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK); ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], test_ctx->tctx->dom); ++} ++ ++void test_object_by_id_user_cache_midpoint(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Setup user. */ ++ prepare_user(test_ctx->tctx->dom, &users[0], 50, time(NULL) - 26); ++ ++ /* Mock values. */ ++ /* DP should be contacted without callback */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 50, ERR_OK); ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], test_ctx->tctx->dom); ++} ++ ++void test_object_by_id_user_ncache(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ errno_t ret; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Setup user. We explicitly add the UID into BOTH UID and GID ++ * namespaces, because otherwise the cache_req plugin would ++ * search the Data Provider anyway, becase it can't be sure ++ * the object can be of the other type or not ++ */ ++ ret = sss_ncache_set_uid(test_ctx->ncache, ++ false, ++ test_ctx->tctx->dom, ++ users[0].uid); ++ assert_int_equal(ret, EOK); ++ ++ ret = sss_ncache_set_gid(test_ctx->ncache, ++ false, ++ test_ctx->tctx->dom, ++ users[0].uid); ++ assert_int_equal(ret, EOK); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT); ++ assert_false(test_ctx->dp_called); ++} ++ ++void test_object_by_id_user_missing_found(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Mock values. */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ mock_account_recv_simple(); ++ ++ test_ctx->create_user1 = true; ++ test_ctx->create_user2 = false; ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK); ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], test_ctx->tctx->dom); ++} ++ ++void test_object_by_id_user_missing_notfound(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Mock values. */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ mock_account_recv_simple(); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT); ++ assert_true(test_ctx->dp_called); ++} ++ ++void test_object_by_id_user_multiple_domains_found(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ "responder_cache_req_test_d", true); ++ assert_non_null(domain); ++ ++ prepare_user(domain, &users[0], 1000, time(NULL)); ++ ++ /* Mock values. */ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK); ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++} ++ ++void test_object_by_id_user_multiple_domains_notfound(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Mock values. */ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT); ++ assert_true(test_ctx->dp_called); ++} ++ ++void test_object_by_id_group_cache_valid(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_GRSRC_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Setup user. */ ++ prepare_group(test_ctx->tctx->dom, &groups[0], 1000, time(NULL)); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK); ++ check_group(test_ctx, &groups[0], test_ctx->tctx->dom); ++} ++ ++void test_object_by_id_group_cache_expired(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_GRSRC_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Setup user. */ ++ prepare_group(test_ctx->tctx->dom, &groups[0], -1000, time(NULL)); ++ ++ /* Mock values. */ ++ /* DP should be contacted */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ mock_account_recv_simple(); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK); ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], test_ctx->tctx->dom); ++} ++ ++void test_object_by_id_group_cache_midpoint(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_GRSRC_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Setup user. */ ++ prepare_group(test_ctx->tctx->dom, &groups[0], 50, time(NULL) - 26); ++ ++ /* Mock values. */ ++ /* DP should be contacted without callback */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 50, ERR_OK); ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], test_ctx->tctx->dom); ++} ++ ++void test_object_by_id_group_ncache(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_GRSRC_ATTRS; ++ errno_t ret; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Setup group. We explicitly add the UID into BOTH UID and GID ++ * namespaces, because otherwise the cache_req plugin would ++ * search the Data Provider anyway, becase it can't be sure ++ * the object can be of the other type or not ++ */ ++ ret = sss_ncache_set_uid(test_ctx->ncache, ++ false, ++ test_ctx->tctx->dom, ++ groups[0].gid); ++ assert_int_equal(ret, EOK); ++ ++ ret = sss_ncache_set_gid(test_ctx->ncache, ++ false, ++ test_ctx->tctx->dom, ++ groups[0].gid); ++ assert_int_equal(ret, EOK); ++ ++ assert_int_equal(ret, EOK); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT); ++ assert_false(test_ctx->dp_called); ++} ++ ++void test_object_by_id_group_missing_found(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_GRSRC_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Mock values. */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ mock_account_recv_simple(); ++ ++ test_ctx->create_group1 = true; ++ test_ctx->create_group2 = false; ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK); ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], test_ctx->tctx->dom); ++} ++ ++void test_object_by_id_group_missing_notfound(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_GRSRC_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Mock values. */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ mock_account_recv_simple(); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT); ++ assert_true(test_ctx->dp_called); ++} ++ ++void test_object_by_id_group_multiple_domains_found(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *attrs[] = SYSDB_GRSRC_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ "responder_cache_req_test_d", true); ++ assert_non_null(domain); ++ ++ prepare_group(domain, &groups[0], 1000, time(NULL)); ++ ++ /* Mock values. */ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK); ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++} ++ ++void test_object_by_id_group_multiple_domains_notfound(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_GRSRC_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Mock values. */ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT); ++ assert_true(test_ctx->dp_called); ++} ++ + int main(int argc, const char *argv[]) + { + poptContext pc; +@@ -2218,6 +2585,24 @@ int main(int argc, const char *argv[]) + new_single_domain_test(object_by_sid_group_missing_notfound), + new_multi_domain_test(object_by_sid_group_multiple_domains_found), + new_multi_domain_test(object_by_sid_group_multiple_domains_notfound), ++ ++ new_single_domain_test(object_by_id_user_cache_valid), ++ new_single_domain_test(object_by_id_user_cache_expired), ++ new_single_domain_test(object_by_id_user_cache_midpoint), ++ new_single_domain_test(object_by_id_user_ncache), ++ new_single_domain_test(object_by_id_user_missing_found), ++ new_single_domain_test(object_by_id_user_missing_notfound), ++ new_multi_domain_test(object_by_id_user_multiple_domains_found), ++ new_multi_domain_test(object_by_id_user_multiple_domains_notfound), ++ ++ new_single_domain_test(object_by_id_group_cache_valid), ++ new_single_domain_test(object_by_id_group_cache_expired), ++ new_single_domain_test(object_by_id_group_cache_midpoint), ++ new_single_domain_test(object_by_id_group_ncache), ++ new_single_domain_test(object_by_id_group_missing_found), ++ new_single_domain_test(object_by_id_group_missing_notfound), ++ new_multi_domain_test(object_by_id_group_multiple_domains_found), ++ new_multi_domain_test(object_by_id_group_multiple_domains_notfound), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +-- +2.14.3 + diff --git a/SOURCES/0077-tcurl-test-add-support-for-tls-settings.patch b/SOURCES/0077-tcurl-test-add-support-for-tls-settings.patch deleted file mode 100644 index d1e5926..0000000 --- a/SOURCES/0077-tcurl-test-add-support-for-tls-settings.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 4a0d05defd8da2fb7e618e485909b9807b83acbf Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Mon, 27 Feb 2017 12:58:06 +0100 -Subject: [PATCH 77/90] tcurl test: add support for tls settings - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit 886e0f75e6f4c7877a23a3625f8a20c09109b09d) ---- - src/tests/tcurl_test_tool.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c -index 7d3bc19f0ec7e118e251247536d25c58fe009f54..9cec000fbf2e4eca2fdc5213c8b3b4cb10f1df1b 100644 ---- a/src/tests/tcurl_test_tool.c -+++ b/src/tests/tcurl_test_tool.c -@@ -37,9 +37,14 @@ struct tool_options { - int debug; - int verbose; - int raw; -+ int tls; -+ int verify_peer; -+ int verify_host; - - enum tcurl_http_method method; - const char *socket_path; -+ const char *capath; -+ const char *cacert; - }; - - static void request_done(struct tevent_req *req) -@@ -181,6 +186,14 @@ prepare_requests(TALLOC_CTX *mem_ctx, - } - } - -+ if (opts->tls) { -+ ret = tcurl_req_verify_peer(requests[i], opts->capath, opts->cacert, -+ opts->verify_peer, opts->verify_host); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ - i++; - } - -@@ -280,6 +293,12 @@ int main(int argc, const char *argv[]) - { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, - { "raw", 'r', POPT_ARG_NONE, &opts.raw, '\0', "Print raw protocol output", NULL }, - { "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL }, -+ /* TLS */ -+ { "tls", '\0', POPT_ARG_NONE, &opts.tls, '\0', "Enable TLS", NULL }, -+ { "verify-peer", '\0', POPT_ARG_NONE, &opts.verify_peer, '\0', "Verify peer when TLS is enabled", NULL }, -+ { "verify-host", '\0', POPT_ARG_NONE, &opts.verify_host, '\0', "Verify host when TLS is enabled", NULL }, -+ { "capath", '\0', POPT_ARG_STRING, &opts.capath, '\0', "Path to CA directory where peer certificate is stored", NULL }, -+ { "cacert", '\0', POPT_ARG_STRING, &opts.cacert, '\0', "Path to CA certificate", NULL }, - POPT_TABLEEND - }; - --- -2.9.3 - diff --git a/SOURCES/0078-CACHE_REQ-Export-cache_req_search_ncache_add-as-cach.patch b/SOURCES/0078-CACHE_REQ-Export-cache_req_search_ncache_add-as-cach.patch new file mode 100644 index 0000000..cf3ca1f --- /dev/null +++ b/SOURCES/0078-CACHE_REQ-Export-cache_req_search_ncache_add-as-cach.patch @@ -0,0 +1,77 @@ +From 26ba3d0b033e52e63d6ec438d7be0df97cb4ce1b Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 30 Oct 2017 20:18:36 +0100 +Subject: [PATCH 78/83] CACHE_REQ: Export cache_req_search_ncache_add() as + cache_req private interface +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Previously, it was enough to add an entry to the negative cache of the +domain being processed in cache_req (cr->domain). But the locator plugin +can return any domain from the processed domain's subdomain list as +well. + +Therefore, this patch extends the internal API for the possibility of +setting the negative cache in another domain as well. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit 800b1a27543fa83bc6cd73d8e2789f3cdbaf584a) +--- + src/responder/common/cache_req/cache_req_private.h | 3 +++ + src/responder/common/cache_req/cache_req_search.c | 10 ++++++++-- + 2 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h +index 0f630542d38a277d1819063fa4134bd7d2525c90..a156fc65fed80693cdd0473613aeaaa3f5bb2269 100644 +--- a/src/responder/common/cache_req/cache_req_private.h ++++ b/src/responder/common/cache_req/cache_req_private.h +@@ -116,6 +116,9 @@ cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx, + const char *domain, + struct cache_req_data *data); + ++void cache_req_search_ncache_add_to_domain(struct cache_req *cr, ++ struct sss_domain_info *domain); ++ + errno_t + cache_req_add_result(TALLOC_CTX *mem_ctx, + struct cache_req_result *new_result, +diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c +index 56d0345cd8f98de574961d3c9628ae7a4c24f9be..9d5ad8056cda0284b1cc32cd51d7cb0ec12ad667 100644 +--- a/src/responder/common/cache_req/cache_req_search.c ++++ b/src/responder/common/cache_req/cache_req_search.c +@@ -60,7 +60,8 @@ static errno_t cache_req_search_ncache(struct cache_req *cr) + return EOK; + } + +-static void cache_req_search_ncache_add(struct cache_req *cr) ++void cache_req_search_ncache_add_to_domain(struct cache_req *cr, ++ struct sss_domain_info *domain) + { + errno_t ret; + +@@ -73,7 +74,7 @@ static void cache_req_search_ncache_add(struct cache_req *cr) + CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Adding [%s] to negative cache\n", + cr->debugobj); + +- ret = cr->plugin->ncache_add_fn(cr->ncache, cr->domain, cr->data); ++ ret = cr->plugin->ncache_add_fn(cr->ncache, domain, cr->data); + if (ret != EOK) { + CACHE_REQ_DEBUG(SSSDBG_MINOR_FAILURE, cr, + "Cannot set negative cache for [%s] [%d]: %s\n", +@@ -84,6 +85,11 @@ static void cache_req_search_ncache_add(struct cache_req *cr) + return; + } + ++static void cache_req_search_ncache_add(struct cache_req *cr) ++{ ++ return cache_req_search_ncache_add_to_domain(cr, cr->domain); ++} ++ + static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, + struct cache_req *cr, + struct ldb_result **_result) +-- +2.14.3 + diff --git a/SOURCES/0078-tcurl-add-support-for-http-basic-auth.patch b/SOURCES/0078-tcurl-add-support-for-http-basic-auth.patch deleted file mode 100644 index fd6ce23..0000000 --- a/SOURCES/0078-tcurl-add-support-for-http-basic-auth.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 1c543722b2b1c55b06c3cc02ace987fc68bc26d7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 28 Feb 2017 13:32:31 +0100 -Subject: [PATCH 78/90] tcurl: add support for http basic auth - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit c2ea75da72b426d98ba489039e220d417bfb4c2a) ---- - src/tests/tcurl_test_tool.c | 14 ++++++++++++++ - src/util/tev_curl.c | 24 ++++++++++++++++++++++++ - src/util/tev_curl.h | 15 +++++++++++++++ - 3 files changed, 53 insertions(+) - -diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c -index 9cec000fbf2e4eca2fdc5213c8b3b4cb10f1df1b..4ceef8e06040ea0abd4d112a5b7845f436c69488 100644 ---- a/src/tests/tcurl_test_tool.c -+++ b/src/tests/tcurl_test_tool.c -@@ -45,6 +45,9 @@ struct tool_options { - const char *socket_path; - const char *capath; - const char *cacert; -+ -+ const char *username; -+ const char *password; - }; - - static void request_done(struct tevent_req *req) -@@ -194,6 +197,14 @@ prepare_requests(TALLOC_CTX *mem_ctx, - } - } - -+ if (opts->username != NULL && opts->password != NULL) { -+ ret = tcurl_req_http_basic_auth(requests[i], opts->username, -+ opts->password); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ - i++; - } - -@@ -299,6 +310,9 @@ int main(int argc, const char *argv[]) - { "verify-host", '\0', POPT_ARG_NONE, &opts.verify_host, '\0', "Verify host when TLS is enabled", NULL }, - { "capath", '\0', POPT_ARG_STRING, &opts.capath, '\0', "Path to CA directory where peer certificate is stored", NULL }, - { "cacert", '\0', POPT_ARG_STRING, &opts.cacert, '\0', "Path to CA certificate", NULL }, -+ /* BASIC AUTH */ -+ { "username", '\0', POPT_ARG_STRING, &opts.username, '\0', "Username for basic authentication", NULL }, -+ { "password", '\0', POPT_ARG_STRING, &opts.password, '\0', "Password for basic authentication", NULL }, - POPT_TABLEEND - }; - -diff --git a/src/util/tev_curl.c b/src/util/tev_curl.c -index c155f4c038d4215933ee30d41c694ad4a14ae132..8faf07c714b636a0351be365597de68d2f68a1be 100644 ---- a/src/util/tev_curl.c -+++ b/src/util/tev_curl.c -@@ -1092,3 +1092,27 @@ errno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req, - - return EOK; - } -+ -+errno_t tcurl_req_http_basic_auth(struct tcurl_request *tcurl_req, -+ const char *username, -+ const char *password) -+{ -+ errno_t ret; -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_USERNAME, username); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ ret = tcurl_set_option(tcurl_req, CURLOPT_PASSWORD, password); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ return EOK; -+} -diff --git a/src/util/tev_curl.h b/src/util/tev_curl.h -index 933abcb9b531412737e8fcf391644d828b125cf8..c733127b3686b5665f53cf53ea72674e0d7af64e 100644 ---- a/src/util/tev_curl.h -+++ b/src/util/tev_curl.h -@@ -243,4 +243,19 @@ errno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req, - const char *cert, - const char *key); - -+/** -+ * @brief Force HTTP basic authentication with @username and @password. -+ * -+ * @param[in] tcurl_request -+ * @param[in] username -+ * @param[in] password -+ * -+ * @returns errno code -+ * -+ * @see tcurl_http -+ */ -+errno_t tcurl_req_http_basic_auth(struct tcurl_request *tcurl_req, -+ const char *username, -+ const char *password); -+ - #endif /* __TEV_CURL_H */ --- -2.9.3 - diff --git a/SOURCES/0079-CACHE_REQ-Add-plugin-methods-required-for-the-domain.patch b/SOURCES/0079-CACHE_REQ-Add-plugin-methods-required-for-the-domain.patch new file mode 100644 index 0000000..50c6e3c --- /dev/null +++ b/SOURCES/0079-CACHE_REQ-Add-plugin-methods-required-for-the-domain.patch @@ -0,0 +1,458 @@ +From 4127348220f6b32886fcc1e3f890a2e9fdedf7ed Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 30 Oct 2017 20:52:42 +0100 +Subject: [PATCH 79/83] CACHE_REQ: Add plugin methods required for the + domain-locator request +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adds three new cache_req plugin methods: + - cache_req_dp_get_domain_check_fn - check if it is time to run the + locator request again + - cache_req_dp_get_domain_send/recv_fn - run the locator itself + +The reason we added also the checker is that when the locator runs, +we add a temporary entry into the negative cache that would denote that +the locator ran and the ordinary domain negative cache (UID negcache, +GID negcache, ..) were set for the domains and can be still used to +skip domains that we know do not contain the account without calling +the getAccountDomain handler again. + +If we didn't have this checker, requesting an entry from a domain +further down the domain list would always call the locator, only +to always receive the same results. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit 2856dac5818265a6b4e42d768b73c65e333d14ff) +--- + src/responder/common/cache_req/cache_req_plugin.h | 69 ++++++++++++++++++++++ + .../cache_req/plugins/cache_req_enum_groups.c | 5 +- + .../common/cache_req/plugins/cache_req_enum_svc.c | 5 +- + .../cache_req/plugins/cache_req_enum_users.c | 5 +- + .../cache_req/plugins/cache_req_group_by_filter.c | 5 +- + .../cache_req/plugins/cache_req_group_by_id.c | 5 +- + .../cache_req/plugins/cache_req_group_by_name.c | 5 +- + .../cache_req/plugins/cache_req_host_by_name.c | 5 +- + .../plugins/cache_req_initgroups_by_name.c | 5 +- + .../plugins/cache_req_initgroups_by_upn.c | 5 +- + .../cache_req/plugins/cache_req_netgroup_by_name.c | 5 +- + .../cache_req/plugins/cache_req_object_by_id.c | 5 +- + .../cache_req/plugins/cache_req_object_by_name.c | 5 +- + .../cache_req/plugins/cache_req_object_by_sid.c | 5 +- + .../cache_req/plugins/cache_req_svc_by_name.c | 5 +- + .../cache_req/plugins/cache_req_svc_by_port.c | 5 +- + .../cache_req/plugins/cache_req_user_by_cert.c | 5 +- + .../cache_req/plugins/cache_req_user_by_filter.c | 5 +- + .../cache_req/plugins/cache_req_user_by_id.c | 5 +- + .../cache_req/plugins/cache_req_user_by_name.c | 5 +- + .../cache_req/plugins/cache_req_user_by_upn.c | 5 +- + 21 files changed, 149 insertions(+), 20 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req_plugin.h b/src/responder/common/cache_req/cache_req_plugin.h +index 8117325506b2951c3966fa50506ed0d55273ee81..803d0f4fa5a54900a458d170177e89f82b398bd9 100644 +--- a/src/responder/common/cache_req/cache_req_plugin.h ++++ b/src/responder/common/cache_req/cache_req_plugin.h +@@ -153,6 +153,72 @@ typedef bool + (*cache_req_dp_recv_fn)(struct tevent_req *subreq, + struct cache_req *cr); + ++/** ++ * Check whether the results of the domain locator can still ++ * be considered valid or whether it is time to call the request ++ * again. ++ * ++ * @param resp_ctx The responder context ++ * @param domain The domain to check. This should be the domain-head, ++ * because the locator works across a domain and its ++ * subdomains. ++ * @param data The cache req data that contain primarily the key ++ * to look for. ++ * ++ * @return True if the locator plugin should be ran again, false if ++ * @return False false ifthe lookup should just proceed with the ++ * data that is already in the negative cache. ++ */ ++typedef bool ++(*cache_req_dp_get_domain_check_fn)(struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ struct cache_req_data *data); ++/** ++ * Send Data Provider request to locate the domain ++ * of an entry ++ * ++ * @param resp_ctx The responder context ++ * @param domain The domain to check. This should be the domain-head, ++ * because the locator works across a domain and its ++ * subdomains. ++ * @param data The cache req data that contain primarily the key ++ * to look for. ++ * ++ * ++ * @return Tevent request on success. ++ * @return NULL on error. ++ */ ++typedef struct tevent_req * ++(*cache_req_dp_get_domain_send_fn)(TALLOC_CTX *mem_ctx, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ struct cache_req_data *data); ++ ++/** ++ * Process result of Data Provider find-domain request. ++ * ++ * Do not free subreq! It will be freed in the caller. ++ * ++ * @param mem_ctx The memory context that owns the _found_domain ++ * result parameter ++ * @param subreq The request to finish ++ * @param cr The cache_req being processed ++ * @param _found_domain The domain the request account belongs to. This ++ * parameter can be NULL even on success, in that ++ * case the account was not found and no lookups are ++ * needed, all domains can be skipped in this case. ++ * ++ * @return EOK if the request did not encounter any error. In this ++ * case, the _found_domain parameter can be considered authoritative, ++ * regarless of its value ++ * @return errno on error. _found_domain should be NULL in this case. ++ */ ++typedef errno_t ++(*cache_req_dp_get_domain_recv_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_req *subreq, ++ struct cache_req *cr, ++ char **_found_domain); ++ + struct cache_req_plugin { + /** + * Plugin name. +@@ -223,6 +289,9 @@ struct cache_req_plugin { + cache_req_lookup_fn lookup_fn; + cache_req_dp_send_fn dp_send_fn; + cache_req_dp_recv_fn dp_recv_fn; ++ cache_req_dp_get_domain_check_fn dp_get_domain_check_fn; ++ cache_req_dp_get_domain_send_fn dp_get_domain_send_fn; ++ cache_req_dp_get_domain_recv_fn dp_get_domain_recv_fn; + }; + + extern const struct cache_req_plugin cache_req_user_by_name; +diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c +index 15350ca8279bc77c73bcc4abe51c97a8a37cb8c8..d302994e8903dea1e25b3da3762aa2ed783daebd 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c ++++ b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c +@@ -86,7 +86,10 @@ const struct cache_req_plugin cache_req_enum_groups = { + .ncache_filter_fn = cache_req_enum_groups_ncache_filter, + .lookup_fn = cache_req_enum_groups_lookup, + .dp_send_fn = cache_req_enum_groups_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c +index 72b2f1a7d2d2e02ce1a995098d1f26003444bddb..282dc1cc83b1fda91d4c4937f99598fbdd6ec625 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c ++++ b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c +@@ -79,7 +79,10 @@ const struct cache_req_plugin cache_req_enum_svc = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_enum_svc_lookup, + .dp_send_fn = cache_req_enum_svc_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_users.c b/src/responder/common/cache_req/plugins/cache_req_enum_users.c +index a3ddcdd45548a2fa7c367f3fb3be103c115dedb4..f83ff30fdbbaacdb3bfb605a65ce70fbd8eb3a89 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_enum_users.c ++++ b/src/responder/common/cache_req/plugins/cache_req_enum_users.c +@@ -86,7 +86,10 @@ const struct cache_req_plugin cache_req_enum_users = { + .ncache_filter_fn = cache_req_enum_users_ncache_filter, + .lookup_fn = cache_req_enum_users_lookup, + .dp_send_fn = cache_req_enum_users_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c +index aa89953b88313605041cce599999fc5bbc741525..009f0f88523c8c4c02a25f0f5d6a83187e0a17f8 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c ++++ b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c +@@ -134,7 +134,10 @@ const struct cache_req_plugin cache_req_group_by_filter = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_group_by_filter_lookup, + .dp_send_fn = cache_req_group_by_filter_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +index 5ca64283a781318bc4e4d6920fff989c3f3919b4..70381266712d2c27c95027b54efab201c5df7690 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +@@ -155,7 +155,10 @@ const struct cache_req_plugin cache_req_group_by_id = { + .ncache_filter_fn = cache_req_group_by_id_ncache_filter, + .lookup_fn = cache_req_group_by_id_lookup, + .dp_send_fn = cache_req_group_by_id_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c +index 7706051818590af77da75d3e4c7f671c89170f82..3be0d5ea557bad11529b897be1d7706a8809acb1 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c +@@ -197,7 +197,10 @@ const struct cache_req_plugin cache_req_group_by_name = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_group_by_name_lookup, + .dp_send_fn = cache_req_group_by_name_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c +index 56048c5e4bcadfb341f4b42d978d53484abd65d2..696d9e50d94e824d2664ed5a8fe3150b821d570e 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c +@@ -99,7 +99,10 @@ const struct cache_req_plugin cache_req_host_by_name = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_host_by_name_lookup, + .dp_send_fn = cache_req_host_by_name_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c +index 75ac44e1ad36238f01342eced9188d07daa50720..c5bea9d84921cc567bf794d3ba5a57fadb81695b 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c +@@ -212,7 +212,10 @@ const struct cache_req_plugin cache_req_initgroups_by_name = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_initgroups_by_name_lookup, + .dp_send_fn = cache_req_initgroups_by_name_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c +index dfb21ac1a0090a3ef9029b38f5b1e8bdda3440c6..9bd00f357c630bae4a52e356577000bd8de94013 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c ++++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c +@@ -123,5 +123,8 @@ const struct cache_req_plugin cache_req_initgroups_by_upn = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_initgroups_by_upn_lookup, + .dp_send_fn = cache_req_initgroups_by_upn_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; +diff --git a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c +index ef0775d0b8eac4d679450f436d8427cff9c04582..d370d342ec5b2c0e0e9f1f4ea90b34b59bff60b6 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c +@@ -131,7 +131,10 @@ const struct cache_req_plugin cache_req_netgroup_by_name = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_netgroup_by_name_lookup, + .dp_send_fn = cache_req_netgroup_by_name_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +index 339bd4f5fef827acc1aa3c123d041e426d9e4782..2af95313cb2df0f46a61519ac962074033f34a12 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +@@ -129,7 +129,10 @@ const struct cache_req_plugin cache_req_object_by_id = { + .ncache_filter_fn = cache_req_object_by_id_ncache_filter, + .lookup_fn = cache_req_object_by_id_lookup, + .dp_send_fn = cache_req_object_by_id_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c +index 854d0b83c420ebebcb5e0e079c707081fa313632..a740fbb8d05efb4601e8e40d2a07896ecb251d4e 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c +@@ -207,7 +207,10 @@ const struct cache_req_plugin cache_req_object_by_name = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_object_by_name_lookup, + .dp_send_fn = cache_req_object_by_name_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c +index 039a79df7bb1ab213ce4334835e9fc18e6d0faac..1af638ff9d94ffa3bf6e418433d5c4e98acfb2b8 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c ++++ b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c +@@ -123,7 +123,10 @@ const struct cache_req_plugin cache_req_object_by_sid = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_object_by_sid_lookup, + .dp_send_fn = cache_req_object_by_sid_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c +index 4c32d9977cc06e43eed3a90e7dcf107e91efefb5..5b17051031e35c5767d27b19c922325cee4b6eac 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c +@@ -155,7 +155,10 @@ const struct cache_req_plugin cache_req_svc_by_name = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_svc_by_name_lookup, + .dp_send_fn = cache_req_svc_by_name_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c +index 1e998f642c766d15d3f6fe777aa5c789629508e2..4c005df3972386fef3c5a858a2b691cb2a63fd57 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c ++++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c +@@ -128,7 +128,10 @@ const struct cache_req_plugin cache_req_svc_by_port = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_svc_by_port_lookup, + .dp_send_fn = cache_req_svc_by_port_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c +index 7a0c7d8ce1644f1c41b64c6903e4e20eb3c2c081..a2dc1fad28ca09eeba77c563f17518671095ab42 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c +@@ -97,7 +97,10 @@ const struct cache_req_plugin cache_req_user_by_cert = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_user_by_cert_lookup, + .dp_send_fn = cache_req_user_by_cert_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c +index dd3f42e855389ecc73690e4d18c4977253b108a6..42b6e816372c51623f29e8a7e28859a9dfca640f 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c +@@ -134,7 +134,10 @@ const struct cache_req_plugin cache_req_user_by_filter = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_user_by_filter_lookup, + .dp_send_fn = cache_req_user_by_filter_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +index 913f9be5bcc2dfd074b52cb3b15fb6948826e831..254330e92cc801b84bfb5e308d6d90ac54507d77 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +@@ -155,7 +155,10 @@ const struct cache_req_plugin cache_req_user_by_id = { + .ncache_filter_fn = cache_req_user_by_id_ncache_filter, + .lookup_fn = cache_req_user_by_id_lookup, + .dp_send_fn = cache_req_user_by_id_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c +index 2e49de938d0af50089d0cf49860441c2b6ea679c..d24a2221b2a69d24d360c46c41073e19dc79036b 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c +@@ -202,7 +202,10 @@ const struct cache_req_plugin cache_req_user_by_name = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_user_by_name_lookup, + .dp_send_fn = cache_req_user_by_name_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c +index b8bcd241ed79c510aca214ad3788215ae2997d20..e08ab70ae081a5d532d7ab436687978416e7c493 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c +@@ -128,5 +128,8 @@ const struct cache_req_plugin cache_req_user_by_upn = { + .ncache_filter_fn = NULL, + .lookup_fn = cache_req_user_by_upn_lookup, + .dp_send_fn = cache_req_user_by_upn_dp_send, +- .dp_recv_fn = cache_req_common_dp_recv ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, + }; +-- +2.14.3 + diff --git a/SOURCES/0079-tcurl-test-allow-to-set-custom-headers.patch b/SOURCES/0079-tcurl-test-allow-to-set-custom-headers.patch deleted file mode 100644 index ac764da..0000000 --- a/SOURCES/0079-tcurl-test-allow-to-set-custom-headers.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 8047207b470ea417b11919e84931a751485d2326 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Fri, 10 Mar 2017 12:11:12 +0100 -Subject: [PATCH 79/90] tcurl test: allow to set custom headers - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit d1ed11fc50922aab2332758a9300f3fbf814f112) ---- - src/tests/tcurl_test_tool.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c -index 4ceef8e06040ea0abd4d112a5b7845f436c69488..63a3e26b561781795873c2a4d72ac071a4da9939 100644 ---- a/src/tests/tcurl_test_tool.c -+++ b/src/tests/tcurl_test_tool.c -@@ -40,6 +40,7 @@ struct tool_options { - int tls; - int verify_peer; - int verify_host; -+ const char **headers; - - enum tcurl_http_method method; - const char *socket_path; -@@ -121,13 +122,14 @@ prepare_requests(TALLOC_CTX *mem_ctx, - size_t *_num_requests) - { - struct tcurl_request **requests; -+ struct sss_iobuf *body; -+ const char **headers; - const char *arg; - const char *url; -- struct sss_iobuf *body; - errno_t ret; - size_t i; - -- static const char *headers[] = { -+ static const char *default_headers[] = { - "Content-type: application/octet-stream", - NULL, - }; -@@ -137,6 +139,8 @@ prepare_requests(TALLOC_CTX *mem_ctx, - return ENOMEM; - } - -+ headers = opts->headers == NULL ? default_headers : opts->headers; -+ - i = 0; - while ((arg = poptGetArg(pc)) != NULL) { - if (i >= MAXREQ) { -@@ -302,6 +306,9 @@ int main(int argc, const char *argv[]) - { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, - { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, - { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, -+#ifdef POPT_ARG_ARGV -+ { "header", 'h', POPT_ARG_ARGV, &opts.headers, '\0', "Add HTTP header", NULL }, -+#endif - { "raw", 'r', POPT_ARG_NONE, &opts.raw, '\0', "Print raw protocol output", NULL }, - { "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL }, - /* TLS */ --- -2.9.3 - diff --git a/SOURCES/0080-CACHE_REQ-Add-a-private-request-cache_req_locate_dom.patch b/SOURCES/0080-CACHE_REQ-Add-a-private-request-cache_req_locate_dom.patch new file mode 100644 index 0000000..f00f399 --- /dev/null +++ b/SOURCES/0080-CACHE_REQ-Add-a-private-request-cache_req_locate_dom.patch @@ -0,0 +1,177 @@ +From d30dd0f52d452562e47f9a30b1630eff2f817792 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 30 Oct 2017 20:21:05 +0100 +Subject: [PATCH 80/83] CACHE_REQ: Add a private request + cache_req_locate_domain() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adds a new request cache_req_locate_domain_send/recv. This request, if the +plugin that is being processed supports the locator, will call the plugin's +dp_get_domain_send_fn(). On any error, the request returns just the error +code. On success, the request returns the domain the object was found at. + +If the getAccountDomain() method returns that the back end does not support +the locator method, all further getAccountDomain() calls are disabled for +that domain. + +Related: +https://pagure.io/SSSD/sssd/issue/3468 + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit 0a0b34f5fbe8f4a8c533a7d65f0f2961ee264054) +--- + src/responder/common/cache_req/cache_req_private.h | 7 ++ + src/responder/common/cache_req/cache_req_search.c | 93 ++++++++++++++++++++++ + src/util/util_errors.c | 1 + + src/util/util_errors.h | 1 + + 4 files changed, 102 insertions(+) + +diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h +index a156fc65fed80693cdd0473613aeaaa3f5bb2269..9586e3788045ff44eb2a4b626dc7fcaf11ec8028 100644 +--- a/src/responder/common/cache_req/cache_req_private.h ++++ b/src/responder/common/cache_req/cache_req_private.h +@@ -106,6 +106,13 @@ errno_t cache_req_search_recv(TALLOC_CTX *mem_ctx, + struct ldb_result **_result, + bool *_dp_success); + ++struct tevent_req *cache_req_locate_domain_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct cache_req *cr); ++errno_t cache_req_locate_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ char **_found_domain); ++ + struct tevent_req * + cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c +index 9d5ad8056cda0284b1cc32cd51d7cb0ec12ad667..3365962d473b0982945de2541e44ba86b43a0db5 100644 +--- a/src/responder/common/cache_req/cache_req_search.c ++++ b/src/responder/common/cache_req/cache_req_search.c +@@ -485,3 +485,96 @@ errno_t cache_req_search_recv(TALLOC_CTX *mem_ctx, + + return EOK; + } ++ ++struct cache_req_locate_domain_state { ++ struct cache_req *cr; ++ ++ char *found_domain; ++}; ++ ++static void cache_req_locate_domain_done(struct tevent_req *subreq); ++ ++struct tevent_req *cache_req_locate_domain_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct cache_req *cr) ++{ ++ struct cache_req_locate_domain_state *state; ++ struct tevent_req *req; ++ struct tevent_req *subreq; ++ errno_t ret; ++ bool should_run; ++ ++ req = tevent_req_create(mem_ctx, &state, struct cache_req_locate_domain_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ state->cr = cr; ++ ++ should_run = cr->plugin->dp_get_domain_check_fn(cr->rctx, ++ get_domains_head(cr->domain), ++ cr->data); ++ if (should_run == false) { ++ /* The request was tried too recently, don't issue a new one ++ * as its results are still valid ++ */ ++ ret = ERR_GET_ACCT_DOM_CACHED; ++ goto immediate; ++ } ++ ++ subreq = cr->plugin->dp_get_domain_send_fn(state, ++ cr->rctx, ++ get_domains_head(cr->domain), ++ cr->data); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, cache_req_locate_domain_done, req); ++ return req; ++ ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void cache_req_locate_domain_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req; ++ struct cache_req_locate_domain_state *state; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct cache_req_locate_domain_state); ++ ++ ret = state->cr->plugin->dp_get_domain_recv_fn(state, ++ subreq, ++ state->cr, ++ &state->found_domain); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t cache_req_locate_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ char **_found_domain) ++{ ++ struct cache_req_locate_domain_state *state = NULL; ++ ++ state = tevent_req_data(req, struct cache_req_locate_domain_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *_found_domain = talloc_steal(mem_ctx, state->found_domain); ++ return EOK; ++} +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 9a9ba3f3063cab4afb538c3a58527a2d2ed3fffd..06c620b40aaa00d6ce58ace3a28449ffbdf8da88 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -116,6 +116,7 @@ struct err_string error_to_str[] = { + { "Unable to verify peer" }, /* ERR_UNABLE_TO_VERIFY_PEER */ + { "Unable to resolve host" }, /* ERR_UNABLE_TO_RESOLVE_HOST */ + { "GetAccountDomain() not supported" }, /* ERR_GET_ACCT_DOM_NOT_SUPPORTED */ ++ { "The last GetAccountDomain() result is still valid" }, /* ERR_GET_ACCT_DOM_CACHED */ + { "ERR_LAST" } /* ERR_LAST */ + }; + +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index 5ee9862c3f2f60c078693b1b85a40f15436e818c..bebd6e198fc0077891a602f80182a993ce3f789b 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -138,6 +138,7 @@ enum sssd_errors { + ERR_UNABLE_TO_VERIFY_PEER, + ERR_UNABLE_TO_RESOLVE_HOST, + ERR_GET_ACCT_DOM_NOT_SUPPORTED, ++ ERR_GET_ACCT_DOM_CACHED, + ERR_LAST /* ALWAYS LAST */ + }; + +-- +2.14.3 + diff --git a/SOURCES/0080-tcurl-test-add-support-for-client-certificate.patch b/SOURCES/0080-tcurl-test-add-support-for-client-certificate.patch deleted file mode 100644 index 8635100..0000000 --- a/SOURCES/0080-tcurl-test-add-support-for-client-certificate.patch +++ /dev/null @@ -1,53 +0,0 @@ -From f63d4b3749fd76796a26f1c1f07bdddcb681a768 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Mon, 13 Mar 2017 13:30:48 +0100 -Subject: [PATCH 80/90] tcurl test: add support for client certificate - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit ae6b11229d9961e26922918183c7c1de7780b8d6) ---- - src/tests/tcurl_test_tool.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c -index 63a3e26b561781795873c2a4d72ac071a4da9939..fbc2790357b131ebb21b4be041688e5f699d73e7 100644 ---- a/src/tests/tcurl_test_tool.c -+++ b/src/tests/tcurl_test_tool.c -@@ -47,6 +47,9 @@ struct tool_options { - const char *capath; - const char *cacert; - -+ const char *clientcert; -+ const char *clientkey; -+ - const char *username; - const char *password; - }; -@@ -201,6 +204,14 @@ prepare_requests(TALLOC_CTX *mem_ctx, - } - } - -+ if (opts->clientcert != NULL) { -+ ret = tcurl_req_set_client_cert(requests[i], opts->clientcert, -+ opts->clientkey); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ - if (opts->username != NULL && opts->password != NULL) { - ret = tcurl_req_http_basic_auth(requests[i], opts->username, - opts->password); -@@ -317,6 +328,8 @@ int main(int argc, const char *argv[]) - { "verify-host", '\0', POPT_ARG_NONE, &opts.verify_host, '\0', "Verify host when TLS is enabled", NULL }, - { "capath", '\0', POPT_ARG_STRING, &opts.capath, '\0', "Path to CA directory where peer certificate is stored", NULL }, - { "cacert", '\0', POPT_ARG_STRING, &opts.cacert, '\0', "Path to CA certificate", NULL }, -+ { "clientcert", '\0', POPT_ARG_STRING, &opts.clientcert, '\0', "Path to client's certificate", NULL }, -+ { "clientkey", '\0', POPT_ARG_STRING, &opts.clientkey, '\0', "Path to client's private key", NULL }, - /* BASIC AUTH */ - { "username", '\0', POPT_ARG_STRING, &opts.username, '\0', "Username for basic authentication", NULL }, - { "password", '\0', POPT_ARG_STRING, &opts.password, '\0', "Password for basic authentication", NULL }, --- -2.9.3 - diff --git a/SOURCES/0081-CACHE_REQ-Implement-the-plugin-methods-that-utilize-.patch b/SOURCES/0081-CACHE_REQ-Implement-the-plugin-methods-that-utilize-.patch new file mode 100644 index 0000000..6c0f694 --- /dev/null +++ b/SOURCES/0081-CACHE_REQ-Implement-the-plugin-methods-that-utilize-.patch @@ -0,0 +1,413 @@ +From 7482c6affd4dfa77a8d465ff0283617792847725 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 6 Nov 2017 15:52:11 +0100 +Subject: [PATCH 81/83] CACHE_REQ: Implement the plugin methods that utilize + the domain locator API +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Mainly, this patch adds handlers for the dp_get_domain_check_fn(), +dp_get_domain_send_fn() and dp_get_domain_recv_fn() functions to +requests that resolve objects by ID. + +This patch also adds domain-local negcache setter for by-id methods +Previously, the by-ID methods only used global negative cache setters +because the ID space is global and we always iterated over all domains. + +However, with addition of the domain locator plugin, we want also +to skip only certain domains and the easiest way to to so is to add +the IDs for domains that do not contain these IDs to the negative cache +with the get-account-domain request. + +Therefore this patch also adds per-domain negative cache setters for +the three plugins that search by ID. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit a6eb9c4c3ff68d134bc745e8374f182737e9696b) +--- + src/responder/common/cache_req/cache_req_private.h | 5 ++ + .../common/cache_req/plugins/cache_req_common.c | 17 +++++ + .../cache_req/plugins/cache_req_group_by_id.c | 62 +++++++++++++++-- + .../cache_req/plugins/cache_req_object_by_id.c | 77 ++++++++++++++++++++-- + .../cache_req/plugins/cache_req_user_by_id.c | 63 ++++++++++++++++-- + src/tests/cmocka/common_mock_resp_dp.c | 23 +++++++ + 6 files changed, 235 insertions(+), 12 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h +index 9586e3788045ff44eb2a4b626dc7fcaf11ec8028..95f24c0e5b9ab1150591d308c7288c57fe478c5d 100644 +--- a/src/responder/common/cache_req/cache_req_private.h ++++ b/src/responder/common/cache_req/cache_req_private.h +@@ -187,4 +187,9 @@ bool + cache_req_common_dp_recv(struct tevent_req *subreq, + struct cache_req *cr); + ++errno_t ++cache_reg_common_get_acct_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *subreq, ++ struct cache_req *cr, ++ char **_domain); + #endif /* _CACHE_REQ_PRIVATE_H_ */ +diff --git a/src/responder/common/cache_req/plugins/cache_req_common.c b/src/responder/common/cache_req/plugins/cache_req_common.c +index 1f86258bc14c7a382712959f24a4ec4c153572d4..408c91949ceb3ecaf743f270f58f4e3fcfc3ccb1 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_common.c ++++ b/src/responder/common/cache_req/plugins/cache_req_common.c +@@ -147,3 +147,20 @@ done: + talloc_free(err_msg); + return bret; + } ++ ++errno_t ++cache_reg_common_get_acct_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *subreq, ++ struct cache_req *cr, ++ char **_domain) ++{ ++ errno_t ret; ++ ++ ret = sss_dp_get_account_domain_recv(mem_ctx, subreq, _domain); ++ if (ret != EOK) { ++ CACHE_REQ_DEBUG(SSSDBG_MINOR_FAILURE, cr, ++ "Could not get account domain [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ } ++ return ret; ++} +diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +index 70381266712d2c27c95027b54efab201c5df7690..ce84b1b4458b447ff6b4b036c6e8fe8f4d7758c8 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +@@ -39,6 +39,15 @@ cache_req_group_by_id_ncache_check(struct sss_nc_ctx *ncache, + struct sss_domain_info *domain, + struct cache_req_data *data) + { ++ errno_t ret; ++ ++ if (domain != NULL) { ++ ret = sss_ncache_check_gid(ncache, domain, data->id); ++ if (ret == EEXIST) { ++ return ret; ++ } ++ } ++ + return sss_ncache_check_gid(ncache, NULL, data->id); + } + +@@ -57,6 +66,14 @@ cache_req_group_by_id_global_ncache_add(struct sss_nc_ctx *ncache, + return sss_ncache_set_gid(ncache, false, NULL, data->id); + } + ++static errno_t ++cache_req_group_by_id_ncache_add(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *domain, ++ struct cache_req_data *data) ++{ ++ return sss_ncache_set_gid(ncache, false, domain, data->id); ++} ++ + static errno_t + cache_req_group_by_id_lookup(TALLOC_CTX *mem_ctx, + struct cache_req *cr, +@@ -132,6 +149,43 @@ cache_req_group_by_id_dp_send(TALLOC_CTX *mem_ctx, + SSS_DP_GROUP, string, id, flag); + } + ++static bool ++cache_req_group_by_id_get_domain_check(struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ struct cache_req_data *data) ++{ ++ int nret; ++ ++ nret = sss_ncache_check_locate_gid(rctx->ncache, domain, data->id); ++ if (nret == EEXIST) { ++ return false; ++ } ++ ++ return true; ++} ++ ++static struct tevent_req * ++cache_req_group_by_id_get_domain_send(TALLOC_CTX *mem_ctx, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ struct cache_req_data *data) ++{ ++ int nret; ++ ++ nret = sss_ncache_set_locate_gid(rctx->ncache, domain, data->id); ++ if (nret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot set negative cache, this might result in performance degradation\n"); ++ /* Not fatal */ ++ } ++ ++ return sss_dp_get_account_domain_send(mem_ctx, ++ rctx, ++ domain, ++ SSS_DP_GROUP, ++ data->id); ++} ++ + const struct cache_req_plugin cache_req_group_by_id = { + .name = "Group by ID", + .attr_expiration = SYSDB_CACHE_EXPIRE, +@@ -151,14 +205,14 @@ const struct cache_req_plugin cache_req_group_by_id = { + .create_debug_name_fn = cache_req_group_by_id_create_debug_name, + .global_ncache_add_fn = cache_req_group_by_id_global_ncache_add, + .ncache_check_fn = cache_req_group_by_id_ncache_check, +- .ncache_add_fn = NULL, ++ .ncache_add_fn = cache_req_group_by_id_ncache_add, + .ncache_filter_fn = cache_req_group_by_id_ncache_filter, + .lookup_fn = cache_req_group_by_id_lookup, + .dp_send_fn = cache_req_group_by_id_dp_send, + .dp_recv_fn = cache_req_common_dp_recv, +- .dp_get_domain_check_fn = NULL, +- .dp_get_domain_send_fn = NULL, +- .dp_get_domain_recv_fn = NULL, ++ .dp_get_domain_check_fn = cache_req_group_by_id_get_domain_check, ++ .dp_get_domain_send_fn = cache_req_group_by_id_get_domain_send, ++ .dp_get_domain_recv_fn = cache_reg_common_get_acct_domain_recv, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +index 2af95313cb2df0f46a61519ac962074033f34a12..1327b480c1b1b68f9826fa229c9b001f2d92b79b 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +@@ -83,6 +83,26 @@ cache_req_object_by_id_global_ncache_add(struct sss_nc_ctx *ncache, + return EOK; + } + ++static errno_t ++cache_req_object_by_id_ncache_add(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *domain, ++ struct cache_req_data *data) ++{ ++ errno_t ret; ++ ++ ret = sss_ncache_set_uid(ncache, false, domain, data->id); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = sss_ncache_set_gid(ncache, false, domain, data->id); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ return EOK; ++} ++ + static errno_t + cache_req_object_by_id_lookup(TALLOC_CTX *mem_ctx, + struct cache_req *cr, +@@ -106,6 +126,55 @@ cache_req_object_by_id_dp_send(TALLOC_CTX *mem_ctx, + cr->data->id, NULL); + } + ++static bool ++cache_req_object_by_id_get_domain_check(struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ struct cache_req_data *data) ++{ ++ int nret; ++ ++ nret = sss_ncache_check_locate_uid(rctx->ncache, domain, data->id); ++ if (nret == EEXIST) { ++ nret = sss_ncache_check_locate_gid(rctx->ncache, domain, data->id); ++ if (nret == EEXIST) { ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static struct tevent_req * ++cache_req_object_by_id_get_domain_send(TALLOC_CTX *mem_ctx, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ struct cache_req_data *data) ++{ ++ int nret; ++ ++ nret = sss_ncache_set_locate_uid(rctx->ncache, domain, data->id); ++ if (nret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot set negative cache, this might result in " ++ "performance degradation\n"); ++ /* Not fatal */ ++ } ++ ++ nret = sss_ncache_set_locate_gid(rctx->ncache, domain, data->id); ++ if (nret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot set negative cache, this might result in " ++ "performance degradation\n"); ++ /* Not fatal */ ++ } ++ ++ return sss_dp_get_account_domain_send(mem_ctx, ++ rctx, ++ domain, ++ SSS_DP_USER_AND_GROUP, ++ data->id); ++} ++ + const struct cache_req_plugin cache_req_object_by_id = { + .name = "Object by ID", + .attr_expiration = SYSDB_CACHE_EXPIRE, +@@ -125,14 +194,14 @@ const struct cache_req_plugin cache_req_object_by_id = { + .create_debug_name_fn = cache_req_object_by_id_create_debug_name, + .global_ncache_add_fn = cache_req_object_by_id_global_ncache_add, + .ncache_check_fn = cache_req_object_by_id_ncache_check, +- .ncache_add_fn = NULL, ++ .ncache_add_fn = cache_req_object_by_id_ncache_add, + .ncache_filter_fn = cache_req_object_by_id_ncache_filter, + .lookup_fn = cache_req_object_by_id_lookup, + .dp_send_fn = cache_req_object_by_id_dp_send, + .dp_recv_fn = cache_req_common_dp_recv, +- .dp_get_domain_check_fn = NULL, +- .dp_get_domain_send_fn = NULL, +- .dp_get_domain_recv_fn = NULL, ++ .dp_get_domain_check_fn = cache_req_object_by_id_get_domain_check, ++ .dp_get_domain_send_fn = cache_req_object_by_id_get_domain_send, ++ .dp_get_domain_recv_fn = cache_reg_common_get_acct_domain_recv, + }; + + struct tevent_req * +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +index 254330e92cc801b84bfb5e308d6d90ac54507d77..656fa41af5f39f68c64e241aa97c4eaf3ec57395 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +@@ -39,6 +39,15 @@ cache_req_user_by_id_ncache_check(struct sss_nc_ctx *ncache, + struct sss_domain_info *domain, + struct cache_req_data *data) + { ++ errno_t ret; ++ ++ if (domain != NULL) { ++ ret = sss_ncache_check_uid(ncache, domain, data->id); ++ if (ret == EEXIST) { ++ return ret; ++ } ++ } ++ + return sss_ncache_check_uid(ncache, NULL, data->id); + } + +@@ -57,6 +66,14 @@ cache_req_user_by_id_global_ncache_add(struct sss_nc_ctx *ncache, + return sss_ncache_set_uid(ncache, false, NULL, data->id); + } + ++static errno_t ++cache_req_user_by_id_ncache_add(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *domain, ++ struct cache_req_data *data) ++{ ++ return sss_ncache_set_uid(ncache, false, domain, data->id); ++} ++ + static errno_t + cache_req_user_by_id_lookup(TALLOC_CTX *mem_ctx, + struct cache_req *cr, +@@ -132,6 +149,44 @@ cache_req_user_by_id_dp_send(TALLOC_CTX *mem_ctx, + SSS_DP_USER, string, id, flag); + } + ++static bool ++cache_req_user_by_id_get_domain_check(struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ struct cache_req_data *data) ++{ ++ int nret; ++ ++ nret = sss_ncache_check_locate_uid(rctx->ncache, domain, data->id); ++ if (nret == EEXIST) { ++ return false; ++ } ++ ++ return true; ++} ++ ++static struct tevent_req * ++cache_req_user_by_id_get_domain_send(TALLOC_CTX *mem_ctx, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ struct cache_req_data *data) ++{ ++ int nret; ++ ++ nret = sss_ncache_set_locate_uid(rctx->ncache, domain, data->id); ++ if (nret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot set negative cache, this might result in " ++ "performance degradation\n"); ++ /* Not fatal */ ++ } ++ ++ return sss_dp_get_account_domain_send(mem_ctx, ++ rctx, ++ domain, ++ SSS_DP_USER, ++ data->id); ++} ++ + const struct cache_req_plugin cache_req_user_by_id = { + .name = "User by ID", + .attr_expiration = SYSDB_CACHE_EXPIRE, +@@ -151,14 +206,14 @@ const struct cache_req_plugin cache_req_user_by_id = { + .create_debug_name_fn = cache_req_user_by_id_create_debug_name, + .global_ncache_add_fn = cache_req_user_by_id_global_ncache_add, + .ncache_check_fn = cache_req_user_by_id_ncache_check, +- .ncache_add_fn = NULL, ++ .ncache_add_fn = cache_req_user_by_id_ncache_add, + .ncache_filter_fn = cache_req_user_by_id_ncache_filter, + .lookup_fn = cache_req_user_by_id_lookup, + .dp_send_fn = cache_req_user_by_id_dp_send, + .dp_recv_fn = cache_req_common_dp_recv, +- .dp_get_domain_check_fn = NULL, +- .dp_get_domain_send_fn = NULL, +- .dp_get_domain_recv_fn = NULL, ++ .dp_get_domain_check_fn = cache_req_user_by_id_get_domain_check, ++ .dp_get_domain_send_fn = cache_req_user_by_id_get_domain_send, ++ .dp_get_domain_recv_fn = cache_reg_common_get_acct_domain_recv, + }; + + struct tevent_req * +diff --git a/src/tests/cmocka/common_mock_resp_dp.c b/src/tests/cmocka/common_mock_resp_dp.c +index 4b38a38e6f53499132f9fe14a0ec0af157cf85ca..f21ca53ad0d6b7f4ed28d0c1d9e491af31355d43 100644 +--- a/src/tests/cmocka/common_mock_resp_dp.c ++++ b/src/tests/cmocka/common_mock_resp_dp.c +@@ -179,3 +179,26 @@ errno_t sss_dp_get_domains_recv(struct tevent_req *req) + { + return test_request_recv(req); + } ++ ++struct tevent_req * ++sss_dp_get_account_domain_send(TALLOC_CTX *mem_ctx, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ enum sss_dp_acct_type type, ++ uint32_t opt_id) ++{ ++ return test_req_succeed_send(mem_ctx, rctx->ev); ++} ++ ++errno_t sss_dp_get_account_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ char **_domain) ++{ ++ errno_t ret; ++ ++ ret = sss_mock_type(errno_t); ++ if (ret == EOK) { ++ *_domain = sss_mock_ptr_type(char *); ++ } ++ return ret; ++} +-- +2.14.3 + diff --git a/SOURCES/0081-ci-do-not-build-secrets-on-rhel6.patch b/SOURCES/0081-ci-do-not-build-secrets-on-rhel6.patch deleted file mode 100644 index f804036..0000000 --- a/SOURCES/0081-ci-do-not-build-secrets-on-rhel6.patch +++ /dev/null @@ -1,115 +0,0 @@ -From c9358747b25b257d82b050967812e54860fe7685 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 28 Mar 2017 15:24:01 +0200 -Subject: [PATCH 81/90] ci: do not build secrets on rhel6 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We require newer libcurl version than is available on rhel6. We don't -ship secrets responder in rhel6 so we just disable its build. - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 6698d40512e55e7c2d03e14c227c51b1edc77ffa) ---- - contrib/ci/configure.sh | 1 + - contrib/sssd.spec.in | 15 +++++++++++++++ - src/tests/intg/test_secrets.py | 4 ++++ - 3 files changed, 20 insertions(+) - -diff --git a/contrib/ci/configure.sh b/contrib/ci/configure.sh -index 7590743c2aa5fe31bcdf1a3e92a3f482dbec699b..9d18d0c187561a2dc3bc47d3e8913626e7ff3046 100644 ---- a/contrib/ci/configure.sh -+++ b/contrib/ci/configure.sh -@@ -38,6 +38,7 @@ if [[ "$DISTRO_BRANCH" == -redhat-redhatenterprise*-6.*- || - "--disable-cifs-idmap-plugin" - "--with-syslog=syslog" - "--without-python3-bindings" -+ "--without-secrets" - "--without-kcm" - ) - fi -diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in -index af14d4e3d6b9ffeb4696f1517113b8daa575cb99..39a974edebba3dbcd7625d1729b4a7330eaa8a27 100644 ---- a/contrib/sssd.spec.in -+++ b/contrib/sssd.spec.in -@@ -112,6 +112,12 @@ - %global enable_systemtap_opt --enable-systemtap - %endif - -+%if (0%{?fedora} || 0%{?epel} >= 7) -+ %global with_secrets 1 -+%else -+ %global with_secret_responder --without-secrets -+%endif -+ - %if (0%{?fedora} >= 23 || 0%{?rhel} >= 7) - %global with_kcm 1 - %global with_kcm_option --with-kcm -@@ -220,8 +226,10 @@ BuildRequires: libsmbclient-devel - %if (0%{?enable_systemtap} == 1) - BuildRequires: systemtap-sdt-devel - %endif -+%if (0%{?with_secrets} == 1) - BuildRequires: http-parser-devel - BuildRequires: jansson-devel -+%endif - BuildRequires: libuuid-devel - BuildRequires: libcurl-devel - -@@ -727,6 +735,7 @@ autoreconf -ivf - %{?with_python3_option} \ - %{?enable_polkit_rules_option} \ - %{?enable_systemtap_opt} \ -+ %{?with_secret_responder} \ - %{?with_kcm_option} \ - %{?experimental} - -@@ -865,7 +874,9 @@ done - %{_libexecdir}/%{servicename}/sssd_nss - %{_libexecdir}/%{servicename}/sssd_pam - %{_libexecdir}/%{servicename}/sssd_autofs -+%if (0%{?with_secrets} == 1) - %{_libexecdir}/%{servicename}/sssd_secrets -+%endif - %{_libexecdir}/%{servicename}/sssd_ssh - %{_libexecdir}/%{servicename}/sssd_sudo - %{_libexecdir}/%{servicename}/p11_child -@@ -900,7 +911,9 @@ done - %dir %{_localstatedir}/cache/krb5rcache - %attr(700,sssd,sssd) %dir %{dbpath} - %attr(755,sssd,sssd) %dir %{mcpath} -+%if (0%{?with_secrets} == 1) - %attr(700,root,root) %dir %{secdbpath} -+%endif - %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/passwd - %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group - %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/initgroups -@@ -933,7 +946,9 @@ done - %{_mandir}/man5/sssd.conf.5* - %{_mandir}/man5/sssd-simple.5* - %{_mandir}/man5/sssd-sudo.5* -+%if (0%{?with_secrets} == 1) - %{_mandir}/man5/sssd-secrets.5* -+%endif - %{_mandir}/man5/sss_rpcidmapd.5* - %{_mandir}/man8/sssd.8* - %{_mandir}/man8/sss_cache.8* -diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py -index d71c1904558cc6f8a6eee36c4049582705bc30ac..202f43e61cb0e4986394ad2b32da5abdcb0be3e9 100644 ---- a/src/tests/intg/test_secrets.py -+++ b/src/tests/intg/test_secrets.py -@@ -46,6 +46,10 @@ def create_sssd_secrets_fixture(request): - raise Exception("failed to regenerate confdb") - - resp_path = os.path.join(config.LIBEXEC_PATH, "sssd", "sssd_secrets") -+ if not os.access(resp_path, os.X_OK): -+ # It would be cleaner to use pytest.mark.skipif on the package level -+ # but upstream insists on supporting RHEL-6. -+ pytest.skip("No Secrets responder, skipping") - - secpid = os.fork() - assert secpid >= 0 --- -2.9.3 - diff --git a/SOURCES/0082-CACHE_REQ-Use-the-domain-locator-request-to-only-sea.patch b/SOURCES/0082-CACHE_REQ-Use-the-domain-locator-request-to-only-sea.patch new file mode 100644 index 0000000..713322a --- /dev/null +++ b/SOURCES/0082-CACHE_REQ-Use-the-domain-locator-request-to-only-sea.patch @@ -0,0 +1,2048 @@ +From 1b4b03720c409b183debe0e0532b1009301e9cb2 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Sun, 19 Nov 2017 22:47:00 +0100 +Subject: [PATCH 82/83] CACHE_REQ: Use the domain-locator request to only + search domains where the entry was found +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Uses the internal cache_req interface around the getAccountDomain to only +search the domain returned by the cache_req_locate_domain_recv() request. + +If that request returns that no domain matched, all domains (belonging +to the currently processed main domain) are skipped by setting the +per-type negative cache. + +if a domain is reported as containing an object, all domains except that +one are marked with the negative cache entries. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3468 + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit f2a5e29f063f9d623c1336d76f4b2bc500c1a5e2) +--- + src/responder/common/cache_req/cache_req.c | 402 +++++- + src/responder/common/cache_req/cache_req_domain.h | 1 + + src/tests/cmocka/test_responder_cache_req.c | 1373 +++++++++++++++++++++ + 3 files changed, 1758 insertions(+), 18 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index 110df561101be538e3f0496addfa2e14e42ea918..ad9bc040dd999a205713141e6a1512e47b69c45e 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -363,6 +363,53 @@ static void cache_req_global_ncache_add(struct cache_req *cr) + return; + } + ++static bool cache_req_check_acct_domain_lookup_type(struct cache_req *cr, ++ struct sss_domain_info *dom) ++{ ++ struct sss_domain_info *head; ++ int nret; ++ ++ head = get_domains_head(dom); ++ if (head == NULL) { ++ return false; ++ } ++ ++ nret = sss_ncache_check_domain_locate_type(cr->rctx->ncache, ++ head, ++ cr->plugin->name); ++ if (nret == ENOENT) { ++ return true; ++ } ++ return false; ++} ++ ++static errno_t cache_req_set_acct_domain_lookup_type(struct cache_req *cr, ++ struct sss_domain_info *dom) ++{ ++ struct sss_domain_info *head; ++ ++ head = get_domains_head(dom); ++ if (head == NULL) { ++ return EINVAL; ++ } ++ ++ return sss_ncache_set_domain_locate_type(cr->rctx->ncache, ++ head, ++ cr->plugin->name); ++} ++ ++static void cache_req_domain_set_locate_flag(struct cache_req_domain *domains, ++ struct cache_req *cr) ++{ ++ struct cache_req_domain *crd_iter; ++ ++ DLIST_FOR_EACH(crd_iter, domains) { ++ if (cache_req_check_acct_domain_lookup_type(cr, crd_iter->domain)) { ++ crd_iter->locate_domain = true; ++ } ++ } ++} ++ + static bool + cache_req_assume_upn(struct cache_req *cr) + { +@@ -391,6 +438,227 @@ cache_req_assume_upn(struct cache_req *cr) + return true; + } + ++struct cache_req_locate_dom_state { ++ /* input data */ ++ struct tevent_context *ev; ++ struct cache_req *cr; ++ struct cache_req_domain *req_domains; ++ ++ /* Return values in case the first cache lookup succeeds */ ++ struct ldb_result *result; ++ bool dp_success; ++}; ++ ++static void cache_req_locate_dom_cache_done(struct tevent_req *subreq); ++static void cache_req_locate_dom_done(struct tevent_req *subreq); ++static void cache_req_locate_dom_mark_neg_all( ++ struct cache_req_locate_dom_state *state); ++static void cache_req_locate_dom_mark_neg_domains( ++ struct cache_req_locate_dom_state *state, ++ const char *found_domain_name); ++ ++static struct tevent_req *cache_req_locate_dom_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct cache_req *cr, ++ struct cache_req_domain *req_domains) ++{ ++ struct tevent_req *req; ++ struct tevent_req *subreq; ++ struct cache_req_locate_dom_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct cache_req_locate_dom_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ state->ev = ev; ++ state->cr = cr; ++ state->req_domains = req_domains; ++ ++ /* It is wasteful to run the domain locator request if the results are ++ * present in the cache, because the domain locator always contacts ++ * the DP. Therefore, first run a cache-only search and only if the ++ * requested data is not available, run the locator ++ * ++ * FIXME - this could be optimized further if we are running the ++ * second iteration with cache_first, then we don't need to search ++ * again ++ */ ++ subreq = cache_req_search_send(state, ++ state->ev, ++ state->cr, ++ false, /* Don't bypass cache */ ++ true); /* Do bypass DP */ ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ tevent_req_set_callback(subreq, cache_req_locate_dom_cache_done, req); ++ ++ return req; ++ ++immediately: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void cache_req_locate_dom_cache_done(struct tevent_req *subreq) ++{ ++ struct cache_req_locate_dom_state *state = NULL; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct cache_req_locate_dom_state); ++ ++ ret = cache_req_search_recv(state, subreq, &state->result, &state->dp_success); ++ talloc_zfree(subreq); ++ ++ switch (ret) { ++ case EOK: ++ /* Just finish the request and let the caller handle the result */ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Result found in the cache\n"); ++ tevent_req_done(req); ++ return; ++ case ENOENT: ++ /* Not cached and locator was requested, run the locator ++ * DP request plugin ++ */ ++ subreq = cache_req_locate_domain_send(state, ++ state->ev, ++ state->cr); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, cache_req_locate_dom_done, req); ++ return; ++ default: ++ DEBUG(SSSDBG_OP_FAILURE, ++ "cache_req_search_recv returned [%d]: %s\n", ret, sss_strerror(ret)); ++ break; ++ } ++ ++ tevent_req_error(req, ret); ++ return; ++} ++ ++static void cache_req_locate_dom_done(struct tevent_req *subreq) ++{ ++ struct cache_req_locate_dom_state *state; ++ struct tevent_req *req; ++ errno_t ret; ++ char *found_domain_name; ++ int nret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct cache_req_locate_dom_state); ++ ++ ret = cache_req_locate_domain_recv(state, subreq, &found_domain_name); ++ talloc_zfree(subreq); ++ switch (ret) { ++ case ERR_GET_ACCT_DOM_NOT_SUPPORTED: ++ nret = cache_req_set_acct_domain_lookup_type(state->cr, ++ state->cr->domain); ++ if (nret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Failed to disable domain locating functionality for %s\n", ++ state->cr->plugin->name); ++ } ++ DEBUG(SSSDBG_CONF_SETTINGS, ++ "Disabled domain locating functionality for %s\n", ++ state->cr->plugin->name); ++ break; ++ case ERR_NOT_FOUND: ++ cache_req_locate_dom_mark_neg_all(state); ++ break; ++ case EOK: ++ cache_req_locate_dom_mark_neg_domains(state, found_domain_name); ++ break; ++ default: ++ /* We explicitly ignore errors here */ ++ break; ++ } ++ ++ tevent_req_done(req); ++ return; ++} ++ ++static void cache_req_locate_dom_mark_neg_all( ++ struct cache_req_locate_dom_state *state) ++{ ++ struct cache_req_domain *iter; ++ ++ DLIST_FOR_EACH(iter, state->req_domains) { ++ if (get_domains_head(state->cr->domain) != get_domains_head(iter->domain)) { ++ /* Only add to negative cache for domains from the same "main" ++ * domain" */ ++ continue; ++ } ++ cache_req_search_ncache_add_to_domain(state->cr, iter->domain); ++ } ++} ++ ++static void cache_req_locate_dom_mark_neg_domains( ++ struct cache_req_locate_dom_state *state, ++ const char *found_domain_name) ++{ ++ struct sss_domain_info *found_domain; ++ struct cache_req_domain *iter; ++ ++ found_domain = find_domain_by_name(get_domains_head(state->cr->domain), ++ found_domain_name, ++ true); ++ if (found_domain == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot find domain %s\n", found_domain_name); ++ return; ++ } ++ ++ /* Set negcache in all subdomains of the one being examined ++ * except the found one */ ++ DLIST_FOR_EACH(iter, state->req_domains) { ++ if (strcasecmp(found_domain_name, ++ iter->domain->name) == 0) { ++ continue; ++ } ++ ++ if (get_domains_head(found_domain) != get_domains_head(iter->domain)) { ++ /* Don't set negative cache for domains outside the main ++ * domain/subdomain tree b/c the locator request is not ++ * authoritative for them ++ */ ++ continue; ++ } ++ cache_req_search_ncache_add_to_domain(state->cr, iter->domain); ++ } ++} ++ ++static errno_t cache_req_locate_dom_cache_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct ldb_result **_result, ++ bool *_dp_success) ++{ ++ struct cache_req_locate_dom_state *state; ++ ++ state = tevent_req_data(req, struct cache_req_locate_dom_state); ++ ++ if (_dp_success != NULL) { ++ *_dp_success = state->dp_success; ++ } ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ if (_result != NULL) { ++ *_result = talloc_steal(mem_ctx, state->result); ++ } ++ ++ return EOK; ++} ++ + struct cache_req_search_domains_state { + /* input data */ + struct tevent_context *ev; +@@ -398,6 +666,7 @@ struct cache_req_search_domains_state { + + /* work data */ + struct cache_req_domain *cr_domain; ++ struct cache_req_domain *req_domains; + struct sss_domain_info *selected_domain; + struct cache_req_result **results; + size_t num_results; +@@ -408,6 +677,10 @@ struct cache_req_search_domains_state { + }; + + static errno_t cache_req_search_domains_next(struct tevent_req *req); ++static errno_t cache_req_handle_result(struct tevent_req *req, ++ struct ldb_result *result); ++ ++static void cache_req_search_domains_locate_done(struct tevent_req *subreq); + + static void cache_req_search_domains_done(struct tevent_req *subreq); + +@@ -417,6 +690,7 @@ cache_req_search_domains_send(TALLOC_CTX *mem_ctx, + struct cache_req *cr, + struct cache_req_domain *cr_domain, + bool check_next, ++ bool first_iteration, + bool bypass_cache, + bool bypass_dp) + { +@@ -435,11 +709,23 @@ cache_req_search_domains_send(TALLOC_CTX *mem_ctx, + state->cr = cr; + + state->cr_domain = cr_domain; ++ state->req_domains = cr_domain; + state->check_next = check_next; + state->dp_success = true; + state->bypass_cache = bypass_cache; + state->bypass_dp = bypass_dp; + ++ if (cr->plugin->dp_get_domain_send_fn != NULL ++ && ((state->check_next && cr_domain->next != NULL) ++ || (state->bypass_cache && !first_iteration))) { ++ /* If the request is not qualified with a domain name AND ++ * there are multiple domains to search OR if this is the second ++ * pass during the "check-cache-first" schema, it makes sense ++ * to try to run the domain-locator plugin ++ */ ++ cache_req_domain_set_locate_flag(cr_domain, cr); ++ } ++ + ret = cache_req_search_domains_next(req); + if (ret == EAGAIN) { + return req; +@@ -510,12 +796,23 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) + return ret; + } + ++ if (state->cr_domain->locate_domain) { ++ subreq = cache_req_locate_dom_send(state, ++ state->ev, ++ cr, ++ state->req_domains); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ tevent_req_set_callback(subreq, cache_req_search_domains_locate_done, req); ++ return EAGAIN; ++ } ++ + subreq = cache_req_search_send(state, state->ev, cr, + state->bypass_cache, state->bypass_dp); + if (subreq == NULL) { + return ENOMEM; + } +- + tevent_req_set_callback(subreq, cache_req_search_domains_done, req); + + /* we will continue with the following domain the next time */ +@@ -549,6 +846,89 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) + return ENOENT; + } + ++static void cache_req_search_domains_locate_done(struct tevent_req *subreq) ++{ ++ struct cache_req_search_domains_state *state; ++ struct ldb_result *result = NULL; ++ struct tevent_req *req; ++ bool dp_success; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct cache_req_search_domains_state); ++ ++ ret = cache_req_locate_dom_cache_recv(state, subreq, &result, &dp_success); ++ talloc_zfree(subreq); ++ ++ /* Remember if any DP request fails, but here it shouldn't matter ++ * as the only DP request that should realistically happen is midpoint ++ * refresh */ ++ state->dp_success = !dp_success ? false : state->dp_success; ++ ++ /* Don't locate the domain again */ ++ state->cr_domain->locate_domain = false; ++ ++ switch (ret) { ++ case EOK: ++ if (result != NULL) { ++ /* Handle result as normally */ ++ ret = cache_req_handle_result(req, result); ++ if (ret != EAGAIN) { ++ goto done; ++ } ++ } ++ break; ++ default: ++ /* Some serious error has happened. Finish. */ ++ goto done; ++ } ++ ++ /* This is a domain less search, continue with the next domain. */ ++ ret = cache_req_search_domains_next(req); ++ ++done: ++ switch (ret) { ++ case EOK: ++ tevent_req_done(req); ++ break; ++ case EAGAIN: ++ break; ++ default: ++ tevent_req_error(req, ret); ++ break; ++ } ++ return; ++} ++ ++static errno_t cache_req_handle_result(struct tevent_req *req, ++ struct ldb_result *result) ++{ ++ struct cache_req_search_domains_state *state; ++ errno_t ret; ++ ++ state = tevent_req_data(req, struct cache_req_search_domains_state); ++ ++ /* We got some data from this search. Save it. */ ++ ret = cache_req_create_and_add_result(state, ++ state->cr, ++ state->selected_domain, ++ result, ++ state->cr->data->name.lookup, ++ &state->results, ++ &state->num_results); ++ if (ret != EOK) { ++ /* We were unable to save data. */ ++ return ret; ++ } ++ ++ if (!state->check_next || !state->cr->plugin->search_all_domains) { ++ /* We are not interested in more results. */ ++ return EOK; ++ } ++ ++ return EAGAIN; ++} ++ + static void cache_req_search_domains_done(struct tevent_req *subreq) + { + struct cache_req_search_domains_state *state; +@@ -568,25 +948,10 @@ static void cache_req_search_domains_done(struct tevent_req *subreq) + + switch (ret) { + case EOK: +- /* We got some data from this search. Save it. */ +- ret = cache_req_create_and_add_result(state, +- state->cr, +- state->selected_domain, +- result, +- state->cr->data->name.lookup, +- &state->results, +- &state->num_results); +- if (ret != EOK) { +- /* We were unable to save data. */ ++ ret = cache_req_handle_result(req, result); ++ if (ret != EAGAIN) { + goto done; + } +- +- if (!state->check_next || !state->cr->plugin->search_all_domains) { +- /* We are not interested in more results. */ +- ret = EOK; +- goto done; +- } +- + break; + case ENOENT: + if (state->check_next == false) { +@@ -1030,6 +1395,7 @@ cache_req_search_domains(struct tevent_req *req, + + subreq = cache_req_search_domains_send(state, state->ev, state->cr, + cr_domain, check_next, ++ state->first_iteration, + bypass_cache, bypass_dp); + if (subreq == NULL) { + return ENOMEM; +diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h +index ebdc71dd635d5d8a5d06e30e96c5d4101b6d98bf..5769b6aee309d9ba3edd5bb73a3cef6dc3193fdc 100644 +--- a/src/responder/common/cache_req/cache_req_domain.h ++++ b/src/responder/common/cache_req/cache_req_domain.h +@@ -26,6 +26,7 @@ + struct cache_req_domain { + struct sss_domain_info *domain; + bool fqnames; ++ bool locate_domain; + + struct cache_req_domain *prev; + struct cache_req_domain *next; +diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c +index f075480a019e476407a3081a795c3c289455aca8..0ee0070d0c9fbb89020f522b2f7613f1076a8cbb 100644 +--- a/src/tests/cmocka/test_responder_cache_req.c ++++ b/src/tests/cmocka/test_responder_cache_req.c +@@ -27,6 +27,7 @@ + #include "tests/cmocka/common_mock_resp.h" + #include "db/sysdb.h" + #include "responder/common/cache_req/cache_req.h" ++#include "db/sysdb_private.h" /* new_subdomain() */ + + #define TESTS_PATH "tp_" BASE_FILE_STEM + #define TEST_CONF_DB "test_responder_cache_req_conf.ldb" +@@ -63,6 +64,11 @@ struct test_group { + test_multi_domain_setup, \ + test_multi_domain_teardown) + ++#define new_subdomain_test(test) \ ++ cmocka_unit_test_setup_teardown(test_ ## test, \ ++ test_subdomain_setup, \ ++ test_subdomain_teardown) ++ + #define run_cache_req(ctx, send_fn, done_fn, dom, crp, lookup, expret) do { \ + TALLOC_CTX *req_mem_ctx; \ + struct tevent_req *req; \ +@@ -110,6 +116,7 @@ struct cache_req_test_ctx { + struct sss_test_ctx *tctx; + struct resp_ctx *rctx; + struct sss_nc_ctx *ncache; ++ struct sss_domain_info *subdomain; + + struct cache_req_result *result; + bool dp_called; +@@ -120,6 +127,8 @@ struct cache_req_test_ctx { + bool create_user2; + bool create_group1; + bool create_group2; ++ bool create_subgroup1; ++ bool create_subuser1; + }; + + const char *domains[] = {"responder_cache_req_test_a", +@@ -128,6 +137,8 @@ const char *domains[] = {"responder_cache_req_test_a", + "responder_cache_req_test_d", + NULL}; + ++const char *subdomain_name = "responder_cache_req_test_a_sub"; ++ + struct cli_protocol_version *register_cli_protocol_version(void) + { + static struct cli_protocol_version version[] = { +@@ -487,6 +498,26 @@ __wrap_sss_dp_get_account_send(TALLOC_CTX *mem_ctx, + prepare_group(ctx->tctx->dom, &groups[1], 1000, time(NULL)); + } + ++ if (ctx->create_subgroup1) { ++ struct sss_domain_info *domain = NULL; ++ ++ domain = find_domain_by_name(ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_group(domain, &groups[0], 1000, time(NULL)); ++ } ++ ++ if (ctx->create_subuser1) { ++ struct sss_domain_info *domain = NULL; ++ ++ domain = find_domain_by_name(ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_user(domain, &users[0], 1000, time(NULL)); ++ } ++ + return test_req_succeed_send(mem_ctx, rctx->ev); + } + +@@ -581,6 +612,67 @@ static int test_multi_domain_teardown(void **state) + return 0; + } + ++static int test_subdomain_setup(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ int ret; ++ const char *const testdom[4] = { subdomain_name, "TEST_A.SUB", "test_a", "S-3" }; ++ ++ assert_true(leak_check_setup()); ++ ++ test_dom_suite_setup(TESTS_PATH); ++ ++ test_ctx = talloc_zero(global_talloc_context, struct cache_req_test_ctx); ++ assert_non_null(test_ctx); ++ *state = test_ctx; ++ ++ test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, TEST_CONF_DB, ++ TEST_DOM_NAME, TEST_ID_PROVIDER, NULL); ++ assert_non_null(test_ctx->tctx); ++ ++ test_ctx->rctx = mock_rctx(test_ctx, test_ctx->tctx->ev, ++ test_ctx->tctx->dom, NULL); ++ assert_non_null(test_ctx->rctx); ++ ++ ret = sss_ncache_init(test_ctx, 10, 0, &test_ctx->ncache); ++ assert_int_equal(ret, EOK); ++ ++ test_ctx->subdomain = new_subdomain(test_ctx, test_ctx->tctx->dom, ++ testdom[0], testdom[1], testdom[2], testdom[3], ++ false, false, NULL, NULL, 0, ++ test_ctx->tctx->confdb); ++ assert_non_null(test_ctx->subdomain); ++ ++ ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, ++ testdom[0], testdom[1], testdom[2], testdom[3], ++ false, false, NULL, 0, NULL); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom, ++ test_ctx->tctx->confdb); ++ assert_int_equal(ret, EOK); ++ ++ *state = test_ctx; ++ check_leaks_push(test_ctx); ++ return 0; ++} ++ ++static int test_subdomain_teardown(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ talloc_zfree(test_ctx->result); ++ talloc_zfree(test_ctx->rctx->cr_domains); ++ ++ assert_true(check_leaks_pop(test_ctx)); ++ talloc_zfree(test_ctx); ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); ++ assert_true(leak_check_teardown()); ++ return 0; ++} ++ + void test_user_by_name_multiple_domains_found(void **state) + { + struct cache_req_test_ctx *test_ctx = NULL; +@@ -974,6 +1066,7 @@ void test_user_by_id_multiple_domains_found(void **state) + /* Mock values. */ + will_return_always(__wrap_sss_dp_get_account_send, test_ctx); + will_return_always(sss_dp_req_recv, 0); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); + + /* Test. */ + run_user_by_id(test_ctx, NULL, 0, ERR_OK); +@@ -990,12 +1083,317 @@ void test_user_by_id_multiple_domains_notfound(void **state) + /* Mock values. */ + will_return_always(__wrap_sss_dp_get_account_send, test_ctx); + will_return_always(sss_dp_req_recv, 0); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); + + /* Test. */ + run_user_by_id(test_ctx, NULL, 0, ENOENT); + assert_true(test_ctx->dp_called); + } + ++void test_user_by_id_multiple_domains_locator_cache_valid(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d"); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ "responder_cache_req_test_d", true); ++ assert_non_null(domain); ++ prepare_user(domain, &users[0], 1000, time(NULL)); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); ++ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, EOK); ++ ++ /* Test. */ ++ run_user_by_id(test_ctx, NULL, 0, ERR_OK); ++ /* Even though the locator tells us to skip all domains except d, the domains ++ * are standalone and the result of the locator request is only valid within ++ * the subdomains ++ */ ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_user_by_id_multiple_domains_locator_cache_expired(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d"); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ "responder_cache_req_test_d", true); ++ assert_non_null(domain); ++ prepare_user(domain, &users[0], -1000, time(NULL)); ++ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, EOK); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); ++ ++ /* Test. */ ++ run_user_by_id(test_ctx, NULL, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_user_by_id_sub_domains_locator_cache_valid(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_user(domain, &users[0], 1000, time(NULL)); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_user_by_id(test_ctx, NULL, 0, ERR_OK); ++ ++ /* Even though the ID is present in the last domain, ++ * we're not calling sss_dp_get_account_send, ++ * because the locator will cause cache_req to skip ++ * all domains except _d ++ */ ++ assert_false(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_user_by_id_sub_domains_locator_cache_expired(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_user(domain, &users[0], -1000, time(NULL)); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_user_by_id(test_ctx, NULL, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_user_by_id_sub_domains_locator_cache_midpoint(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_user(domain, &users[0], 50, time(NULL) - 26); ++ ++ /* Note - DP will only be called once and we're not waiting ++ * for the results (so, we're not mocking _recv) ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_user_by_id(test_ctx, NULL, 50, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_user_by_id_sub_domains_locator_missing_found(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ test_ctx->create_subuser1 = true; ++ run_user_by_id(test_ctx, NULL, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_user_by_id_sub_domains_locator_missing_notfound(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND); ++ ++ /* Test. */ ++ run_user_by_id(test_ctx, NULL, 0, ENOENT); ++ assert_false(test_ctx->dp_called); ++} ++ ++void test_user_by_id_sub_domains_locator_cache_expired_two_calls(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ test_ctx->create_subuser1 = true; ++ prepare_user(domain, &users[0], -1000, time(NULL)); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_user_by_id(test_ctx, NULL, 0, ERR_OK); ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ /* Request the same user again */ ++ test_ctx->tctx->done = false; ++ talloc_zfree(test_ctx->result); ++ ++ run_user_by_id(test_ctx, NULL, 0, ERR_OK); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ + void test_user_by_id_cache_valid(void **state) + { + struct cache_req_test_ctx *test_ctx = NULL; +@@ -1332,6 +1730,7 @@ void test_group_by_id_multiple_domains_found(void **state) + /* Mock values. */ + will_return_always(__wrap_sss_dp_get_account_send, test_ctx); + will_return_always(sss_dp_req_recv, 0); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); + + /* Test. */ + run_group_by_id(test_ctx, NULL, 0, ERR_OK); +@@ -1348,12 +1747,318 @@ void test_group_by_id_multiple_domains_notfound(void **state) + /* Mock values. */ + will_return_always(__wrap_sss_dp_get_account_send, test_ctx); + will_return_always(sss_dp_req_recv, 0); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); + + /* Test. */ + run_group_by_id(test_ctx, NULL, 0, ENOENT); + assert_true(test_ctx->dp_called); + } + ++void test_group_by_id_multiple_domains_locator_cache_valid(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d"); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ "responder_cache_req_test_d", true); ++ assert_non_null(domain); ++ prepare_group(domain, &groups[0], 1000, time(NULL)); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); ++ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, EOK); ++ ++ /* Test. */ ++ run_group_by_id(test_ctx, NULL, 0, ERR_OK); ++ ++ /* Even though the locator tells us to skip all domains except d, the domains ++ * are standalone and the result of the locator request is only valid within ++ * the subdomains ++ */ ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_group_by_id_multiple_domains_locator_cache_expired(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d"); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ "responder_cache_req_test_d", true); ++ assert_non_null(domain); ++ prepare_group(domain, &groups[0], -1000, time(NULL)); ++ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, EOK); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); ++ ++ /* Test. */ ++ run_group_by_id(test_ctx, NULL, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_group_by_id_sub_domains_locator_cache_valid(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_group(domain, &groups[0], 1000, time(NULL)); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_group_by_id(test_ctx, NULL, 0, ERR_OK); ++ ++ /* Even though the ID is present in the last domain, ++ * we're not calling sss_dp_get_account_send, ++ * because the locator will cause cache_req to skip ++ * all domains except _d ++ */ ++ assert_false(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_group_by_id_sub_domains_locator_cache_expired(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_group(domain, &groups[0], -1000, time(NULL)); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_group_by_id(test_ctx, NULL, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_group_by_id_sub_domains_locator_cache_midpoint(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_group(domain, &groups[0], 50, time(NULL) - 26); ++ ++ /* Note - DP will only be called once and we're not waiting ++ * for the results (so, we're not mocking _recv) ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_group_by_id(test_ctx, NULL, 50, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_group_by_id_sub_domains_locator_missing_found(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ test_ctx->create_subgroup1 = true; ++ run_group_by_id(test_ctx, NULL, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_group_by_id_sub_domains_locator_missing_notfound(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND); ++ ++ /* Test. */ ++ run_group_by_id(test_ctx, NULL, 0, ENOENT); ++ assert_false(test_ctx->dp_called); ++} ++ ++void test_group_by_id_sub_domains_locator_cache_expired_two_calls(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ test_ctx->create_subgroup1 = true; ++ prepare_group(domain, &groups[0], -1000, time(NULL)); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_group_by_id(test_ctx, NULL, 0, ERR_OK); ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ /* Request the same group again */ ++ test_ctx->tctx->done = false; ++ talloc_zfree(test_ctx->result); ++ ++ run_group_by_id(test_ctx, NULL, 0, ERR_OK); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ + void test_group_by_id_cache_valid(void **state) + { + struct cache_req_test_ctx *test_ctx = NULL; +@@ -2311,6 +3016,7 @@ void test_object_by_id_user_multiple_domains_found(void **state) + /* Mock values. */ + will_return_always(__wrap_sss_dp_get_account_send, test_ctx); + will_return_always(sss_dp_req_recv, 0); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); + + /* Test. */ + run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK); +@@ -2328,6 +3034,7 @@ void test_object_by_id_user_multiple_domains_notfound(void **state) + /* Mock values. */ + will_return_always(__wrap_sss_dp_get_account_send, test_ctx); + will_return_always(sss_dp_req_recv, 0); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); + + /* Test. */ + run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT); +@@ -2476,6 +3183,7 @@ void test_object_by_id_group_multiple_domains_found(void **state) + /* Mock values. */ + will_return_always(__wrap_sss_dp_get_account_send, test_ctx); + will_return_always(sss_dp_req_recv, 0); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); + + /* Test. */ + run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK); +@@ -2493,12 +3201,641 @@ void test_object_by_id_group_multiple_domains_notfound(void **state) + /* Mock values. */ + will_return_always(__wrap_sss_dp_get_account_send, test_ctx); + will_return_always(sss_dp_req_recv, 0); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); + + /* Test. */ + run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT); + assert_true(test_ctx->dp_called); + } + ++void test_object_by_id_user_multiple_domains_locator_cache_valid(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d"); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ "responder_cache_req_test_d", true); ++ assert_non_null(domain); ++ prepare_user(domain, &users[0], 1000, time(NULL)); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); ++ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, EOK); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK); ++ /* Even though the locator tells us to skip all domains except d, the domains ++ * are standalone and the result of the locator request is only valid within ++ * the subdomains ++ */ ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_user_multiple_domains_locator_cache_expired(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d"); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ "responder_cache_req_test_d", true); ++ assert_non_null(domain); ++ prepare_user(domain, &users[0], -1000, time(NULL)); ++ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, EOK); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_user_sub_domains_locator_cache_valid(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_user(domain, &users[0], 1000, time(NULL)); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK); ++ ++ /* Even though the ID is present in the last domain, ++ * we're not calling sss_dp_get_account_send, ++ * because the locator will cause cache_req to skip ++ * all domains except _d ++ */ ++ assert_false(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_user_sub_domains_locator_cache_expired(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_user(domain, &users[0], -1000, time(NULL)); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_user_sub_domains_locator_cache_midpoint(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_user(domain, &users[0], 50, time(NULL) - 26); ++ ++ /* Note - DP will only be called once and we're not waiting ++ * for the results (so, we're not mocking _recv) ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 50, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_user_sub_domains_locator_missing_found(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ test_ctx->create_subuser1 = true; ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_user_sub_domains_locator_missing_notfound(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND); ++ ++ /* The test won't even ask the DP for the object, just iterate ++ * over the domains using the negative cache and quit ++ */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT); ++ assert_false(test_ctx->dp_called); ++} ++ ++void test_object_by_id_user_sub_domains_locator_cache_expired_two_calls(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup user. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ test_ctx->create_subuser1 = true; ++ prepare_user(domain, &users[0], -1000, time(NULL)); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, EOK); ++ assert_true(test_ctx->dp_called); ++ check_user(test_ctx, &users[0], domain); ++ ++ /* Request the same user again */ ++ test_ctx->tctx->done = false; ++ talloc_zfree(test_ctx->result); ++ ++ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, EOK); ++ check_user(test_ctx, &users[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_group_multiple_domains_locator_cache_valid(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d"); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ "responder_cache_req_test_d", true); ++ assert_non_null(domain); ++ prepare_group(domain, &groups[0], 1000, time(NULL)); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); ++ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, EOK); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK); ++ /* Even though the locator tells us to skip all domains except d, the domains ++ * are standalone and the result of the locator request is only valid within ++ * the subdomains ++ */ ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_group_multiple_domains_locator_cache_expired(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d"); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ "responder_cache_req_test_d", true); ++ assert_non_null(domain); ++ prepare_group(domain, &groups[0], -1000, time(NULL)); ++ ++ will_return_always(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, EOK); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_group_sub_domains_locator_cache_valid(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_group(domain, &groups[0], 1000, time(NULL)); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK); ++ ++ /* Even though the ID is present in the last domain, ++ * we're not calling sss_dp_get_account_send, ++ * because the locator will cause cache_req to skip ++ * all domains except _d ++ */ ++ assert_false(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_group_sub_domains_locator_cache_expired(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_group(domain, &groups[0], -1000, time(NULL)); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_group_sub_domains_locator_cache_midpoint(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ prepare_group(domain, &groups[0], 50, time(NULL) - 26); ++ ++ /* Note - DP will only be called once and we're not waiting ++ * for the results (so, we're not mocking _recv) ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 50, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_group_sub_domains_locator_missing_found(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ test_ctx->create_subgroup1 = true; ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK); ++ ++ assert_true(test_ctx->dp_called); ++ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_object_by_id_group_sub_domains_locator_missing_notfound(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND); ++ ++ /* The test won't even ask the DP for the object, just iterate ++ * over the domains using the negative cache and quit ++ */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT); ++ assert_false(test_ctx->dp_called); ++} ++ ++void test_object_by_id_group_sub_domains_locator_cache_expired_two_calls(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ struct sss_domain_info *domain = NULL; ++ const char *locator_domain; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = SYSDB_PW_ATTRS; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ tmp_ctx = talloc_new(test_ctx); ++ assert_non_null(tmp_ctx); ++ ++ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */ ++ locator_domain = talloc_strdup(tmp_ctx, subdomain_name); ++ assert_non_null(locator_domain); ++ ++ /* Setup group. */ ++ domain = find_domain_by_name(test_ctx->tctx->dom, ++ subdomain_name, ++ true); ++ assert_non_null(domain); ++ test_ctx->create_subgroup1 = true; ++ prepare_group(domain, &groups[0], -1000, time(NULL)); ++ ++ /* Note - DP will only be called once (so, we're not using will_return_always) ++ * because the locator will tell us which domain to look into. For the recv ++ * function, we use always b/c internally it mocks several values. ++ */ ++ will_return(__wrap_sss_dp_get_account_send, test_ctx); ++ will_return_always(sss_dp_req_recv, 0); ++ ++ will_return(sss_dp_get_account_domain_recv, EOK); ++ will_return(sss_dp_get_account_domain_recv, locator_domain); ++ ++ /* Test. */ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, EOK); ++ assert_true(test_ctx->dp_called); ++ check_group(test_ctx, &groups[0], domain); ++ ++ /* Request the same group again */ ++ test_ctx->tctx->done = false; ++ talloc_zfree(test_ctx->result); ++ ++ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, EOK); ++ check_group(test_ctx, &groups[0], domain); ++ ++ talloc_free(tmp_ctx); ++} ++ + int main(int argc, const char *argv[]) + { + poptContext pc; +@@ -2557,6 +3894,24 @@ int main(int argc, const char *argv[]) + new_multi_domain_test(group_by_id_multiple_domains_found), + new_multi_domain_test(group_by_id_multiple_domains_notfound), + ++ new_multi_domain_test(group_by_id_multiple_domains_locator_cache_valid), ++ new_multi_domain_test(group_by_id_multiple_domains_locator_cache_expired), ++ new_subdomain_test(group_by_id_sub_domains_locator_cache_valid), ++ new_subdomain_test(group_by_id_sub_domains_locator_cache_expired), ++ new_subdomain_test(group_by_id_sub_domains_locator_cache_midpoint), ++ new_subdomain_test(group_by_id_sub_domains_locator_missing_found), ++ new_subdomain_test(group_by_id_sub_domains_locator_missing_notfound), ++ new_subdomain_test(group_by_id_sub_domains_locator_cache_expired_two_calls), ++ ++ new_multi_domain_test(user_by_id_multiple_domains_locator_cache_valid), ++ new_multi_domain_test(user_by_id_multiple_domains_locator_cache_expired), ++ new_subdomain_test(user_by_id_sub_domains_locator_cache_valid), ++ new_subdomain_test(user_by_id_sub_domains_locator_cache_expired), ++ new_subdomain_test(user_by_id_sub_domains_locator_cache_midpoint), ++ new_subdomain_test(user_by_id_sub_domains_locator_missing_found), ++ new_subdomain_test(user_by_id_sub_domains_locator_missing_notfound), ++ new_subdomain_test(user_by_id_sub_domains_locator_cache_expired_two_calls), ++ + new_single_domain_test(user_by_recent_filter_valid), + new_single_domain_test(users_by_recent_filter_valid), + new_single_domain_test(group_by_recent_filter_valid), +@@ -2603,6 +3958,24 @@ int main(int argc, const char *argv[]) + new_single_domain_test(object_by_id_group_missing_notfound), + new_multi_domain_test(object_by_id_group_multiple_domains_found), + new_multi_domain_test(object_by_id_group_multiple_domains_notfound), ++ ++ new_multi_domain_test(object_by_id_user_multiple_domains_locator_cache_valid), ++ new_multi_domain_test(object_by_id_user_multiple_domains_locator_cache_expired), ++ new_subdomain_test(object_by_id_user_sub_domains_locator_cache_valid), ++ new_subdomain_test(object_by_id_user_sub_domains_locator_cache_expired), ++ new_subdomain_test(object_by_id_user_sub_domains_locator_cache_midpoint), ++ new_subdomain_test(object_by_id_user_sub_domains_locator_missing_found), ++ new_subdomain_test(object_by_id_user_sub_domains_locator_missing_notfound), ++ new_subdomain_test(object_by_id_user_sub_domains_locator_cache_expired_two_calls), ++ ++ new_multi_domain_test(object_by_id_group_multiple_domains_locator_cache_valid), ++ new_multi_domain_test(object_by_id_group_multiple_domains_locator_cache_expired), ++ new_subdomain_test(object_by_id_group_sub_domains_locator_cache_valid), ++ new_subdomain_test(object_by_id_group_sub_domains_locator_cache_expired), ++ new_subdomain_test(object_by_id_group_sub_domains_locator_cache_midpoint), ++ new_subdomain_test(object_by_id_group_sub_domains_locator_missing_found), ++ new_subdomain_test(object_by_id_group_sub_domains_locator_missing_notfound), ++ new_subdomain_test(object_by_id_group_sub_domains_locator_cache_expired_two_calls), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +-- +2.14.3 + diff --git a/SOURCES/0082-build-make-curl-required-by-secrets.patch b/SOURCES/0082-build-make-curl-required-by-secrets.patch deleted file mode 100644 index 0880b3c..0000000 --- a/SOURCES/0082-build-make-curl-required-by-secrets.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 1ea81a335baa08746df7daf2707c070271990937 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Wed, 22 Mar 2017 12:32:31 +0100 -Subject: [PATCH 82/90] build: make curl required by secrets -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Also remove --disable-libcurl since it doesn't make sense. - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit 793f2573b2beaf8b48eab850429482acf68ec2b1) ---- - configure.ac | 6 +++++- - src/external/libcurl.m4 | 16 ++-------------- - 2 files changed, 7 insertions(+), 15 deletions(-) - -diff --git a/configure.ac b/configure.ac -index cf5e2557ef0a1bd6374200aa33abea6c509d03aa..80d8ea9ff5785b0d76edbb04f454d0dd8c8a1e6d 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -201,9 +201,13 @@ if test x$with_secrets = xyes; then - fi - - if test x$with_kcm = xyes; then -- m4_include([src/external/libcurl.m4]) - m4_include([src/external/libuuid.m4]) - fi -+ -+if test x$with_kcm = xyes -o x$with_secrets = xyes; then -+ m4_include([src/external/libcurl.m4]) -+fi -+ - # This variable is defined by external/libcurl.m4, but conditionals - # must be always evaluated - AM_CONDITIONAL([BUILD_WITH_LIBCURL], -diff --git a/src/external/libcurl.m4 b/src/external/libcurl.m4 -index b420b04ad806bd1251f086b773ffe480d39f8bd3..42be308cd1e4b04e736daf887be9b75ea92db80e 100644 ---- a/src/external/libcurl.m4 -+++ b/src/external/libcurl.m4 -@@ -1,17 +1,5 @@ --AC_ARG_ENABLE([curl], -- [AS_HELP_STRING([--disable-curl-support], -- [do not build with libcurl support])], -- [enable_libcurl=$enableval], -- [enable_libcurl=yes]) -- --found_libcurl="no" --AS_IF([test x$enable_libcurl = xyes], -- [PKG_CHECK_MODULES([CURL], -- [libcurl], -- [found_libcurl=yes], -- [AC_MSG_ERROR([ --The libcurl development library was not found.]) -- ])]) -+PKG_CHECK_MODULES([CURL], [libcurl], [found_libcurl=yes], -+ [AC_MSG_ERROR([The libcurl development library was not found.])]) - - AS_IF([test x"$found_libcurl" = xyes], - CFLAGS="$CFLAGS $CURL_CFLAGS" --- -2.9.3 - diff --git a/SOURCES/0083-MAN-Document-how-the-Global-Catalog-is-used-currentl.patch b/SOURCES/0083-MAN-Document-how-the-Global-Catalog-is-used-currentl.patch new file mode 100644 index 0000000..4a339e0 --- /dev/null +++ b/SOURCES/0083-MAN-Document-how-the-Global-Catalog-is-used-currentl.patch @@ -0,0 +1,48 @@ +From 251e4914e55c6b66ab6eabd3b3e2e2b7b49029e3 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Sun, 19 Nov 2017 22:31:44 +0100 +Subject: [PATCH 83/83] MAN: Document how the Global Catalog is used currently +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The existing documentation was outdated. Remove it and document what the +current patchset adds. + +Related: +https://pagure.io/SSSD/sssd/issue/3468 + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +(cherry picked from commit a72919af8347b5bbc65a3b1fb3e5d31447240b24) +--- + src/man/sssd-ad.5.xml | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index 649042d587de3d3600fff59866681e302c721af8..c4a3fc2b5780eb0f15935a2c38f48418c5f7bb52 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -84,9 +84,16 @@ + + ldap_id_mapping = False + +- In order to retrieve users and groups using POSIX attributes from trusted +- domains, the AD administrator must make sure that the POSIX attributes +- are replicated to the Global Catalog. ++ If POSIX attributes should be used, it is recommended for ++ performance reasons that the attributes are also replicated ++ to the Global Catalog. If POSIX attributes are replicated, ++ SSSD will attempt to locate the domain of a requested ++ numerical ID with the help of the Global Catalog and only ++ search that domain. In contrast, if POSIX attributes are not ++ replicated to the Global Catalog, SSSD must search all the ++ domains in the forest sequentially. Please note that that the ++ cache_first option might be also helpful in ++ speeding up domainless searches. + + + Users, groups and other entities served by SSSD are always treated as +-- +2.14.3 + diff --git a/SOURCES/0083-secrets-use-tcurl-in-proxy-provider.patch b/SOURCES/0083-secrets-use-tcurl-in-proxy-provider.patch deleted file mode 100644 index 7292536..0000000 --- a/SOURCES/0083-secrets-use-tcurl-in-proxy-provider.patch +++ /dev/null @@ -1,459 +0,0 @@ -From a53c4afd13d92572b8c0ebb93d0dbe3f7c7bc680 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Wed, 22 Feb 2017 10:38:56 +0100 -Subject: [PATCH 83/90] secrets: use tcurl in proxy provider - -We switch from http-parser to libcurl for an http client. This gaves us many -features for free such as tls and http basic authentication support instead -of implementing it on our own. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3192 - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit df99d709c8cbef3c378c111944d83b7345e4c1ea) ---- - Makefile.am | 3 + - src/responder/secrets/providers.c | 20 +++ - src/responder/secrets/proxy.c | 246 ++++++++++++++++++++++----------- - src/responder/secrets/secsrv_private.h | 5 + - 4 files changed, 191 insertions(+), 83 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index 573b37c52fdeab1add4ea057e1e1844ea4d348a5..4a414f77df999b8b1d81f663fcc18dbd2d6d2dc4 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -1486,6 +1486,8 @@ sssd_secrets_SOURCES = \ - src/responder/secrets/local.c \ - src/responder/secrets/proxy.c \ - src/util/sss_sockets.c \ -+ src/util/sss_iobuf.c \ -+ src/util/tev_curl.c \ - $(SSSD_RESPONDER_OBJ) \ - $(SSSD_RESOLV_OBJ) \ - $(NULL) -@@ -1497,6 +1499,7 @@ sssd_secrets_LDADD = \ - $(SYSTEMD_DAEMON_LIBS) \ - $(CARES_LIBS) \ - $(SSSD_INTERNAL_LTLIBS) \ -+ $(CURL_LIBS) \ - $(NULL) - endif - -diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c -index 94831c73036d269addca45c0117811a2c68873fd..80a443d91135447ec8ce8d424b692a6d7e26a907 100644 ---- a/src/responder/secrets/providers.c -+++ b/src/responder/secrets/providers.c -@@ -22,6 +22,7 @@ - #include "responder/secrets/secsrv_private.h" - #include "responder/secrets/secsrv_local.h" - #include "responder/secrets/secsrv_proxy.h" -+#include "util/sss_iobuf.h" - #include - - typedef int (*url_mapper_fn)(struct sec_req_ctx *secreq, -@@ -387,6 +388,25 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply, - return EOK; - } - -+errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx, -+ struct sec_data *reply, -+ int response_code, -+ struct sss_iobuf *response) -+{ -+ DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d\n", response_code); -+ -+ reply->data = (char *)sss_iobuf_get_data(response); -+ reply->length = sss_iobuf_get_len(response); -+ -+ talloc_steal(mem_ctx, reply->data); -+ -+ if (reply->data == NULL) { -+ return EINVAL; -+ } -+ -+ return EOK; -+} -+ - enum sec_http_status_codes sec_errno_to_http_status(errno_t err) - { - DEBUG(SSSDBG_TRACE_LIBS, "Request errno: %d\n", err); -diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c -index 3ed03e6086d0de0f6f80de227ffc65ef4067db4f..fe2f0134e233d9a98f499fe563abe0af69762514 100644 ---- a/src/responder/secrets/proxy.c -+++ b/src/responder/secrets/proxy.c -@@ -23,10 +23,15 @@ - #include "util/crypto/sss_crypto.h" - #include "resolv/async_resolv.h" - #include "util/sss_sockets.h" -+#include "util/sss_iobuf.h" -+#include "util/tev_curl.h" -+ -+#define SEC_PROXY_TIMEOUT 5 - - struct proxy_context { - struct resolv_ctx *resctx; - struct confdb_ctx *cdb; -+ struct tcurl_ctx *tcurl; - }; - - enum proxy_auth_type { -@@ -216,103 +221,177 @@ int proxy_sec_map_url(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, - return EOK; - } - --int proxy_sec_map_headers(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, -- struct proxy_cfg *pcfg, char **req_headers) -+static errno_t proxy_http_append_header(TALLOC_CTX *mem_ctx, -+ const char *name, -+ const char *value, -+ const char ***_headers, -+ size_t *_num_headers) - { -- int ret; -- -- for (int i = 0; i < secreq->num_headers; i++) { -- bool forward = false; -- for (int j = 0; pcfg->fwd_headers[j]; j++) { -- if (strcasecmp(secreq->headers[i].name, -- pcfg->fwd_headers[j]) == 0) { -- forward = true; -+ const char **headers = *_headers; -+ size_t num_headers = *_num_headers; -+ -+ num_headers++; -+ headers = talloc_realloc(mem_ctx, headers, const char *, -+ num_headers + 1); -+ if (headers == NULL) { -+ return ENOMEM; -+ } -+ -+ headers[num_headers - 1] = talloc_asprintf(headers, "%s: %s", name, value); -+ if (headers[num_headers - 1] == NULL) { -+ return ENOMEM; -+ } -+ -+ headers[num_headers] = NULL; -+ -+ *_headers = headers; -+ *_num_headers = num_headers; -+ -+ return EOK; -+} -+ -+static const char ** -+proxy_http_create_headers(TALLOC_CTX *mem_ctx, -+ struct sec_req_ctx *secreq, -+ struct proxy_cfg *pcfg) -+{ -+ TALLOC_CTX *tmp_ctx; -+ const char **headers; -+ size_t num_headers; -+ errno_t ret; -+ int i, j; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); -+ return NULL; -+ } -+ -+ headers = talloc_zero_array(tmp_ctx, const char *, 1); -+ if (headers == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ num_headers = 0; -+ for (i = 0; i < secreq->num_headers; i++) { -+ for (j = 0; pcfg->fwd_headers[j]; j++) { -+ if (strcasecmp(secreq->headers[i].name, pcfg->fwd_headers[j]) == 0) { -+ DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s: %s\n", -+ secreq->headers[i].name, secreq->headers[i].value); -+ -+ ret = proxy_http_append_header(tmp_ctx, secreq->headers[i].name, -+ secreq->headers[i].value, -+ &headers, &num_headers); -+ if (ret != EOK) { -+ goto done; -+ } -+ - break; - } - } -- if (forward) { -- DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s:%s\n", -- secreq->headers[i].name, secreq->headers[i].value); -- -- ret = sec_http_append_header(mem_ctx, req_headers, -- secreq->headers[i].name, -- secreq->headers[i].value); -- if (ret) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Couldn't append header %s\n", secreq->headers[i].name); -- return ret; -- } -- } - } - - if (pcfg->auth_type == PAT_HEADER) { -- DEBUG(SSSDBG_TRACE_LIBS, -- "Forwarding header %s\n", pcfg->auth.header.name); -+ DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s\n", -+ pcfg->auth.header.name); - -- ret = sec_http_append_header(mem_ctx, req_headers, -- pcfg->auth.header.name, -- pcfg->auth.header.value); -- if (ret) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Couldn't append header %s\n", pcfg->auth.header.name); -- return ret; -+ ret = proxy_http_append_header(tmp_ctx, pcfg->auth.header.name, -+ pcfg->auth.header.value, -+ &headers, &num_headers); -+ if (ret != EOK) { -+ goto done; - } - } - -- return EOK; -+ talloc_steal(mem_ctx, headers); -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ -+ if (ret != EOK) { -+ return NULL; -+ } -+ -+ return headers; - } - --static int proxy_http_create_request(TALLOC_CTX *mem_ctx, -- struct sec_req_ctx *secreq, -- struct proxy_cfg *pcfg, -- const char *http_uri, -- struct sec_data **http_req) -+static errno_t proxy_http_create_request(TALLOC_CTX *mem_ctx, -+ struct sec_req_ctx *secreq, -+ struct proxy_cfg *pcfg, -+ const char *url, -+ struct tcurl_request **_tcurl_req) - { -- struct sec_data *req; -- int ret; -+ TALLOC_CTX *tmp_ctx; -+ struct tcurl_request *tcurl_req; -+ enum tcurl_http_method method; -+ struct sss_iobuf *body; -+ const char **headers; -+ errno_t ret; - -- req = talloc_zero(mem_ctx, struct sec_data); -- if (!req) return ENOMEM; -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); -+ return ENOMEM; -+ } - -- /* Request-Line */ -- req->data = talloc_asprintf(req, "%s %s HTTP/1.1\r\n", -- http_method_str(secreq->method), http_uri); -- if (!req->data) { -+ headers = proxy_http_create_headers(tmp_ctx, secreq, pcfg); -+ if (headers == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to construct HTTP headers!\n"); - ret = ENOMEM; - goto done; - } - -- /* Headers */ -- ret = proxy_sec_map_headers(req, secreq, pcfg, &req->data); -- if (ret) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't map headers\n"); -+ body = sss_iobuf_init_readonly(tmp_ctx, (uint8_t *)secreq->body.data, -+ secreq->body.length); -+ if (body == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create HTTP body!\n"); -+ ret = ENOMEM; - goto done; - } - -- /* CRLF separator before body */ -- req->data = talloc_strdup_append_buffer(req->data, "\r\n"); -- -- req->length = strlen(req->data); -+ switch (secreq->method) { -+ case HTTP_GET: -+ method = TCURL_HTTP_GET; -+ break; -+ case HTTP_PUT: -+ method = TCURL_HTTP_PUT; -+ break; -+ case HTTP_POST: -+ method = TCURL_HTTP_POST; -+ break; -+ case HTTP_DELETE: -+ method = TCURL_HTTP_DELETE; -+ break; -+ default: -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected HTTP method: %d\n", -+ secreq->method); -+ ret = EINVAL; -+ goto done; -+ } - -- /* Message-Body */ -- if (secreq->body.length > 0) { -- req->data = talloc_realloc_size(req, req->data, -- req->length + secreq->body.length); -- if (!req->data) { -- ret = ENOMEM; -- goto done; -- } -+ tcurl_req = tcurl_http(tmp_ctx, method, NULL, url, headers, body); -+ if (tcurl_req == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create TCURL request!\n"); -+ ret = ENOMEM; -+ goto done; -+ } - -- memcpy(&req->data[req->length], -- secreq->body.data, secreq->body.length); -- req->length += secreq->body.length; -+ /* TCURL will return response buffer also with headers. */ -+ ret = tcurl_req_enable_rawoutput(tcurl_req); -+ if (ret != EOK) { -+ goto done; - } - -- *http_req = req; -+ talloc_steal(tcurl_req, body); -+ *_tcurl_req = talloc_steal(mem_ctx, tcurl_req); -+ - ret = EOK; - - done: -- if (ret) talloc_free(req); -+ talloc_free(tmp_ctx); - return ret; - } - -@@ -911,8 +990,8 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx, - { - struct tevent_req *req, *subreq; - struct proxy_secret_state *state; -+ struct tcurl_request *tcurl_req; - struct proxy_context *pctx; -- struct sec_data *http_req; - char *http_uri; - int ret; - -@@ -942,9 +1021,8 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx, - goto done; - } - -- - ret = proxy_http_create_request(state, state->secreq, state->pcfg, -- http_uri, &http_req); -+ http_uri, &tcurl_req); - if (ret) { - DEBUG(SSSDBG_CRIT_FAILURE, - "proxy_http_create_request failed [%d]: %s\n", -@@ -952,10 +1030,9 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx, - goto done; - } - -- -- subreq = proxy_http_req_send(pctx, state, ev, state->secreq, -- http_uri, http_req); -- if (!subreq) { -+ subreq = tcurl_request_send(mem_ctx, ev, pctx->tcurl, tcurl_req, -+ SEC_PROXY_TIMEOUT); -+ if (subreq == NULL) { - ret = ENOMEM; - goto done; - } -@@ -981,32 +1058,30 @@ static void proxy_secret_req_done(struct tevent_req *subreq) - { - struct tevent_req *req; - struct proxy_secret_state *state; -- struct proxy_http_reply *reply = NULL; -+ struct sss_iobuf *response; -+ int http_code; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct proxy_secret_state); - -- ret = proxy_http_req_recv(subreq, state, &reply); -+ ret = tcurl_request_recv(state, subreq, &response, &http_code); - talloc_zfree(subreq); - - if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "proxy_http request failed [%d]: %s\n", -+ DEBUG(SSSDBG_OP_FAILURE, "proxy_http request failed [%d]: %s\n", - ret, sss_strerror(ret)); - tevent_req_error(req, ret); - return; - } - -- ret = sec_http_reply_with_headers(state->secreq, &state->secreq->reply, -- reply->status_code, reply->reason_phrase, -- reply->headers, reply->num_headers, -- &reply->body); -+ ret = sec_http_reply_iobuf(state->secreq, &state->secreq->reply, -+ http_code, response); - if (ret == EOK) { - tevent_req_done(req); - } else { - DEBUG(SSSDBG_OP_FAILURE, -- "sec_http_reply_with_headers request failed [%d]: %s\n", -+ "sec_http_reply_iobuf request failed [%d]: %s\n", - ret, sss_strerror(ret)); - tevent_req_error(req, ret); - } -@@ -1034,6 +1109,11 @@ int proxy_secrets_provider_handle(struct sec_ctx *sctx, - - pctx->resctx = sctx->resctx; - pctx->cdb = sctx->rctx->cdb; -+ pctx->tcurl = tcurl_init(pctx, sctx->rctx->ev); -+ if (pctx->tcurl == NULL) { -+ talloc_free(pctx); -+ return ENOMEM; -+ } - - handle->context = pctx; - -diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h -index a8544f656517a17fe4576247779bff4850beaf97..2e68628f61a0a8e79cd48fb5a510221e6fc36c70 100644 ---- a/src/responder/secrets/secsrv_private.h -+++ b/src/responder/secrets/secsrv_private.h -@@ -25,6 +25,7 @@ - #include "config.h" - #include "responder/common/responder.h" - #include "responder/secrets/secsrv.h" -+#include "util/sss_iobuf.h" - #include - - struct sec_kvp { -@@ -129,6 +130,10 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply, - int status_code, const char *reason, - struct sec_kvp *headers, int num_headers, - struct sec_data *body); -+errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx, -+ struct sec_data *reply, -+ int response_code, -+ struct sss_iobuf *response); - enum sec_http_status_codes sec_errno_to_http_status(errno_t err); - - int sec_json_to_simple_secret(TALLOC_CTX *mem_ctx, --- -2.9.3 - diff --git a/SOURCES/0084-p11_child-make-sure-OCSP-checks-are-done.patch b/SOURCES/0084-p11_child-make-sure-OCSP-checks-are-done.patch new file mode 100644 index 0000000..e2b497f --- /dev/null +++ b/SOURCES/0084-p11_child-make-sure-OCSP-checks-are-done.patch @@ -0,0 +1,54 @@ +From 62275e72ff0b9849c899f0fecea90731fff9da0a Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 7 Dec 2017 17:08:33 +0100 +Subject: [PATCH 84/86] p11_child: make sure OCSP checks are done +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If CERT_VerifyCertificateNow() is used with +'certificateUsageCheckAllUsages' OCSP checks are skipped even if OCSP +was enabled. + +This patch calls CERT_CheckOCSPStatus() explicitly if OCSP checks are +enabled. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 2297cc7d6cd5c38a7d64027165e4e82ca497f418) +--- + src/p11_child/p11_child_nss.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index 21c508eb1b1b68b3606d0a5eed36573b01f27a19..bf533f3efe4d680f4c6dbd10a0d2c5a5da371c67 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -338,6 +338,23 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + PR_GetError(), PORT_ErrorToString(PR_GetError())); + continue; + } ++ ++ /* with 'certificateUsageCheckAllUsages' set ++ * CERT_VerifyCertificateNow() does not do OCSP so it must be done ++ * explicitly */ ++ if (cert_verify_opts->do_ocsp) { ++ rv = CERT_CheckOCSPStatus(handle, cert_list_node->cert, ++ PR_Now(), NULL); ++ if (rv != SECSuccess) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Certificate [%s][%s] failed OCSP check [%d][%s], " ++ "skipping.\n", ++ cert_list_node->cert->nickname, ++ cert_list_node->cert->subjectName, ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); ++ continue; ++ } ++ } + } + + if (key_id_in != NULL) { +-- +2.14.3 + diff --git a/SOURCES/0084-secrets-remove-http-parser-code-in-proxy-provider.patch b/SOURCES/0084-secrets-remove-http-parser-code-in-proxy-provider.patch deleted file mode 100644 index 7245f94..0000000 --- a/SOURCES/0084-secrets-remove-http-parser-code-in-proxy-provider.patch +++ /dev/null @@ -1,612 +0,0 @@ -From cfb82199afe237b4e892aaf2816db63279d7cb21 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 28 Feb 2017 14:14:40 +0100 -Subject: [PATCH 84/90] secrets: remove http-parser code in proxy provider - -We switche to libcurl in previous patch. This just removes the unused code. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3192 - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit 06744bf5a47d5971a338281c8243b11cf72dac90) ---- - src/responder/secrets/proxy.c | 581 ------------------------------------------ - 1 file changed, 581 deletions(-) - -diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c -index fe2f0134e233d9a98f499fe563abe0af69762514..3c495716010ac468c9e2f1fb6356529a8dbdc614 100644 ---- a/src/responder/secrets/proxy.c -+++ b/src/responder/secrets/proxy.c -@@ -395,587 +395,6 @@ done: - return ret; - } - --struct proxy_http_request { -- struct sec_data *data; -- size_t written; --}; -- --struct proxy_http_reply { -- http_parser parser; -- bool complete; -- -- int status_code; -- char *reason_phrase; -- struct sec_kvp *headers; -- int num_headers; -- struct sec_data body; -- -- size_t received; --}; -- --struct proxy_http_req_state { -- struct tevent_context *ev; -- -- char *proxyname; -- int port; -- -- struct resolv_hostent *hostent; -- int hostidx; -- -- int sd; -- struct tevent_fd *fde; -- -- struct proxy_http_request request; -- struct proxy_http_reply *reply; --}; -- --static int proxy_http_req_state_destroy(void *data); --static void proxy_http_req_gethostname_done(struct tevent_req *subreq); --static void proxy_http_req_connect_step(struct tevent_req *req); --static void proxy_http_req_connect_done(struct tevent_req *subreq); --static void proxy_fd_handler(struct tevent_context *ev, struct tevent_fd *fde, -- uint16_t flags, void *ptr); -- --struct tevent_req *proxy_http_req_send(struct proxy_context *pctx, -- TALLOC_CTX *mem_ctx, -- struct tevent_context *ev, -- struct sec_req_ctx *secreq, -- const char *http_uri, -- struct sec_data *http_req) --{ -- struct proxy_http_req_state *state; -- struct http_parser_url parsed; -- struct tevent_req *req, *subreq; -- int ret; -- -- req = tevent_req_create(mem_ctx, &state, struct proxy_http_req_state); -- if (!req) return NULL; -- -- state->ev = ev; -- state->request.data = http_req; -- state->sd = -1; -- talloc_set_destructor((TALLOC_CTX *)state, -- proxy_http_req_state_destroy); -- -- /* STEP1: reparse URL to get hostname and port */ -- ret = http_parser_parse_url(http_uri, strlen(http_uri), 0, &parsed); -- if (ret) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse URL [%s]: %d: %s\n", -- http_uri, ret, sss_strerror(ret)); -- goto done; -- } -- -- if (!(parsed.field_set & (1 << UF_HOST))) { -- DEBUG(SSSDBG_CRIT_FAILURE, "No UF_HOST flag found\n"); -- ret = EINVAL; -- goto done; -- } -- state->proxyname = -- talloc_strndup(state, -- &http_uri[parsed.field_data[UF_HOST].off], -- parsed.field_data[UF_HOST].len); -- if (!state->proxyname) { -- ret = ENOMEM; -- goto done; -- } -- DEBUG(SSSDBG_TRACE_LIBS, "proxy name: %s\n", state->proxyname); -- -- if (parsed.field_set & (1 << UF_PORT)) { -- state->port = parsed.port; -- } else if (parsed.field_set & (1 << UF_SCHEMA)) { -- uint16_t off = parsed.field_data[UF_SCHEMA].off; -- uint16_t len = parsed.field_data[UF_SCHEMA].len; -- -- if ((len == 5) && -- (strncmp("https", &http_uri[off], len) == 0)) { -- state->port = 443; -- } else if ((len == 4) && -- (strncmp("http", &http_uri[off], len) == 0)) { -- state->port = 80; -- } -- } -- DEBUG(SSSDBG_TRACE_LIBS, "proxy port: %d\n", state->port); -- -- /* STEP2: resolve hostname first */ -- subreq = resolv_gethostbyname_send(state, ev, pctx->resctx, -- state->proxyname, IPV4_FIRST, -- default_host_dbs); -- if (subreq == NULL) { -- ret = ENOMEM; -- goto done; -- } -- -- tevent_req_set_callback(subreq, proxy_http_req_gethostname_done, req); -- -- return req; -- --done: -- if (ret == EOK) { -- tevent_req_done(req); -- } else { -- tevent_req_error(req, ret); -- } -- tevent_req_post(req, ev); -- -- return req; --} -- --static void proxy_http_req_gethostname_done(struct tevent_req *subreq) --{ -- struct tevent_req *req; -- struct proxy_http_req_state *state; -- int resolv_status; -- int ret; -- -- req = tevent_req_callback_data(subreq, struct tevent_req); -- state = tevent_req_data(req, struct proxy_http_req_state); -- -- ret = resolv_gethostbyname_recv(subreq, state, &resolv_status, NULL, -- &state->hostent); -- talloc_zfree(subreq); -- if (ret != EOK) { -- if (ret == ENOENT) { -- /* Empty result, just quit */ -- DEBUG(SSSDBG_TRACE_INTERNAL, "No hostent found\n"); -- } else { -- DEBUG(SSSDBG_OP_FAILURE, -- "Could not resolve fqdn for this machine, error [%d]: %s, " -- "resolver returned: [%d]: %s\n", ret, strerror(ret), -- resolv_status, resolv_strerror(resolv_status)); -- } -- goto done; -- } -- -- /* EOK */ -- DEBUG(SSSDBG_TRACE_INTERNAL, "Found fqdn: %s\n", state->hostent->name); -- -- /* STEP3: connect to one of the servers */ -- proxy_http_req_connect_step(req); -- return; -- --done: -- if (ret == EOK) { -- tevent_req_done(req); -- } else { -- tevent_req_error(req, ret); -- } --} -- --static void proxy_http_req_connect_step(struct tevent_req *req) --{ -- struct proxy_http_req_state *state; -- struct sockaddr_storage *sockaddr; -- char *ipaddr; -- struct tevent_req *subreq; -- int ret; -- -- state = tevent_req_data(req, struct proxy_http_req_state); -- -- if (!state->hostent->addr_list[state->hostidx]) { -- DEBUG(SSSDBG_CRIT_FAILURE, "No more addresses to try.\n"); -- ret = ERR_SEC_NO_PROXY; -- goto done; -- } -- -- sockaddr = resolv_get_sockaddr_address_index(state, state->hostent, -- state->port, state->hostidx); -- if (sockaddr == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "resolv_get_sockaddr_address() failed\n"); -- ret = EIO; -- goto done; -- } -- -- if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) { -- ipaddr = resolv_get_string_address_index(state, state->hostent, -- state->hostidx); -- if (!ipaddr) { -- ret = EFAULT; -- goto done; -- } -- DEBUG(SSSDBG_TRACE_FUNC, "Connecting to %s:%d\n", -- ipaddr, state->port); -- } -- -- /* increase idx for next attempt */ -- state->hostidx++; -- -- subreq = sssd_async_socket_init_send(state, state->ev, sockaddr, -- sizeof(struct sockaddr_storage), -- SEC_NET_TIMEOUT); -- if (!subreq) { -- ret = EIO; -- goto done; -- } -- tevent_req_set_callback(subreq, proxy_http_req_connect_done, req); -- return; -- --done: -- if (ret == EOK) { -- tevent_req_done(req); -- } else { -- tevent_req_error(req, ret); -- } --} -- --static void proxy_http_req_connect_done(struct tevent_req *subreq) --{ -- struct tevent_req *req; -- struct proxy_http_req_state *state; -- int ret; -- -- req = tevent_req_callback_data(subreq, struct tevent_req); -- state = tevent_req_data(req, struct proxy_http_req_state); -- -- ret = sssd_async_socket_init_recv(subreq, &state->sd); -- talloc_zfree(subreq); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "sssd_async_socket_init request failed: [%d]: %s.\n", -- ret, sss_strerror(ret)); -- -- /* try next server if any */ -- proxy_http_req_connect_step(req); -- return; -- } -- -- /* EOK */ -- DEBUG(SSSDBG_TRACE_FUNC, "Connected to %s\n", state->hostent->name); -- -- state->fde = tevent_add_fd(state->ev, state, state->sd, -- TEVENT_FD_WRITE, proxy_fd_handler, -- req); -- if (!state->fde) { -- ret = EIO; -- goto done; -- } -- -- return; -- --done: -- if (ret == EOK) { -- tevent_req_done(req); -- } else { -- tevent_req_error(req, ret); -- } --} -- -- --int proxy_http_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, -- struct proxy_http_reply **reply) --{ -- struct proxy_http_req_state *state = -- tevent_req_data(req, struct proxy_http_req_state); -- -- TEVENT_REQ_RETURN_ON_ERROR(req); -- -- *reply = talloc_move(mem_ctx, &state->reply); -- -- return EOK; --} -- --static int proxy_http_req_state_destroy(void *data) --{ -- struct proxy_http_req_state *state = -- talloc_get_type(data, struct proxy_http_req_state); -- -- if (!state) return 0; -- -- if (state->sd != -1) { -- DEBUG(SSSDBG_TRACE_FUNC, "closing socket [%d]\n", state->sd); -- close(state->sd); -- state->sd = -1; -- } -- -- return 0; --} -- --static int proxy_wire_send(int fd, struct proxy_http_request *req) --{ -- struct sec_data data; -- int ret; -- -- data.data = req->data->data + req->written; -- data.length = req->data->length - req->written; -- -- ret = sec_send_data(fd, &data); -- if (ret != EOK && ret != EAGAIN) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "sec_send_data failed [%d]: %s\n", ret, sss_strerror(ret)); -- return ret; -- } -- -- req->written = req->data->length - data.length; -- return ret; --} -- --static void proxy_fd_send(void *data) --{ -- struct proxy_http_req_state *state; -- struct tevent_req * req; -- int ret; -- -- req = talloc_get_type(data, struct tevent_req); -- state = tevent_req_data(req, struct proxy_http_req_state); -- -- ret = proxy_wire_send(state->sd, &state->request); -- if (ret == EAGAIN) { -- /* not all data was sent, loop again */ -- return; -- } -- if (ret != EOK) { -- DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting!\n"); -- tevent_req_error(req, ret); -- return; -- } -- -- /* ok all sent, wait for reply now */ -- TEVENT_FD_NOT_WRITEABLE(state->fde); -- TEVENT_FD_READABLE(state->fde); -- return; --} -- --static bool ph_received_data(struct proxy_http_reply *reply, size_t length) --{ -- reply->received += length; -- if (reply->received > SEC_REQUEST_MAX_SIZE) { -- DEBUG(SSSDBG_FATAL_FAILURE, "Request too big, aborting!\n"); -- return true; -- } -- return false; --} -- --static void ph_append_string(TALLOC_CTX *memctx, char **dest, -- const char *src, size_t len) --{ -- if (*dest) { -- *dest = talloc_strndup_append_buffer(*dest, src, len); -- } else { -- *dest = talloc_strndup(memctx, src, len); -- } --} -- --static int ph_on_message_begin(http_parser *parser) --{ -- DEBUG(SSSDBG_TRACE_INTERNAL, "HTTP Message parsing begins\n"); -- return 0; --} -- --#if ((HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)) --static int ph_on_status(http_parser *parser, const char *at, size_t length) --{ -- struct proxy_http_reply *reply = -- talloc_get_type(parser->data, struct proxy_http_reply); -- -- if (ph_received_data(reply, length)) return -1; -- -- ph_append_string(reply, &reply->reason_phrase, at, length); -- if (!reply->reason_phrase) { -- DEBUG(SSSDBG_FATAL_FAILURE, -- "Failed to store reason phrase, aborting client!\n"); -- return -1; -- } -- -- return 0; --} --#endif -- --static int ph_on_header_field(http_parser *parser, -- const char *at, size_t length) --{ -- struct proxy_http_reply *reply = -- talloc_get_type(parser->data, struct proxy_http_reply); -- int n = reply->num_headers; -- -- if (ph_received_data(reply, length)) return -1; -- -- if (!reply->headers) { -- reply->headers = talloc_zero_array(reply, struct sec_kvp, 10); -- } else if ((n % 10 == 0) && -- (reply->headers[n - 1].value)) { -- reply->headers = talloc_realloc(reply, reply->headers, -- struct sec_kvp, n + 10); -- if (reply->headers) { -- memset(&reply->headers[n], 0, sizeof(struct sec_kvp) * 10); -- } -- } -- if (!reply->headers) { -- DEBUG(SSSDBG_FATAL_FAILURE, -- "Failed to store headers, aborting client!\n"); -- return -1; -- } -- -- if (!n || reply->headers[n - 1].value) { -- /* new field */ -- n++; -- } -- ph_append_string(reply->headers, &reply->headers[n - 1].name, at, length); -- if (!reply->headers[n - 1].name) { -- DEBUG(SSSDBG_FATAL_FAILURE, -- "Failed to store header name, aborting client!\n"); -- return -1; -- } -- -- return 0; --} -- --static int ph_on_header_value(http_parser *parser, -- const char *at, size_t length) --{ -- struct proxy_http_reply *reply = -- talloc_get_type(parser->data, struct proxy_http_reply); -- int n = reply->num_headers; -- -- if (ph_received_data(reply, length)) return -1; -- -- if (!reply->headers) { -- DEBUG(SSSDBG_FATAL_FAILURE, -- "Invalid headers pointer, aborting client!\n"); -- return -1; -- } -- -- if (reply->headers[n].name && !reply->headers[n].value) { -- /* we increment on new value */ -- n = ++reply->num_headers; -- } -- -- ph_append_string(reply->headers, &reply->headers[n - 1].value, at, length); -- if (!reply->headers[n - 1].value) { -- DEBUG(SSSDBG_FATAL_FAILURE, -- "Failed to store header value, aborting client!\n"); -- return -1; -- } -- -- return 0; --} -- --static int ph_on_headers_complete(http_parser *parser) --{ -- /* TODO: if message has no body we should return 1 */ -- return 0; --} -- --static int ph_on_body(http_parser *parser, const char *at, size_t length) --{ -- struct proxy_http_reply *reply = -- talloc_get_type(parser->data, struct proxy_http_reply); -- -- if (ph_received_data(reply, length)) return -1; -- -- /* FIXME: body may be binary */ -- ph_append_string(reply, &reply->body.data, at, length); -- if (!reply->body.data) { -- DEBUG(SSSDBG_FATAL_FAILURE, -- "Failed to store body, aborting!\n"); -- return -1; -- } -- reply->body.length += length; -- -- return 0; --} -- --static int ph_on_message_complete(http_parser *parser) --{ -- struct proxy_http_reply *reply = -- talloc_get_type(parser->data, struct proxy_http_reply); -- -- reply->status_code = parser->status_code; -- reply->complete = true; -- -- return 0; --} -- --static http_parser_settings ph_callbacks = { -- .on_message_begin = ph_on_message_begin, --#if ((HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)) -- .on_status = ph_on_status, --#endif -- .on_header_field = ph_on_header_field, -- .on_header_value = ph_on_header_value, -- .on_headers_complete = ph_on_headers_complete, -- .on_body = ph_on_body, -- .on_message_complete = ph_on_message_complete --}; -- --static void proxy_fd_recv(void *data) --{ -- char buffer[SEC_PACKET_MAX_RECV_SIZE]; -- struct sec_data packet = { buffer, -- SEC_PACKET_MAX_RECV_SIZE }; -- struct proxy_http_req_state *state; -- struct tevent_req *req; -- bool must_complete = false; -- int ret; -- -- req = talloc_get_type(data, struct tevent_req); -- state = tevent_req_data(req, struct proxy_http_req_state); -- -- if (!state->reply) { -- /* A new reply */ -- state->reply = talloc_zero(state, struct proxy_http_reply); -- if (!state->reply) { -- DEBUG(SSSDBG_FATAL_FAILURE, "Failed to allocate reply, aborting!\n"); -- tevent_req_error(req, ENOMEM); -- return; -- } -- http_parser_init(&state->reply->parser, HTTP_RESPONSE); -- state->reply->parser.data = state->reply; -- } -- -- ret = sec_recv_data(state->sd, &packet); -- switch (ret) { -- case ENODATA: -- DEBUG(SSSDBG_TRACE_ALL, "Server closed connection.\n"); -- /* if we got no content length and the request is not complete, -- * then 0 length will indicate EOF to the parser, otherwise we -- * have an error */ -- must_complete = true; -- break; -- case EAGAIN: -- DEBUG(SSSDBG_TRACE_ALL, -- "Interrupted before any data could be read, retry later\n"); -- return; -- case EOK: -- /* all fine */ -- break; -- default: -- DEBUG(SSSDBG_FATAL_FAILURE, -- "Failed to receive data (%d, %s), aborting\n", -- ret, sss_strerror(ret)); -- tevent_req_error(req, EIO); -- return; -- } -- -- ret = http_parser_execute(&state->reply->parser, &ph_callbacks, -- packet.data, packet.length); -- if (ret != packet.length) { -- DEBUG(SSSDBG_FATAL_FAILURE, -- "Failed to parse request, aborting!\n"); -- tevent_req_error(req, EIO); -- return; -- } -- -- if (!state->reply->complete) { -- if (must_complete) { -- tevent_req_error(req, EIO); -- } -- return; -- } -- -- /* do not read anymore, server is done sending */ -- TEVENT_FD_NOT_READABLE(state->fde); -- tevent_req_done(req); --} -- --static void proxy_fd_handler(struct tevent_context *ev, struct tevent_fd *fde, -- uint16_t flags, void *data) --{ -- if (flags & TEVENT_FD_READ) { -- proxy_fd_recv(data); -- } else if (flags & TEVENT_FD_WRITE) { -- proxy_fd_send(data); -- } --} -- - struct proxy_secret_state { - struct tevent_context *ev; - struct sec_req_ctx *secreq; --- -2.9.3 - diff --git a/SOURCES/0085-IPA-Include-SYSDB_OBJECTCATEGORY-not-OBJECTCLASS-in-.patch b/SOURCES/0085-IPA-Include-SYSDB_OBJECTCATEGORY-not-OBJECTCLASS-in-.patch new file mode 100644 index 0000000..49fffa3 --- /dev/null +++ b/SOURCES/0085-IPA-Include-SYSDB_OBJECTCATEGORY-not-OBJECTCLASS-in-.patch @@ -0,0 +1,43 @@ +From 0f707b5f99f4cc17b61026e7a0e7787e776fae87 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 6 Dec 2017 15:45:13 +0100 +Subject: [PATCH 85/86] IPA: Include SYSDB_OBJECTCATEGORY, not OBJECTCLASS in + cache search results +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The function get_object_from_cache() returns an ldb_message that is +passed to apply_subdomain_homedir() which expects SYSDB_OBJECTCATEGORY +to be present in the message, otherwise it errors out. + +However, get_object_from_cache() was reading only SYSDB_OBJECTCLASS. + +This patch changes get_object_from_cache() to ready +SYSDB_OBJECTCATEGORY. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3599 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit dc49e07a0dbbbf3d69d09a7c6f236d82c86c7def) +--- + src/providers/ipa/ipa_subdomains_id.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c +index 2ba9813a44b4d914d9c2ef7a1a7504546f52954c..d40671086854f9c1a3f8bc7fc711009298dc31c8 100644 +--- a/src/providers/ipa/ipa_subdomains_id.c ++++ b/src/providers/ipa/ipa_subdomains_id.c +@@ -965,7 +965,7 @@ errno_t get_object_from_cache(TALLOC_CTX *mem_ctx, + const char *attrs[] = { SYSDB_NAME, + SYSDB_UIDNUM, + SYSDB_SID_STR, +- SYSDB_OBJECTCLASS, ++ SYSDB_OBJECTCATEGORY, + SYSDB_UUID, + SYSDB_GHOST, + SYSDB_HOMEDIR, +-- +2.14.3 + diff --git a/SOURCES/0085-secrets-allow-to-configure-certificate-check.patch b/SOURCES/0085-secrets-allow-to-configure-certificate-check.patch deleted file mode 100644 index dd9bea7..0000000 --- a/SOURCES/0085-secrets-allow-to-configure-certificate-check.patch +++ /dev/null @@ -1,254 +0,0 @@ -From d35f47a4e50feeb2b54c1621d0c2f5b15cd275eb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 28 Feb 2017 11:47:32 +0100 -Subject: [PATCH 85/90] secrets: allow to configure certificate check - -Some users may want to use TLS with unverified peer (for example if -they use self-signed certificate) or if unverified hostname (if -certificate hostname does not match with the real hostname). On the -other side it may be useful to point to a directory containing custom -certificate authorities. - -This patch add three new options to secrets responder: -verify_peer => peer's certificate must be valid -verify_host => hostnames must match -capath => path to directory containing CA certs -cacert => ca certificate -cert => client certificate -key => client private key - -Resolves: -https://pagure.io/SSSD/sssd/issue/3192 - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit 720e1a5b95a953a0f1c8315bbb7c9c1edf9fb417) ---- - src/config/SSSDConfig/__init__.py.in | 6 +++ - src/config/cfg_rules.ini | 6 +++ - src/config/etc/sssd.api.conf | 6 +++ - src/man/sssd-secrets.5.xml | 76 ++++++++++++++++++++++++++++++++++++ - src/responder/secrets/proxy.c | 55 ++++++++++++++++++++++++++ - 5 files changed, 149 insertions(+) - -diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in -index 211338778e81c1c60ffb3cdbc67c9619343d7798..75515ab5c68822538728900482296b9159e1547e 100644 ---- a/src/config/SSSDConfig/__init__.py.in -+++ b/src/config/SSSDConfig/__init__.py.in -@@ -137,6 +137,12 @@ option_strings = { - 'forward_headers': _('The list of the headers to forward to the Custodia server together with the request'), - 'username': _('The username to use when authenticating to a Custodia server using basic_auth'), - 'password': _('The password to use when authenticating to a Custodia server using basic_auth'), -+ 'verify_peer': _('If true peer\'s certificate is verified if proxy_url uses https protocol'), -+ 'verify_host': _('If false peer\'s certificate may contain different hostname then proxy_url when https protocol is used'), -+ 'capath': _('Path to directory where certificate authority certificates are stored'), -+ 'cacert': _('Path to file containing server\'s CA certificate'), -+ 'cert': _('Path to file containing client\'s certificate'), -+ 'key': _('Path to file containing client\'s private key'), - - # [provider] - 'id_provider' : _('Identity provider'), -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 1a749db754cedd87f263f7ae596d6f8238bb4357..e47ff33242d6a9e5979fe0eb8eea14c2af28685a 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -265,6 +265,12 @@ option = auth_header_value - option = forward_headers - option = username - option = password -+option = verify_peer -+option = verify_host -+option = capath -+option = cacert -+option = cert -+option = key - - # KCM responder - [rule/allowed_kcm_options] -diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf -index a1a0c2992925a4c7df86832117eec2a0cf7894c9..f86589ecefa0b9e046aba781ded107f8e94395d6 100644 ---- a/src/config/etc/sssd.api.conf -+++ b/src/config/etc/sssd.api.conf -@@ -114,6 +114,12 @@ auth_header_value = str, None, false - forward_headers = list, None, false - username = str, None, false - password = str, None, false -+verify_peer = bool, None, false -+verify_host = bool, None, false -+capath = str, None, false -+cacert = str, None, false -+cert = str, None, false -+key = str, None, false - - [provider] - #Available provider types -diff --git a/src/man/sssd-secrets.5.xml b/src/man/sssd-secrets.5.xml -index 80e9c405921e1fb46a3d172d9873deebfa5ed2ce..44a86c3fb56a8bdebebd01e9f49ad171986282a4 100644 ---- a/src/man/sssd-secrets.5.xml -+++ b/src/man/sssd-secrets.5.xml -@@ -273,6 +273,82 @@ systemctl enable sssd-secrets.service - - - -+ -+ verify_peer (boolean) -+ -+ -+ Whether peer's certificate should be verified and valid -+ if HTTPS protocol is used with the proxy provider. -+ -+ -+ Default: true -+ -+ -+ -+ -+ verify_host (boolean) -+ -+ -+ Whether peer's hostname must match with hostname in -+ its certificate if HTTPS protocol is used with the -+ proxy provider. -+ -+ -+ Default: true -+ -+ -+ -+ -+ capath (string) -+ -+ -+ Path to directory containing stored certificate authority -+ certificates. System default path is used if this option is -+ not set. -+ -+ -+ Default: not set -+ -+ -+ -+ -+ cacert (string) -+ -+ -+ Path to file containing server's certificate authority -+ certificate. If this option is not set then the CA's -+ certificate is looked up in capath. -+ -+ -+ Default: not set -+ -+ -+ -+ -+ cert (string) -+ -+ -+ Path to file containing client's certificate if required -+ by the server. This file may also contain private key or -+ the private key may be in separate file set with -+ key. -+ -+ -+ Default: not set -+ -+ -+ -+ -+ key (string) -+ -+ -+ Path to file containing client's private key. -+ -+ -+ Default: not set -+ -+ -+ - - - -diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c -index 3c495716010ac468c9e2f1fb6356529a8dbdc614..240a1de1e431d511a1eca24d8b463c37ba893e7b 100644 ---- a/src/responder/secrets/proxy.c -+++ b/src/responder/secrets/proxy.c -@@ -59,6 +59,13 @@ struct proxy_cfg { - struct pat_basic_auth basic; - struct pat_header header; - } auth; -+ -+ char *key; -+ char *cert; -+ char *cacert; -+ char *capath; -+ bool verify_peer; -+ bool verify_host; - }; - - static int proxy_get_config_string(struct proxy_context *pctx, -@@ -129,6 +136,38 @@ static int proxy_sec_get_cfg(struct proxy_context *pctx, - } - } - -+ ret = confdb_get_bool(pctx->cdb, secreq->cfg_section, "verify_peer", -+ true, &cfg->verify_peer); -+ if (ret) goto done; -+ DEBUG(SSSDBG_CONF_SETTINGS, "verify_peer: %s\n", -+ (&cfg->verify_peer ? "true" : "false")); -+ -+ ret = confdb_get_bool(pctx->cdb, secreq->cfg_section, "verify_host", -+ true, &cfg->verify_host); -+ if (ret) goto done; -+ DEBUG(SSSDBG_CONF_SETTINGS, "verify_host: %s\n", -+ (&cfg->verify_host ? "true" : "false")); -+ -+ ret = proxy_get_config_string(pctx, cfg, false, secreq, -+ "capath", &cfg->capath); -+ if (ret) goto done; -+ DEBUG(SSSDBG_CONF_SETTINGS, "capath: %s\n", cfg->capath); -+ -+ ret = proxy_get_config_string(pctx, cfg, false, secreq, -+ "cacert", &cfg->cacert); -+ if (ret) goto done; -+ DEBUG(SSSDBG_CONF_SETTINGS, "cacert: %s\n", cfg->cacert); -+ -+ ret = proxy_get_config_string(pctx, cfg, false, secreq, -+ "cert", &cfg->cert); -+ if (ret) goto done; -+ DEBUG(SSSDBG_CONF_SETTINGS, "cert: %s\n", cfg->cert); -+ -+ ret = proxy_get_config_string(pctx, cfg, false, secreq, -+ "key", &cfg->key); -+ if (ret) goto done; -+ DEBUG(SSSDBG_CONF_SETTINGS, "key: %s\n", cfg->key); -+ - ret = confdb_get_string_as_list(pctx->cdb, cfg, secreq->cfg_section, - "forward_headers", &cfg->fwd_headers); - if ((ret != 0) && (ret != ENOENT)) goto done; -@@ -385,6 +424,22 @@ static errno_t proxy_http_create_request(TALLOC_CTX *mem_ctx, - goto done; - } - -+ /* Set TLS settings to verify peer. -+ * This has no effect for HTTP protocol so we can set it anyway. */ -+ ret = tcurl_req_verify_peer(tcurl_req, pcfg->capath, pcfg->cacert, -+ pcfg->verify_peer, pcfg->verify_host); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ /* Set client's certificate if required. */ -+ if (pcfg->cert != NULL) { -+ ret = tcurl_req_set_client_cert(tcurl_req, pcfg->cert, pcfg->key); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ - talloc_steal(tcurl_req, body); - *_tcurl_req = talloc_steal(mem_ctx, tcurl_req); - --- -2.9.3 - diff --git a/SOURCES/0086-nss-idmap-allow-NULL-result-in-_timeout-calls.patch b/SOURCES/0086-nss-idmap-allow-NULL-result-in-_timeout-calls.patch new file mode 100644 index 0000000..95bdd75 --- /dev/null +++ b/SOURCES/0086-nss-idmap-allow-NULL-result-in-_timeout-calls.patch @@ -0,0 +1,113 @@ +From 2a3accc78bb9658401b33ad5a3a2f1bc4bc3c269 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 7 Dec 2017 17:42:45 +0100 +Subject: [PATCH 86/86] nss-idmap: allow NULL result in *_timeout calls +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To make the *_timeout calls more resilient checks are added if the +result parameter is NULL. It will not be used in this case. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Alexander Bokovoy +(cherry picked from commit bba068c535d23eebff61f592bddb3a6438446d6f) +--- + src/sss_client/idmap/sss_nss_ex.c | 46 +++++++++++++++++++++++++++------------ + 1 file changed, 32 insertions(+), 14 deletions(-) + +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +index dcd9619a8b07ced7498f61b7e809fa46ebffe09e..861b1e1e92db4f7e6e8d74a812dc3c9220711773 100644 +--- a/src/sss_client/idmap/sss_nss_ex.c ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -367,13 +367,17 @@ int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, + return ret; + } + +- *result = NULL; +- + ret = sss_get_ex(&inp, flags, timeout); + free(discard_const(inp.rd.data)); +- if (ret == 0) { +- *result = inp.result.pwrep.result; ++ ++ if (result != NULL) { ++ if (ret == 0) { ++ *result = inp.result.pwrep.result; ++ } else { ++ *result = NULL; ++ } + } ++ + return ret; + } + +@@ -395,12 +399,17 @@ int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd, + + SAFEALIGN_COPY_UINT32(&req_data[0], &uid, NULL); + SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL); +- *result = NULL; + + ret = sss_get_ex(&inp, flags, timeout); +- if (ret == 0) { +- *result = inp.result.pwrep.result; ++ ++ if (result != NULL) { ++ if (ret == 0) { ++ *result = inp.result.pwrep.result; ++ } else { ++ *result = NULL; ++ } + } ++ + return ret; + } + +@@ -421,13 +430,17 @@ int sss_nss_getgrnam_timeout(const char *name, struct group *grp, + return ret; + } + +- *result = NULL; +- + ret = sss_get_ex(&inp, flags, timeout); + free(discard_const(inp.rd.data)); +- if (ret == 0) { +- *result = inp.result.grrep.result; ++ ++ if (result != NULL) { ++ if (ret == 0) { ++ *result = inp.result.grrep.result; ++ } else { ++ *result = NULL; ++ } + } ++ + return ret; + } + +@@ -448,12 +461,17 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, + + SAFEALIGN_COPY_UINT32(&req_data[0], &gid, NULL); + SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL); +- *result = NULL; + + ret = sss_get_ex(&inp, flags, timeout); +- if (ret == 0) { +- *result = inp.result.grrep.result; ++ ++ if (result != NULL) { ++ if (ret == 0) { ++ *result = inp.result.grrep.result; ++ } else { ++ *result = NULL; ++ } + } ++ + return ret; + } + +-- +2.14.3 + diff --git a/SOURCES/0086-secrets-support-HTTP-basic-authentication-with-proxy.patch b/SOURCES/0086-secrets-support-HTTP-basic-authentication-with-proxy.patch deleted file mode 100644 index f048f94..0000000 --- a/SOURCES/0086-secrets-support-HTTP-basic-authentication-with-proxy.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 28d590900ab20dec3dc447562aefaa5e2771c48e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 28 Feb 2017 13:58:20 +0100 -Subject: [PATCH 86/90] secrets: support HTTP basic authentication with proxy - provider - -Even though configuration options auth_type = basic, username and password -are read they were not used anywhere prior this patch. - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit af026ea6a6e812b7d6c5c889dda64ba7b7c433ee) ---- - src/responder/secrets/proxy.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c -index 240a1de1e431d511a1eca24d8b463c37ba893e7b..fd96e985c897e2cb470a9b5d6eecbd34350fb7d2 100644 ---- a/src/responder/secrets/proxy.c -+++ b/src/responder/secrets/proxy.c -@@ -440,6 +440,15 @@ static errno_t proxy_http_create_request(TALLOC_CTX *mem_ctx, - } - } - -+ /* Set basic authentication if required. */ -+ if (pcfg->auth_type == PAT_BASIC_AUTH) { -+ ret = tcurl_req_http_basic_auth(tcurl_req, pcfg->auth.basic.username, -+ pcfg->auth.basic.password); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ - talloc_steal(tcurl_req, body); - *_tcurl_req = talloc_steal(mem_ctx, tcurl_req); - --- -2.9.3 - diff --git a/SOURCES/0087-cache-Check-for-max_id-min_id-in-cache_req.patch b/SOURCES/0087-cache-Check-for-max_id-min_id-in-cache_req.patch new file mode 100644 index 0000000..04860c2 --- /dev/null +++ b/SOURCES/0087-cache-Check-for-max_id-min_id-in-cache_req.patch @@ -0,0 +1,353 @@ +From 2f712c8fe0ecaa07f7b15ebeae5213978d033278 Mon Sep 17 00:00:00 2001 +From: amitkuma +Date: Thu, 30 Nov 2017 22:18:39 +0530 +Subject: [PATCH 87/87] cache: Check for max_id/min_id in cache_req +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The cache_req code doesn't check the min_id/max_id +boundaries for requests by ID. +Extending the .lookup_fn function in each plugin +that searches by ID for a check that returns non-zero +if the entry is out of the range and 0 if not. + +Resolves: https://pagure.io/SSSD/sssd/issue/3569 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 2af80640f18966d65cf82106059ce3c060df93bf) +--- + src/responder/common/cache_req/cache_req.c | 1 + + src/responder/common/cache_req/cache_req_private.h | 3 + + src/responder/common/cache_req/cache_req_search.c | 5 + + .../common/cache_req/plugins/cache_req_common.c | 11 ++ + .../cache_req/plugins/cache_req_group_by_id.c | 6 + + .../cache_req/plugins/cache_req_object_by_id.c | 6 + + .../cache_req/plugins/cache_req_user_by_id.c | 5 + + src/tests/cmocka/test_responder_cache_req.c | 127 +++++++++++++++++---- + src/util/util_errors.c | 1 + + src/util/util_errors.h | 1 + + 10 files changed, 141 insertions(+), 25 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index ad9bc040dd999a205713141e6a1512e47b69c45e..134688b0f62c6546763d91468af3f54b73b6073a 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -953,6 +953,7 @@ static void cache_req_search_domains_done(struct tevent_req *subreq) + goto done; + } + break; ++ case ERR_ID_OUTSIDE_RANGE: + case ENOENT: + if (state->check_next == false) { + /* Not found. */ +diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h +index 95f24c0e5b9ab1150591d308c7288c57fe478c5d..9538b9568ca7f77e377cfee67235c8a52ebbe454 100644 +--- a/src/responder/common/cache_req/cache_req_private.h ++++ b/src/responder/common/cache_req/cache_req_private.h +@@ -192,4 +192,7 @@ cache_reg_common_get_acct_domain_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *subreq, + struct cache_req *cr, + char **_domain); ++ ++errno_t cache_req_idminmax_check(struct cache_req_data *data, ++ struct sss_domain_info *domain); + #endif /* _CACHE_REQ_PRIVATE_H_ */ +diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c +index 3365962d473b0982945de2541e44ba86b43a0db5..7423feb6305df87d368bcc10ba28b9b29d57ecf0 100644 +--- a/src/responder/common/cache_req/cache_req_search.c ++++ b/src/responder/common/cache_req/cache_req_search.c +@@ -203,6 +203,11 @@ static errno_t cache_req_search_cache(TALLOC_CTX *mem_ctx, + + *_result = result; + break; ++ case ERR_ID_OUTSIDE_RANGE: ++ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, ++ "ID [%s] was filtered out\n", ++ cr->debugobj); ++ break; + case ENOENT: + CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, + "Object [%s] was not found in cache\n", +diff --git a/src/responder/common/cache_req/plugins/cache_req_common.c b/src/responder/common/cache_req/plugins/cache_req_common.c +index 408c91949ceb3ecaf743f270f58f4e3fcfc3ccb1..bb11eaa86a8bca3f9d15afe48dab9921319d184e 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_common.c ++++ b/src/responder/common/cache_req/plugins/cache_req_common.c +@@ -26,6 +26,17 @@ + #include "providers/data_provider.h" + #include "responder/common/cache_req/cache_req_plugin.h" + ++errno_t cache_req_idminmax_check(struct cache_req_data *data, ++ struct sss_domain_info *domain) ++{ ++ if (((domain->id_min != 0) && (data->id < domain->id_min)) || ++ ((domain->id_max != 0) && (data->id > domain->id_max))) { ++ DEBUG(SSSDBG_FUNC_DATA, "id exceeds min/max boundaries\n"); ++ return ERR_ID_OUTSIDE_RANGE; ++ } ++ return EOK; ++} ++ + static struct ldb_message * + cache_req_well_known_sid_msg(TALLOC_CTX *mem_ctx, + const char *sid, +diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +index ce84b1b4458b447ff6b4b036c6e8fe8f4d7758c8..d178283c33c84e277b83772d04973aa6069af967 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +@@ -81,6 +81,12 @@ cache_req_group_by_id_lookup(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + struct ldb_result **_result) + { ++ errno_t ret; ++ ++ ret = cache_req_idminmax_check(data, domain); ++ if (ret != EOK) { ++ return ret; ++ } + return sysdb_getgrgid_with_views(mem_ctx, domain, data->id, _result); + } + +diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +index 1327b480c1b1b68f9826fa229c9b001f2d92b79b..be9488d298885320139ccfcd3c59a83ff088e77d 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +@@ -110,6 +110,12 @@ cache_req_object_by_id_lookup(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + struct ldb_result **_result) + { ++ errno_t ret; ++ ++ ret = cache_req_idminmax_check(data, domain); ++ if (ret != EOK) { ++ return ret; ++ } + return sysdb_search_object_by_id(mem_ctx, domain, data->id, + data->attrs, _result); + } +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +index 656fa41af5f39f68c64e241aa97c4eaf3ec57395..151c3e17acf6ef0d958d5a73a36e1c93b9e7a9a9 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +@@ -81,6 +81,11 @@ cache_req_user_by_id_lookup(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + struct ldb_result **_result) + { ++ errno_t ret; ++ ret = cache_req_idminmax_check(data, domain); ++ if (ret != EOK) { ++ return ret; ++ } + return sysdb_getpwuid_with_views(mem_ctx, domain, data->id, _result); + } + +diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c +index 0ee0070d0c9fbb89020f522b2f7613f1076a8cbb..5f50b27a5ee846c9ccf71e1e661359a07c2e02e8 100644 +--- a/src/tests/cmocka/test_responder_cache_req.c ++++ b/src/tests/cmocka/test_responder_cache_req.c +@@ -59,6 +59,11 @@ struct test_group { + test_single_domain_setup, \ + test_single_domain_teardown) + ++#define new_single_domain_id_limit_test(test) \ ++ cmocka_unit_test_setup_teardown(test_ ## test, \ ++ test_single_domain_id_limits_setup, \ ++ test_single_domain_teardown) ++ + #define new_multi_domain_test(test) \ + cmocka_unit_test_setup_teardown(test_ ## test, \ + test_multi_domain_setup, \ +@@ -521,33 +526,39 @@ __wrap_sss_dp_get_account_send(TALLOC_CTX *mem_ctx, + return test_req_succeed_send(mem_ctx, rctx->ev); + } + ++static int test_single_domain_setup_common(void **state, ++ struct sss_test_conf_param *params) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ errno_t ret; ++ ++ assert_true(leak_check_setup()); ++ ++ test_dom_suite_setup(TESTS_PATH); ++ ++ test_ctx = talloc_zero(global_talloc_context, struct cache_req_test_ctx); ++ assert_non_null(test_ctx); ++ *state = test_ctx; ++ ++ test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, TEST_CONF_DB, ++ TEST_DOM_NAME, TEST_ID_PROVIDER, params); ++ assert_non_null(test_ctx->tctx); ++ ++ test_ctx->rctx = mock_rctx(test_ctx, test_ctx->tctx->ev, ++ test_ctx->tctx->dom, NULL); ++ assert_non_null(test_ctx->rctx); ++ ++ ret = sss_ncache_init(test_ctx, 10, 0, &test_ctx->ncache); ++ assert_int_equal(ret, EOK); ++ ++ check_leaks_push(test_ctx); ++ ++ return 0; ++} ++ + static int test_single_domain_setup(void **state) + { +- struct cache_req_test_ctx *test_ctx = NULL; +- errno_t ret; +- +- assert_true(leak_check_setup()); +- +- test_dom_suite_setup(TESTS_PATH); +- +- test_ctx = talloc_zero(global_talloc_context, struct cache_req_test_ctx); +- assert_non_null(test_ctx); +- *state = test_ctx; +- +- test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, TEST_CONF_DB, +- TEST_DOM_NAME, TEST_ID_PROVIDER, NULL); +- assert_non_null(test_ctx->tctx); +- +- test_ctx->rctx = mock_rctx(test_ctx, test_ctx->tctx->ev, +- test_ctx->tctx->dom, NULL); +- assert_non_null(test_ctx->rctx); +- +- ret = sss_ncache_init(test_ctx, 10, 0, &test_ctx->ncache); +- assert_int_equal(ret, EOK); +- +- check_leaks_push(test_ctx); +- +- return 0; ++ return test_single_domain_setup_common(state, NULL); + } + + static int test_single_domain_teardown(void **state) +@@ -565,6 +576,16 @@ static int test_single_domain_teardown(void **state) + return 0; + } + ++static int test_single_domain_id_limits_setup(void **state) ++{ ++ struct sss_test_conf_param params[] = { ++ { "min_id", "100" }, ++ { "max_id", "10000" }, ++ { NULL, NULL }, /* Sentinel */ ++ }; ++ return test_single_domain_setup_common(state, params); ++} ++ + static int test_multi_domain_setup(void **state) + { + struct cache_req_test_ctx *test_ctx = NULL; +@@ -596,6 +617,32 @@ static int test_multi_domain_setup(void **state) + return 0; + } + ++void test_user_by_id_below_id_range(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Test. */ ++ run_cache_req(test_ctx, cache_req_user_by_id_send, ++ cache_req_user_by_id_test_done, test_ctx->tctx->dom, ++ 0, 10, ENOENT); ++ assert_false(test_ctx->dp_called); ++} ++ ++void test_user_by_id_above_id_range(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Test. */ ++ run_cache_req(test_ctx, cache_req_user_by_id_send, ++ cache_req_user_by_id_test_done, test_ctx->tctx->dom, ++ 0, 100000, ENOENT); ++ assert_false(test_ctx->dp_called); ++} ++ + static int test_multi_domain_teardown(void **state) + { + struct cache_req_test_ctx *test_ctx; +@@ -1332,6 +1379,32 @@ void test_user_by_id_sub_domains_locator_missing_found(void **state) + talloc_free(tmp_ctx); + } + ++void test_group_by_id_below_id_range(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Test. */ ++ run_cache_req(test_ctx, cache_req_group_by_id_send, ++ cache_req_group_by_id_test_done, test_ctx->tctx->dom, ++ 0, 10, ENOENT); ++ assert_false(test_ctx->dp_called); ++} ++ ++void test_group_by_id_above_id_range(void **state) ++{ ++ struct cache_req_test_ctx *test_ctx = NULL; ++ ++ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); ++ ++ /* Test. */ ++ run_cache_req(test_ctx, cache_req_group_by_id_send, ++ cache_req_group_by_id_test_done, test_ctx->tctx->dom, ++ 0, 100000, ENOENT); ++ assert_false(test_ctx->dp_called); ++} ++ + void test_user_by_id_sub_domains_locator_missing_notfound(void **state) + { + struct cache_req_test_ctx *test_ctx = NULL; +@@ -3874,6 +3947,8 @@ int main(int argc, const char *argv[]) + new_single_domain_test(user_by_id_missing_notfound), + new_multi_domain_test(user_by_id_multiple_domains_found), + new_multi_domain_test(user_by_id_multiple_domains_notfound), ++ new_single_domain_id_limit_test(user_by_id_below_id_range), ++ new_single_domain_id_limit_test(user_by_id_above_id_range), + + new_single_domain_test(group_by_name_cache_valid), + new_single_domain_test(group_by_name_cache_expired), +@@ -3884,6 +3959,8 @@ int main(int argc, const char *argv[]) + new_multi_domain_test(group_by_name_multiple_domains_found), + new_multi_domain_test(group_by_name_multiple_domains_notfound), + new_multi_domain_test(group_by_name_multiple_domains_parse), ++ new_single_domain_id_limit_test(group_by_id_below_id_range), ++ new_single_domain_id_limit_test(group_by_id_above_id_range), + + new_single_domain_test(group_by_id_cache_valid), + new_single_domain_test(group_by_id_cache_expired), +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 06c620b40aaa00d6ce58ace3a28449ffbdf8da88..39ce3d7dcf4af4c489a0a9b7768668497cb84ba5 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -117,6 +117,7 @@ struct err_string error_to_str[] = { + { "Unable to resolve host" }, /* ERR_UNABLE_TO_RESOLVE_HOST */ + { "GetAccountDomain() not supported" }, /* ERR_GET_ACCT_DOM_NOT_SUPPORTED */ + { "The last GetAccountDomain() result is still valid" }, /* ERR_GET_ACCT_DOM_CACHED */ ++ { "ID is outside the allowed range" }, /* ERR_ID_OUTSIDE_RANGE */ + { "ERR_LAST" } /* ERR_LAST */ + }; + +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index bebd6e198fc0077891a602f80182a993ce3f789b..621a3b116edac45960190684055bcd0692135957 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -139,6 +139,7 @@ enum sssd_errors { + ERR_UNABLE_TO_RESOLVE_HOST, + ERR_GET_ACCT_DOM_NOT_SUPPORTED, + ERR_GET_ACCT_DOM_CACHED, ++ ERR_ID_OUTSIDE_RANGE, + ERR_LAST /* ALWAYS LAST */ + }; + +-- +2.14.3 + diff --git a/SOURCES/0087-secrets-fix-debug-message.patch b/SOURCES/0087-secrets-fix-debug-message.patch deleted file mode 100644 index 19e563b..0000000 --- a/SOURCES/0087-secrets-fix-debug-message.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 265c8ea3b9564a53e38df08b89e0fbfb4e7dbfb9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Wed, 15 Mar 2017 13:27:59 +0100 -Subject: [PATCH 87/90] secrets: fix debug message - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit db826f57b4c2ee814823057cc536386889f7aa1d) ---- - src/responder/secrets/secsrv_cmd.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/responder/secrets/secsrv_cmd.c b/src/responder/secrets/secsrv_cmd.c -index 70679ec0398fca25cfb0525772f539526a0eb3ff..b88680c3d7c3105d160de5c78e6d981b852318b9 100644 ---- a/src/responder/secrets/secsrv_cmd.c -+++ b/src/responder/secrets/secsrv_cmd.c -@@ -451,7 +451,8 @@ int sec_send_data(int fd, struct sec_data *data) - - data->length -= len; - data->data += len; -- DEBUG(SSSDBG_TRACE_INTERNAL, "sent %zu bytes\n", data->length); -+ DEBUG(SSSDBG_TRACE_INTERNAL, "sent %zu bytes, %zu bytes remaining\n", -+ len, data->length); - return EOK; - } - --- -2.9.3 - diff --git a/SOURCES/0088-Revert-p11_child-make-sure-OCSP-checks-are-done.patch b/SOURCES/0088-Revert-p11_child-make-sure-OCSP-checks-are-done.patch new file mode 100644 index 0000000..18b947b --- /dev/null +++ b/SOURCES/0088-Revert-p11_child-make-sure-OCSP-checks-are-done.patch @@ -0,0 +1,47 @@ +From 424aa780fbb645214b92cf09f23c905b93bdf267 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 12 Dec 2017 15:28:27 +0100 +Subject: [PATCH 88/89] Revert "p11_child: make sure OCSP checks are done" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit 2297cc7d6cd5c38a7d64027165e4e82ca497f418. + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit c221b5fb4d3fc511cebcae2f042e43fb1c577bc7) +--- + src/p11_child/p11_child_nss.c | 17 ----------------- + 1 file changed, 17 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index bf533f3efe4d680f4c6dbd10a0d2c5a5da371c67..21c508eb1b1b68b3606d0a5eed36573b01f27a19 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -338,23 +338,6 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + PR_GetError(), PORT_ErrorToString(PR_GetError())); + continue; + } +- +- /* with 'certificateUsageCheckAllUsages' set +- * CERT_VerifyCertificateNow() does not do OCSP so it must be done +- * explicitly */ +- if (cert_verify_opts->do_ocsp) { +- rv = CERT_CheckOCSPStatus(handle, cert_list_node->cert, +- PR_Now(), NULL); +- if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Certificate [%s][%s] failed OCSP check [%d][%s], " +- "skipping.\n", +- cert_list_node->cert->nickname, +- cert_list_node->cert->subjectName, +- PR_GetError(), PORT_ErrorToString(PR_GetError())); +- continue; +- } +- } + } + + if (key_id_in != NULL) { +-- +2.14.3 + diff --git a/SOURCES/0088-secrets-always-add-Content-Length-header.patch b/SOURCES/0088-secrets-always-add-Content-Length-header.patch deleted file mode 100644 index d941ad3..0000000 --- a/SOURCES/0088-secrets-always-add-Content-Length-header.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 07271dbd7c8f28a6aace48787040580973eb5a4e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Wed, 15 Mar 2017 15:15:08 +0100 -Subject: [PATCH 88/90] secrets: always add Content-Length header - -If custodia server does not reply with Content-Length header, curl may -wait for non-existing body of http reply if such body does not exist -(for example during POST operation when creating a container). - -Reviewed-by: Simo Sorce -Reviewed-by: Jakub Hrozek -(cherry picked from commit 13d720de13e490850c1139eea865bcd5195a2630) ---- - src/responder/secrets/providers.c | 72 ++++++++++++++++++++++++++++++++++++--- - 1 file changed, 68 insertions(+), 4 deletions(-) - -diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c -index 80a443d91135447ec8ce8d424b692a6d7e26a907..a27fb720b394e7c76d1b65f656146bcd00755449 100644 ---- a/src/responder/secrets/providers.c -+++ b/src/responder/secrets/providers.c -@@ -388,20 +388,84 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply, - return EOK; - } - -+static errno_t -+sec_http_iobuf_split(struct sss_iobuf *response, -+ const char **headers, -+ const char **body) -+{ -+ const char *data = (const char *)sss_iobuf_get_data(response); -+ char *delim; -+ -+ /* The last header ends with \r\n and then comes \r\n again as a separator -+ * of body from headers. We can use this to find this point. */ -+ delim = strstr(data, "\r\n\r\n"); -+ if (delim == NULL) { -+ return EINVAL; -+ } -+ -+ /* Skip to the body delimiter. */ -+ delim = delim + sizeof("\r\n") - 1; -+ -+ /* Replace \r\n with zeros turning data into: -+ * from HEADER\r\nBODY into HEADER\0\0BODY format. */ -+ delim[0] = '\0'; -+ delim[1] = '\0'; -+ -+ /* Split the buffer. */ -+ *headers = data; -+ *body = delim + 2; -+ -+ return 0; -+} -+ -+static const char * -+sec_http_iobuf_add_content_length(TALLOC_CTX *mem_ctx, -+ const char *headers, -+ size_t body_len) -+{ -+ /* If Content-Length is already present we do nothing. */ -+ if (strstr(headers, "Content-Length:") != NULL) { -+ return headers; -+ } -+ -+ return talloc_asprintf(mem_ctx, "%sContent-Length: %zu\r\n", -+ headers, body_len); -+} -+ - errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx, - struct sec_data *reply, - int response_code, - struct sss_iobuf *response) - { -+ const char *headers; -+ const char *body; -+ size_t body_len; -+ errno_t ret; -+ - DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d\n", response_code); - -- reply->data = (char *)sss_iobuf_get_data(response); -- reply->length = sss_iobuf_get_len(response); -+ ret = sec_http_iobuf_split(response, &headers, &body); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Unexpected HTTP reply, returning what we got from server\n"); -+ reply->data = (char *)sss_iobuf_get_data(response); -+ reply->length = sss_iobuf_get_len(response); - -- talloc_steal(mem_ctx, reply->data); -+ return EOK; -+ } - -+ /* Add Content-Length header if not present so client does not await -+ * not-existing incoming data. */ -+ body_len = strlen(body); -+ headers = sec_http_iobuf_add_content_length(mem_ctx, headers, body_len); -+ if (headers == NULL) { -+ return ENOMEM; -+ } -+ -+ reply->length = strlen(headers) + sizeof("\r\n") - 1 + body_len; -+ reply->data = talloc_asprintf(mem_ctx, "%s\r\n%s", headers, body); - if (reply->data == NULL) { -- return EINVAL; -+ return ENOMEM; - } - - return EOK; --- -2.9.3 - diff --git a/SOURCES/0089-p11_child-properly-check-results-of-CERT_VerifyCerti.patch b/SOURCES/0089-p11_child-properly-check-results-of-CERT_VerifyCerti.patch new file mode 100644 index 0000000..85e867a --- /dev/null +++ b/SOURCES/0089-p11_child-properly-check-results-of-CERT_VerifyCerti.patch @@ -0,0 +1,64 @@ +From 56402a2b350ebdcfd49685a5a3c0fd42131b2196 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 12 Dec 2017 15:24:57 +0100 +Subject: [PATCH 89/89] p11_child: properly check results of + CERT_VerifyCertificateNow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With certificateUsageCheckAllUsages not only the return code of +CERT_VerifyCertificateNow() should be checked but also the usages for +which the certificate was verified. The usages checked here will all +involve CA signature checks and OCSP checks if OCSP is enabled. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 787ba9c882f1d7ff9ea4f2745e779c5fb04dfafc) +--- + src/p11_child/p11_child_nss.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index 21c508eb1b1b68b3606d0a5eed36573b01f27a19..cb894280c18fcbd59c5499e36d30f3ba305c0ea2 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -45,6 +45,15 @@ + #include "util/crypto/sss_crypto.h" + #include "util/cert.h" + ++#define EXP_USAGES ( certificateUsageSSLClient \ ++ | certificateUsageSSLServer \ ++ | certificateUsageSSLServerWithStepUp \ ++ | certificateUsageEmailSigner \ ++ | certificateUsageEmailRecipient \ ++ | certificateUsageObjectSigner \ ++ | certificateUsageStatusResponder \ ++ | certificateUsageSSLCA ) ++ + enum op_mode { + OP_NONE, + OP_AUTH, +@@ -136,6 +145,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + char *cert_b64 = NULL; + char *multi = NULL; + PRCList *node; ++ SECCertificateUsage returned_usage = 0; + + nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, ¶meters, flags); + if (nss_ctx == NULL) { +@@ -329,8 +339,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert, + PR_TRUE, + certificateUsageCheckAllUsages, +- NULL, NULL); +- if (rv != SECSuccess) { ++ NULL, &returned_usage); ++ if (rv != SECSuccess || ((returned_usage & EXP_USAGES) == 0)) { + DEBUG(SSSDBG_OP_FAILURE, + "Certificate [%s][%s] not valid [%d][%s], skipping.\n", + cert_list_node->cert->nickname, +-- +2.14.3 + diff --git a/SOURCES/0089-sss_iobuf-fix-read-shadows-a-global-declaration.patch b/SOURCES/0089-sss_iobuf-fix-read-shadows-a-global-declaration.patch deleted file mode 100644 index 2524495..0000000 --- a/SOURCES/0089-sss_iobuf-fix-read-shadows-a-global-declaration.patch +++ /dev/null @@ -1,40 +0,0 @@ -From ce191dc1922d894573eee828c88c325f64515d3e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 28 Mar 2017 15:26:52 +0200 -Subject: [PATCH 89/90] sss_iobuf: fix 'read' shadows a global declaration -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 18e4fe9d836e8f7bee52724374ffc0011172329f) ---- - src/util/sss_iobuf.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/util/sss_iobuf.c b/src/util/sss_iobuf.c -index fc288d2df2bfaaba393dd490d4da8976de804cb5..518713e4cc3dd99627a3a4450f235cbbc69ed3a2 100644 ---- a/src/util/sss_iobuf.c -+++ b/src/util/sss_iobuf.c -@@ -188,15 +188,15 @@ errno_t sss_iobuf_read_len(struct sss_iobuf *iobuf, - size_t len, - uint8_t *_buf) - { -- size_t read; -+ size_t read_bytes; - errno_t ret; - -- ret = sss_iobuf_read(iobuf, len, _buf, &read); -+ ret = sss_iobuf_read(iobuf, len, _buf, &read_bytes); - if (ret != EOK) { - return ret; - } - -- if (read != len) { -+ if (read_bytes != len) { - return ENOBUFS; - } - --- -2.9.3 - diff --git a/SOURCES/0090-configure-fix-typo.patch b/SOURCES/0090-configure-fix-typo.patch deleted file mode 100644 index f7a0f28..0000000 --- a/SOURCES/0090-configure-fix-typo.patch +++ /dev/null @@ -1,29 +0,0 @@ -From a87cb169e5700bf9a3e74d4a1980e8e5c8e24692 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Wed, 29 Mar 2017 13:28:49 +0200 -Subject: [PATCH 90/90] configure: fix typo -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit dc186bfe90665c13d589b3b4efd9009293e62c46) ---- - src/external/libhttp_parser.m4 | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/external/libhttp_parser.m4 b/src/external/libhttp_parser.m4 -index 504bdf0f66c95b3d224c677a205a46e6f8b44726..3a5ef0dbbc63423ad8e960d72e97ec4fb4481dd1 100644 ---- a/src/external/libhttp_parser.m4 -+++ b/src/external/libhttp_parser.m4 -@@ -17,6 +17,6 @@ AS_IF([test x"$found_http_parser" != xyes], - ], - [-L$sss_extra_libdir -lhttp_parser_strict])], - [AC_MSG_ERROR([ --You must have the header file http_parse.h installed to build sssd -+You must have the header file http_parser.h installed to build sssd - with secrets responder. If you want to build sssd without secret responder - then specify --without-secrets when running configure.])])]) --- -2.9.3 - diff --git a/SOURCES/0090-ifp-use-realloc-in-ifp_list_ctx_remaining_capacity.patch b/SOURCES/0090-ifp-use-realloc-in-ifp_list_ctx_remaining_capacity.patch new file mode 100644 index 0000000..c731709 --- /dev/null +++ b/SOURCES/0090-ifp-use-realloc-in-ifp_list_ctx_remaining_capacity.patch @@ -0,0 +1,92 @@ +From 674c5c3ba930a8546371ea8e138ff20a15090431 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 15 Dec 2017 12:09:06 +0100 +Subject: [PATCH 90/90] ifp: use realloc in ifp_list_ctx_remaining_capacity() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ifp_list_ctx_remaining_capacity() might be called multiple times if +results from multiple domains are added to the result list. + +The current use of talloc_zero_array() which was introduced with commit +b0b9222 will override results which are already in the list. This causes +a regression since it worked before. + +This patch replaces it with talloc_realloc(). + +Resolves https://pagure.io/SSSD/sssd/issue/3608 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 510ac193900a7bb9dfae10c0ca4607c224b265af) +--- + src/responder/ifp/ifp_private.h | 1 + + src/responder/ifp/ifpsrv_util.c | 16 ++++++++++++---- + 2 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h +index 13455bbf70860fb6dbfa3bb65fe3bd565d53257d..b406e7f5bab3e0dbc9696a5ab58e46b6ee7839eb 100644 +--- a/src/responder/ifp/ifp_private.h ++++ b/src/responder/ifp/ifp_private.h +@@ -93,6 +93,7 @@ struct ifp_list_ctx { + struct ifp_ctx *ctx; + + const char **paths; ++ size_t paths_max; + size_t path_count; + }; + +diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c +index 1df646339526186e862dcd09cddd971b77c20a8b..da4ab06796a99c930b7a4ad21ca408814f8b4c49 100644 +--- a/src/responder/ifp/ifpsrv_util.c ++++ b/src/responder/ifp/ifpsrv_util.c +@@ -372,7 +372,9 @@ struct ifp_list_ctx *ifp_list_ctx_new(struct sbus_request *sbus_req, + list_ctx->ctx = ctx; + list_ctx->dom = ctx->rctx->domains; + list_ctx->filter = filter; +- list_ctx->paths = talloc_zero_array(list_ctx, const char *, 1); ++ list_ctx->paths_max = 1; ++ list_ctx->paths = talloc_zero_array(list_ctx, const char *, ++ list_ctx->paths_max); + if (list_ctx->paths == NULL) { + talloc_free(list_ctx); + return NULL; +@@ -387,6 +389,7 @@ errno_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx, + { + size_t capacity = list_ctx->limit - list_ctx->path_count; + errno_t ret; ++ size_t c; + + if (list_ctx->limit == 0) { + capacity = entries; +@@ -396,19 +399,24 @@ errno_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx, + if (capacity < entries) { + DEBUG(SSSDBG_MINOR_FAILURE, + "IFP list request has limit of %"PRIu32" entries but back end " +- "returned %zu entries\n", list_ctx->limit, entries); ++ "returned %zu entries\n", list_ctx->limit, ++ list_ctx->path_count + entries); + } else { + capacity = entries; + } + + immediately: +- talloc_zfree(list_ctx->paths); +- list_ctx->paths = talloc_zero_array(list_ctx, const char *, capacity); ++ list_ctx->paths_max = list_ctx->path_count + capacity; ++ list_ctx->paths = talloc_realloc(list_ctx, list_ctx->paths, const char *, ++ list_ctx->paths_max); + if (list_ctx->paths == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n"); + ret = ENOMEM; + goto done; + } ++ for (c = list_ctx->path_count; c < list_ctx->paths_max; c++) { ++ list_ctx->paths[c] = NULL; ++ } + + *_capacity = capacity; + ret = EOK; +-- +2.14.3 + diff --git a/SOURCES/0091-IPA-Delay-the-first-periodic-refresh-of-trusted-doma.patch b/SOURCES/0091-IPA-Delay-the-first-periodic-refresh-of-trusted-doma.patch new file mode 100644 index 0000000..c828f38 --- /dev/null +++ b/SOURCES/0091-IPA-Delay-the-first-periodic-refresh-of-trusted-doma.patch @@ -0,0 +1,64 @@ +From a2f7322b9d8e47c0c93463d9fe1f37dc869799df Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 8 Jan 2018 18:30:57 +0100 +Subject: [PATCH 91/96] IPA: Delay the first periodic refresh of trusted + domains +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When the IPA subdomains code is initialized, the responders send a request +to fetch subdomains. This request first stores the list of trusted domains +to the cache and then runs the ipa-getkeytab helper. + +At the same time, the periodical task to update the subdomains is also +started. The task founds out that all the trusted domains are already known +and finishes the request, which replies to the Data Provider requests as +well even while the ipa-getkeytab request is still running. + +This unblocks requests from the responders, which try to connect to the AD +DCs even before the keytab is available, which switches the SSSD status to +offline. + +This patch simply delays the first periodic task in the IPA subdomains code +by 10 minutes, thus mitigating the startup race. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3601 + +Reviewed-by: Sumit Bose +Reviewed-by: Michal Židek +Reviewed-by: Pavel Březina +(cherry picked from commit 261a84355d9d033ca03f46727dbc2cf4921f154e) +--- + src/providers/ipa/ipa_subdomains.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index 3d3341a3eff5e55ae0c6fa5ad40603adc609e692..7d2cf80c8137a0428880c5474d4d94ca3ad1a5d4 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -2379,6 +2379,11 @@ errno_t ipa_subdomains_init(TALLOC_CTX *mem_ctx, + struct ipa_options *ipa_options; + time_t period; + errno_t ret; ++ /* Delay the first ptask that refreshes the trusted domains so that a race between ++ * the first responder-induced request and the ptask doesn't cause issues, see ++ * also upstream ticket #3601 ++ */ ++ const time_t ptask_first_delay = 600; + + ipa_options = ipa_id_ctx->ipa_options; + +@@ -2401,7 +2406,7 @@ errno_t ipa_subdomains_init(TALLOC_CTX *mem_ctx, + struct ipa_subdomains_ctx, struct dp_subdomains_data, struct dp_reply_std); + + period = be_ctx->domain->subdomain_refresh_interval; +- ret = be_ptask_create(sd_ctx, be_ctx, period, 0, 0, 0, period, ++ ret = be_ptask_create(sd_ctx, be_ctx, period, ptask_first_delay, 0, 0, period, + BE_PTASK_OFFLINE_DISABLE, 0, + ipa_subdomains_ptask_send, ipa_subdomains_ptask_recv, sd_ctx, + "Subdomains Refresh", NULL); +-- +2.14.3 + diff --git a/SOURCES/0091-pam_test_client-add-service-and-environment-to-PAM-t.patch b/SOURCES/0091-pam_test_client-add-service-and-environment-to-PAM-t.patch deleted file mode 100644 index e511e0d..0000000 --- a/SOURCES/0091-pam_test_client-add-service-and-environment-to-PAM-t.patch +++ /dev/null @@ -1,105 +0,0 @@ -From a5a6f0ab816be0dfd24b97a59c161adbe15ef406 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 24 Jan 2017 14:50:20 +0100 -Subject: [PATCH 91/96] pam_test_client: add service and environment to PAM - test client -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related to https://pagure.io/SSSD/sssd/issue/3292 - -Reviewed-by: Pavel Březina -(cherry picked from commit 7be6624d9eda369e9a4d70c8ee4939b3622229b3) ---- - src/sss_client/pam_test_client.c | 50 ++++++++++++++++++++++++++++++---------- - 1 file changed, 38 insertions(+), 12 deletions(-) - -diff --git a/src/sss_client/pam_test_client.c b/src/sss_client/pam_test_client.c -index 29d1fcbf01682668d51bf154736aec673bd46501..ea032a75b195a9bf8078ed7d248da154ab0c8430 100644 ---- a/src/sss_client/pam_test_client.c -+++ b/src/sss_client/pam_test_client.c -@@ -48,34 +48,44 @@ static struct pam_conv conv = { - # error "Missing text based pam conversation function" - #endif - -+#define DEFAULT_ACTION "acct" -+#define DEFAULT_SERVICE "system-auth" -+ - int main(int argc, char *argv[]) { - - pam_handle_t *pamh; - char *user; - char *action; -+ char *service; - int ret; -+ size_t c; -+ char **pam_env; - - if (argc == 1) { -- fprintf(stderr, "missing action and user name, using default\n"); -- action = strdup("auth"); -- user = strdup("dummy"); -+ fprintf(stderr, "Usage: pam_test_client USERNAME " -+ "[auth|acct|setc|chau|open|clos] [pam_service]\n"); -+ return 0; - } else if (argc == 2) { -- fprintf(stdout, "using first argument as action and default user name\n"); -- action = strdup(argv[1]); -- user = strdup("dummy"); -- } else { -- action = strdup(argv[1]); -- user = strdup(argv[2]); -+ fprintf(stderr, "using first argument as user name and default action " -+ "and service\n"); -+ } else if (argc == 3) { -+ fprintf(stderr, "using first argument as user name, second as action " -+ "and default service\n"); - } - -- if (action == NULL || user == NULL) { -+ user = strdup(argv[1]); -+ action = argc > 2 ? strdup(argv[2]) : strdup(DEFAULT_ACTION); -+ service = argc > 3 ? strdup(argv[3]) : strdup(DEFAULT_SERVICE); -+ -+ if (action == NULL || user == NULL || service == NULL) { - fprintf(stderr, "Out of memory!\n"); - return 1; - } - -- fprintf(stdout, "action: %s\nuser: %s\n", action,user); -+ fprintf(stdout, "user: %s\naction: %s\nservice: %s\n", -+ user, action, service); - -- ret = pam_start("sss_test", user, &conv, &pamh); -+ ret = pam_start(service, user, &conv, &pamh); - if (ret != PAM_SUCCESS) { - fprintf(stderr, "pam_start failed: %s\n", pam_strerror(pamh, ret)); - return 1; -@@ -109,7 +119,23 @@ int main(int argc, char *argv[]) { - fprintf(stderr, "unknown action\n"); - } - -+ fprintf(stderr, "PAM Environment:\n"); -+ pam_env = pam_getenvlist(pamh); -+ if (pam_env != NULL && pam_env[0] != NULL) { -+ for (c = 0; pam_env[c] != NULL; c++) { -+ fprintf(stderr, " - %s\n", pam_env[c]); -+ free(pam_env[c]); -+ } -+ } else { -+ fprintf(stderr, " - no env -\n"); -+ } -+ free(pam_env); -+ - pam_end(pamh, ret); - -+ free(user); -+ free(action); -+ free(service); -+ - return 0; - } --- -2.9.3 - diff --git a/SOURCES/0092-pam_test_client-add-SSSD-getpwnam-lookup.patch b/SOURCES/0092-pam_test_client-add-SSSD-getpwnam-lookup.patch deleted file mode 100644 index fc139dc..0000000 --- a/SOURCES/0092-pam_test_client-add-SSSD-getpwnam-lookup.patch +++ /dev/null @@ -1,142 +0,0 @@ -From 109c99463219be59fbf168a4075a74585193aef9 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 25 Jan 2017 16:50:00 +0100 -Subject: [PATCH 92/96] pam_test_client: add SSSD getpwnam lookup -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related to https://pagure.io/SSSD/sssd/issue/3292 - -Reviewed-by: Pavel Březina -(cherry picked from commit 435b3678de25d22eb8a6e892109d26c32f0760a4) ---- - Makefile.am | 10 ++++-- - src/sss_client/pam_test_client.c | 76 ++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 84 insertions(+), 2 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index 4a414f77df999b8b1d81f663fcc18dbd2d6d2dc4..368ebe54b8617cb5bafb079322582d5346b6c4df 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -3460,8 +3460,14 @@ if BUILD_WITH_LIBCURL - noinst_PROGRAMS += tcurl-test-tool - endif - --pam_test_client_SOURCES = src/sss_client/pam_test_client.c --pam_test_client_LDADD = $(PAM_LIBS) $(PAM_MISC_LIBS) -+pam_test_client_SOURCES = \ -+ src/sss_client/pam_test_client.c \ -+ $(NULL) -+pam_test_client_LDADD = \ -+ $(PAM_LIBS) \ -+ $(PAM_MISC_LIBS) \ -+ $(LIBADD_DL) \ -+ $(NULL) - - if BUILD_AUTOFS - autofs_test_client_SOURCES = \ -diff --git a/src/sss_client/pam_test_client.c b/src/sss_client/pam_test_client.c -index ea032a75b195a9bf8078ed7d248da154ab0c8430..69af612270492968b56d1c11de2bf56ebf57471f 100644 ---- a/src/sss_client/pam_test_client.c -+++ b/src/sss_client/pam_test_client.c -@@ -25,6 +25,11 @@ - #include - #include - #include -+#include -+#include -+#include -+#include -+#include - - #include - -@@ -51,6 +56,70 @@ static struct pam_conv conv = { - #define DEFAULT_ACTION "acct" - #define DEFAULT_SERVICE "system-auth" - -+#define DEFAULT_BUFSIZE 4096 -+ -+static int sss_getpwnam_check(const char *user) -+{ -+ void *dl_handle = NULL; -+ enum nss_status (*sss_getpwnam_r)(const char *name, struct passwd *result, -+ char *buffer, size_t buflen, -+ int *errnop); -+ struct passwd pwd = { 0 }; -+ enum nss_status status; -+ char *buffer = NULL; -+ size_t buflen; -+ int nss_errno; -+ int ret; -+ -+ dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW); -+ if (dl_handle == NULL) { -+ fprintf(stderr, "dlopen failed with [%s].\n", dlerror()); -+ ret = EIO; -+ goto done; -+ } -+ -+ sss_getpwnam_r = dlsym(dl_handle, "_nss_sss_getpwnam_r"); -+ if (sss_getpwnam_r == NULL) { -+ fprintf(stderr, "dlsym failed with [%s].\n", dlerror()); -+ ret = EIO; -+ goto done; -+ } -+ -+ buflen = DEFAULT_BUFSIZE; -+ buffer = malloc(buflen); -+ if (buffer == NULL) { -+ fprintf(stderr, "malloc failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ status = sss_getpwnam_r(user, &pwd, buffer, buflen, &nss_errno); -+ if (status != NSS_STATUS_SUCCESS) { -+ fprintf(stderr, "sss_getpwnam_r failed with [%d].\n", status); -+ ret = EIO; -+ goto done; -+ } -+ -+ fprintf(stdout, "SSSD nss user lookup result:\n"); -+ fprintf(stdout, " - user name: %s\n", pwd.pw_name); -+ fprintf(stdout, " - user id: %d\n", pwd.pw_uid); -+ fprintf(stdout, " - group id: %d\n", pwd.pw_gid); -+ fprintf(stdout, " - gecos: %s\n", pwd.pw_gecos); -+ fprintf(stdout, " - home directory: %s\n", pwd.pw_dir); -+ fprintf(stdout, " - shell: %s\n", pwd.pw_shell); -+ -+ ret = 0; -+ -+done: -+ if (dl_handle != NULL) { -+ dlclose(dl_handle); -+ } -+ -+ free(buffer); -+ -+ return ret; -+} -+ - int main(int argc, char *argv[]) { - - pam_handle_t *pamh; -@@ -85,6 +154,13 @@ int main(int argc, char *argv[]) { - fprintf(stdout, "user: %s\naction: %s\nservice: %s\n", - user, action, service); - -+ if (*user != '\0') { -+ ret = sss_getpwnam_check(user); -+ if (ret != 0) { -+ fprintf(stderr, "User name lookup with [%s] failed.\n", user); -+ } -+ } -+ - ret = pam_start(service, user, &conv, &pamh); - if (ret != PAM_SUCCESS) { - fprintf(stderr, "pam_start failed: %s\n", pam_strerror(pamh, ret)); --- -2.9.3 - diff --git a/SOURCES/0092-sysdb-add-userMappedCertificate-to-the-index.patch b/SOURCES/0092-sysdb-add-userMappedCertificate-to-the-index.patch new file mode 100644 index 0000000..346c8b5 --- /dev/null +++ b/SOURCES/0092-sysdb-add-userMappedCertificate-to-the-index.patch @@ -0,0 +1,55 @@ +From 57a83eb8657a125d203a335b052d965c7a3b15de Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 8 Jan 2018 18:22:17 +0100 +Subject: [PATCH 92/96] sysdb: add userMappedCertificate to the index +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to https://pagure.io/SSSD/sssd/issue/3503 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 5b78fff78bb44d1af5420db23b02210f755f5f17) +--- + src/db/sysdb_private.h | 1 + + src/db/sysdb_upgrade.c | 12 ++++++++++++ + 2 files changed, 13 insertions(+) + +diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h +index cac06ba46da23080d1ab661502d0792bd37b9291..c0a8e29ab9578acb27cf8d1db049c4260904fdda 100644 +--- a/src/db/sysdb_private.h ++++ b/src/db/sysdb_private.h +@@ -78,6 +78,7 @@ + "@IDXATTR: canonicalUserPrincipalName\n" \ + "@IDXATTR: uniqueID\n" \ + "@IDXATTR: mail\n" \ ++ "@IDXATTR: userMappedCertificate\n" \ + "\n" \ + "dn: @MODULES\n" \ + "@LIST: asq,memberof\n" \ +diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c +index bc157a24664239bc1255e49a1825243a07acc90f..46df971e98f73dc28bc6764a478f13d871515124 100644 +--- a/src/db/sysdb_upgrade.c ++++ b/src/db/sysdb_upgrade.c +@@ -2475,6 +2475,18 @@ int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver) + goto done; + } + ++ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_USER_MAPPED_CERT); ++ if (ret != LDB_SUCCESS) { ++ ret = ENOMEM; ++ goto done; ++ } ++ + ret = ldb_modify(sysdb->ldb, msg); + if (ret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(ret); +-- +2.14.3 + diff --git a/SOURCES/0093-AD-Inherit-the-MPG-setting-from-the-main-domain.patch b/SOURCES/0093-AD-Inherit-the-MPG-setting-from-the-main-domain.patch new file mode 100644 index 0000000..875f5fb --- /dev/null +++ b/SOURCES/0093-AD-Inherit-the-MPG-setting-from-the-main-domain.patch @@ -0,0 +1,48 @@ +From e67f94d854ef125626294771473a1204726eeba4 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 15 Jan 2018 22:11:24 +0100 +Subject: [PATCH 93/96] AD: Inherit the MPG setting from the main domain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the auto_private_groups option was set in the domain section for +direct integration, it only had an effect on the joined domain, not any +of the subdomains, so requesting a user from the child domain would look +like this: + $ id childuser@child.win.trust.test + uid=30000(childuser@child.win.trust.test) gid=40000(usergroup@child.win.trust.test) groups=40000(usergroup@child.win.trust.test) +The expected result, visible after this patch is: + $ id childuser@child.win.trust.test + uid=30000(childuser@child.win.trust.test) gid=30000(childuser@child.win.trust.test) groups=30000(childuser@child.win.trust.test),40000(usergroup@child.win.trust.test) + +Resolves: +https://pagure.io/SSSD/sssd/issue/3613 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 29ebf45f96b13590ae76a19c7c16c53f172e4ae4) +--- + src/providers/ad/ad_subdomains.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 3fb9b950f171d85817cce35ac92ad7c4974ccb68..1b9483a5dce937d6acdd813486a1e8c18210d35f 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -391,6 +391,13 @@ ad_subdom_store(struct sdap_idmap_ctx *idmap_ctx, + } + + mpg = sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, name, sid_str); ++ if (mpg == false) { ++ /* Domains that use the POSIX attributes set by the admin must ++ * inherit the MPG setting from the parent domain so that the ++ * auto_private_groups options works for trusted domains as well ++ */ ++ mpg = domain->mpg; ++ } + + ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str, + mpg, enumerate, domain->forest, 0, NULL); +-- +2.14.3 + diff --git a/SOURCES/0093-sss_sifp-update-method-names.patch b/SOURCES/0093-sss_sifp-update-method-names.patch deleted file mode 100644 index 0dac7de..0000000 --- a/SOURCES/0093-sss_sifp-update-method-names.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 52622fbb51d972ba1f02ff0c7dff2e9fa7adf96c Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 16 Mar 2017 11:37:41 +0100 -Subject: [PATCH 93/96] sss_sifp: update method names -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related to https://pagure.io/SSSD/sssd/issue/3292 - -Reviewed-by: Pavel Březina -(cherry picked from commit 40ff10d73063949ca699670ca212e96b809d5fcd) ---- - Makefile.am | 2 +- - src/lib/sifp/sss_sifp_common.c | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index 368ebe54b8617cb5bafb079322582d5346b6c4df..b16a71cc9e07f21d02b4ceb3f41a8e9de0591ec9 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -1221,7 +1221,7 @@ libsss_simpleifp_la_LIBADD = \ - $(DHASH_LIBS) - libsss_simpleifp_la_LDFLAGS = \ - -Wl,--version-script,$(srcdir)/src/lib/sifp/sss_simpleifp.exports \ -- -version-info 1:0:1 -+ -version-info 1:1:1 - - dist_noinst_DATA += src/lib/sifp/sss_simpleifp.exports - -diff --git a/src/lib/sifp/sss_sifp_common.c b/src/lib/sifp/sss_sifp_common.c -index bd1dc6a3108329d2c795dc0a259637e71964be9f..8913d0be3d43bd8707829001a5b476d9ab864fd8 100644 ---- a/src/lib/sifp/sss_sifp_common.c -+++ b/src/lib/sifp/sss_sifp_common.c -@@ -168,7 +168,7 @@ sss_sifp_fetch_user_by_uid(sss_sifp_ctx *ctx, - uint64_t _uid = uid; - - return sss_sifp_fetch_object_by_attr(ctx, IFP_PATH_USERS, IFACE_IFP_USERS, -- IFACE_IFP_USERS_USER, "UserByID", -+ IFACE_IFP_USERS_USER, "ByID", - DBUS_TYPE_UINT64, &_uid, _user); - } - -@@ -178,6 +178,6 @@ sss_sifp_fetch_user_by_name(sss_sifp_ctx *ctx, - sss_sifp_object **_user) - { - return sss_sifp_fetch_object_by_name(ctx, IFP_PATH_USERS, IFACE_IFP_USERS, -- IFACE_IFP_USERS_USER, "UserByName", -+ IFACE_IFP_USERS_USER, "ByName", - name, _user); - } --- -2.9.3 - diff --git a/SOURCES/0094-SDAP-skip-builtin-AD-groups-in-sdap_save_grpmem.patch b/SOURCES/0094-SDAP-skip-builtin-AD-groups-in-sdap_save_grpmem.patch new file mode 100644 index 0000000..72c1f2c --- /dev/null +++ b/SOURCES/0094-SDAP-skip-builtin-AD-groups-in-sdap_save_grpmem.patch @@ -0,0 +1,53 @@ +From 75da39f57ba0223be9bd9906cd3ed902623aed10 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 18 Dec 2017 20:30:04 +0100 +Subject: [PATCH 94/96] SDAP: skip builtin AD groups in sdap_save_grpmem() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +While processing group memberships SSSD might accidentally save builtin +or other well known AD groups. With this patch those groups are skipped +similar as e.g. in sdap_save_group(). + +Resolves: +https://pagure.io/SSSD/sssd/issue/3610 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit c36a66b7fb77cff29400c751b363a342923e122e) +--- + src/providers/ldap/sdap_async_groups.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c +index b1cfb7e4a4c054e5d365da5fca65da27c9ef5461..bbe6f1386eadbe4eb7b47bea9e5a6bb8ff4ee8eb 100644 +--- a/src/providers/ldap/sdap_async_groups.c ++++ b/src/providers/ldap/sdap_async_groups.c +@@ -880,6 +880,8 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx, + int ret; + const char *remove_attrs[] = {SYSDB_MEMBER, SYSDB_ORIG_MEMBER, SYSDB_GHOST, + NULL}; ++ const char *check_dom; ++ const char *check_name; + + if (dom->ignore_group_members) { + DEBUG(SSSDBG_CRIT_FAILURE, +@@ -905,6 +907,15 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx, + group_dom = sss_get_domain_by_sid_ldap_fallback(get_domains_head(dom), + group_sid); + if (group_dom == NULL) { ++ ret = well_known_sid_to_name(group_sid, &check_dom, &check_name); ++ if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Skipping group with SID [%s][%s\\%s] which is " ++ "currently not handled by SSSD.\n", ++ group_sid, check_dom, check_name); ++ return EOK; ++ } ++ + DEBUG(SSSDBG_TRACE_FUNC, "SID [%s] does not belong to any known " + "domain, using [%s].\n", group_sid, + dom->name); +-- +2.14.3 + diff --git a/SOURCES/0094-pam_test_client-add-InfoPipe-user-lookup.patch b/SOURCES/0094-pam_test_client-add-InfoPipe-user-lookup.patch deleted file mode 100644 index 6d20370..0000000 --- a/SOURCES/0094-pam_test_client-add-InfoPipe-user-lookup.patch +++ /dev/null @@ -1,131 +0,0 @@ -From acefbdd65a083b5d9577d9f683ac64e358c2f9c0 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 16 Mar 2017 11:38:20 +0100 -Subject: [PATCH 94/96] pam_test_client: add InfoPipe user lookup -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related to https://pagure.io/SSSD/sssd/issue/3292 - -Reviewed-by: Pavel Březina -(cherry picked from commit 9be97c9cc69e5e6e568d7e21f61a46c3ae2dc387) ---- - Makefile.am | 1 + - src/sss_client/pam_test_client.c | 71 ++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 72 insertions(+) - -diff --git a/Makefile.am b/Makefile.am -index b16a71cc9e07f21d02b4ceb3f41a8e9de0591ec9..c4d252357356c2d5452a414fd360fc5370b2c775 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -3467,6 +3467,7 @@ pam_test_client_LDADD = \ - $(PAM_LIBS) \ - $(PAM_MISC_LIBS) \ - $(LIBADD_DL) \ -+ libsss_simpleifp.la \ - $(NULL) - - if BUILD_AUTOFS -diff --git a/src/sss_client/pam_test_client.c b/src/sss_client/pam_test_client.c -index 69af612270492968b56d1c11de2bf56ebf57471f..40ef3f6d480c0108c985fce7e34e983d145f237e 100644 ---- a/src/sss_client/pam_test_client.c -+++ b/src/sss_client/pam_test_client.c -@@ -30,9 +30,12 @@ - #include - #include - #include -+#include - - #include - -+#include "lib/sifp/sss_sifp.h" -+ - #ifdef HAVE_SECURITY_PAM_MISC_H - # include - #elif defined(HAVE_SECURITY_OPENPAM_H) -@@ -58,6 +61,69 @@ static struct pam_conv conv = { - - #define DEFAULT_BUFSIZE 4096 - -+static int get_ifp_user(const char *user) -+{ -+ sss_sifp_ctx *sifp; -+ sss_sifp_error error; -+ sss_sifp_object *user_obj; -+ const char *tmp_str; -+ uint32_t tmp_uint32; -+ size_t c; -+ -+ struct ifp_user_attr { -+ const char *name; -+ bool is_string; -+ } ifp_user_attr[] = { -+ { "name", true }, -+ { "uidNumber", false }, -+ { "gidNumber", false }, -+ { "gecos", true }, -+ { "homeDirectory", true }, -+ { "loginShell", true }, -+ { NULL, false } -+ }; -+ -+ error = sss_sifp_init(&sifp); -+ if (error != SSS_SIFP_OK) { -+ fprintf(stderr, "Unable to connect to the InfoPipe"); -+ return EFAULT; -+ } -+ -+ error = sss_sifp_fetch_user_by_name(sifp, user, &user_obj); -+ if (error != SSS_SIFP_OK) { -+ fprintf(stderr, "Unable to get user object"); -+ return EIO; -+ } -+ -+ fprintf(stdout, "SSSD InfoPipe user lookup result:\n"); -+ for (c = 0; ifp_user_attr[c].name != NULL; c++) { -+ if (ifp_user_attr[c].is_string) { -+ error = sss_sifp_find_attr_as_string(user_obj->attrs, -+ ifp_user_attr[c].name, -+ &tmp_str); -+ } else { -+ error = sss_sifp_find_attr_as_uint32(user_obj->attrs, -+ ifp_user_attr[c].name, -+ &tmp_uint32); -+ } -+ if (error != SSS_SIFP_OK) { -+ fprintf(stderr, "Unable to get user name attr"); -+ return EIO; -+ } -+ -+ if (ifp_user_attr[c].is_string) { -+ fprintf(stdout, " - %s: %s\n", ifp_user_attr[c].name, tmp_str); -+ } else { -+ fprintf(stdout, " - %s: %"PRIu32"\n", ifp_user_attr[c].name, -+ tmp_uint32); -+ } -+ } -+ -+ sss_sifp_free_object(sifp, &user_obj); -+ sss_sifp_free(&sifp); -+ return 0; -+} -+ - static int sss_getpwnam_check(const char *user) - { - void *dl_handle = NULL; -@@ -159,6 +225,11 @@ int main(int argc, char *argv[]) { - if (ret != 0) { - fprintf(stderr, "User name lookup with [%s] failed.\n", user); - } -+ -+ ret = get_ifp_user(user); -+ if (ret != 0) { -+ fprintf(stderr, "InforPipe User lookup with [%s] failed.\n", user); -+ } - } - - ret = pam_start(service, user, &conv, &pamh); --- -2.9.3 - diff --git a/SOURCES/0095-SYSDB-Read-the-ldb_message-from-loop-s-index-counter.patch b/SOURCES/0095-SYSDB-Read-the-ldb_message-from-loop-s-index-counter.patch new file mode 100644 index 0000000..b0469ba --- /dev/null +++ b/SOURCES/0095-SYSDB-Read-the-ldb_message-from-loop-s-index-counter.patch @@ -0,0 +1,39 @@ +From 80e4aa68587d5a70bfd41f78f17902bf06b447a1 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 23 Jan 2018 11:11:14 +0100 +Subject: [PATCH 95/96] SYSDB: Read the ldb_message from loop's index counter + when reading subdomain UPNs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There was a typo in code that read the UPN suffixes from the subdomain +ldb_message. As a result, the UPN suffixes from the first domain were +always consulted for all domains. + +Related to: +https://pagure.io/SSSD/sssd/issue/3431 + +Reviewed-by: Lukáš Slebodník +Reviewed-by: Sumit Bose +(cherry picked from commit a8a3fcbf6f75a7c2665e8bf503c186e07dfab333) +--- + src/db/sysdb_subdomains.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index 0dd05c24c963f12a28ef6f6b64dc40faa7fcc649..b0863b7935b060cb545197005c84f51efbc2d49c 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -386,7 +386,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain, + SYSDB_SUBDOMAIN_FOREST, NULL); + + upn_suffixes = NULL; +- tmp_el = ldb_msg_find_element(res->msgs[0], SYSDB_UPN_SUFFIXES); ++ tmp_el = ldb_msg_find_element(res->msgs[i], SYSDB_UPN_SUFFIXES); + if (tmp_el != NULL) { + upn_suffixes = sss_ldb_el_to_string_list(tmp_ctx, tmp_el); + if (upn_suffixes == NULL) { +-- +2.14.3 + diff --git a/SOURCES/0095-sssctl-integrate-pam_test_client-into-sssctl.patch b/SOURCES/0095-sssctl-integrate-pam_test_client-into-sssctl.patch deleted file mode 100644 index d942a65..0000000 --- a/SOURCES/0095-sssctl-integrate-pam_test_client-into-sssctl.patch +++ /dev/null @@ -1,359 +0,0 @@ -From 1bc25dba8f4725ef34e394d8e8eee42dbdaed924 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 30 Mar 2017 16:21:15 +0200 -Subject: [PATCH 95/96] sssctl: integrate pam_test_client into sssctl -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Pavel Březina -(cherry picked from commit 4a9160e2b3b9c531e2b4a7884f49bfbb4a07a992) ---- - Makefile.am | 16 +-- - po/POTFILES.in | 1 - - src/tools/sssctl/sssctl.c | 1 + - src/tools/sssctl/sssctl.h | 4 + - .../sssctl/sssctl_user_checks.c} | 122 +++++++++++---------- - 5 files changed, 72 insertions(+), 72 deletions(-) - rename src/{sss_client/pam_test_client.c => tools/sssctl/sssctl_user_checks.c} (62%) - -diff --git a/Makefile.am b/Makefile.am -index c4d252357356c2d5452a414fd360fc5370b2c775..f5ac363a35e4aae51e8b70bad27c7fc824be10f2 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -1724,11 +1724,15 @@ sssctl_SOURCES = \ - src/tools/sssctl/sssctl_domains.c \ - src/tools/sssctl/sssctl_sifp.c \ - src/tools/sssctl/sssctl_config.c \ -+ src/tools/sssctl/sssctl_user_checks.c \ - $(SSSD_TOOLS_OBJ) \ - $(NULL) - sssctl_LDADD = \ - $(TOOLS_LIBS) \ - $(SSSD_INTERNAL_LTLIBS) \ -+ $(PAM_LIBS) \ -+ $(PAM_MISC_LIBS) \ -+ $(LIBADD_DL) \ - libsss_simpleifp.la \ - $(NULL) - sssctl_CFLAGS = \ -@@ -3449,7 +3453,7 @@ endif # BUILD_KCM - - endif # HAVE_CMOCKA - --noinst_PROGRAMS = pam_test_client -+noinst_PROGRAMS = - if BUILD_SUDO - noinst_PROGRAMS += sss_sudo_cli - endif -@@ -3460,16 +3464,6 @@ if BUILD_WITH_LIBCURL - noinst_PROGRAMS += tcurl-test-tool - endif - --pam_test_client_SOURCES = \ -- src/sss_client/pam_test_client.c \ -- $(NULL) --pam_test_client_LDADD = \ -- $(PAM_LIBS) \ -- $(PAM_MISC_LIBS) \ -- $(LIBADD_DL) \ -- libsss_simpleifp.la \ -- $(NULL) -- - if BUILD_AUTOFS - autofs_test_client_SOURCES = \ - src/sss_client/autofs/autofs_test_client.c \ -diff --git a/po/POTFILES.in b/po/POTFILES.in -index ee532def223fdd5db632ad98fd11a57e38d0e125..f4e4e095f9e4025d129b6b13422bdd0bc07c8e1a 100644 ---- a/po/POTFILES.in -+++ b/po/POTFILES.in -@@ -9,7 +9,6 @@ src/sss_client/common.c - src/sss_client/nss_group.c - src/sss_client/nss_passwd.c - src/sss_client/pam_sss.c --src/sss_client/pam_test_client.c - src/sss_client/ssh/sss_ssh_authorizedkeys.c - src/sss_client/ssh/sss_ssh_knownhostsproxy.c - src/tools/sss_useradd.c -diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c -index e1cf46382cd1dee54cd372ca500368f149411b78..509d2e1a00d3b57b541590ce7db5f94d2ff43add 100644 ---- a/src/tools/sssctl/sssctl.c -+++ b/src/tools/sssctl/sssctl.c -@@ -263,6 +263,7 @@ int main(int argc, const char **argv) - SSS_TOOL_DELIMITER("SSSD Status:"), - SSS_TOOL_COMMAND("domain-list", "List available domains", 0, sssctl_domain_list), - SSS_TOOL_COMMAND("domain-status", "Print information about domain", 0, sssctl_domain_status), -+ SSS_TOOL_COMMAND("user-checks", "Print information about a user and check authentication", 0, sssctl_user_checks), - SSS_TOOL_DELIMITER("Information about cached content:"), - SSS_TOOL_COMMAND("user-show", "Information about cached user", 0, sssctl_user_show), - SSS_TOOL_COMMAND("group-show", "Information about cached group", 0, sssctl_group_show), -diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h -index 5270a9ec62dfb288511af179a99e9a542ea26ec4..22626e2210252e5e3fadeb6c5d01d4620cd60e5b 100644 ---- a/src/tools/sssctl/sssctl.h -+++ b/src/tools/sssctl/sssctl.h -@@ -121,4 +121,8 @@ errno_t sssctl_netgroup_show(struct sss_cmdline *cmdline, - errno_t sssctl_config_check(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt); -+ -+errno_t sssctl_user_checks(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt); - #endif /* _SSSCTL_H_ */ -diff --git a/src/sss_client/pam_test_client.c b/src/tools/sssctl/sssctl_user_checks.c -similarity index 62% -rename from src/sss_client/pam_test_client.c -rename to src/tools/sssctl/sssctl_user_checks.c -index 40ef3f6d480c0108c985fce7e34e983d145f237e..7c7b564bd29100382c9bbef7a3131c379e9aa97e 100644 ---- a/src/sss_client/pam_test_client.c -+++ b/src/tools/sssctl/sssctl_user_checks.c -@@ -35,6 +35,9 @@ - #include - - #include "lib/sifp/sss_sifp.h" -+#include "util/util.h" -+#include "tools/common/sss_tools.h" -+#include "tools/sssctl/sssctl.h" - - #ifdef HAVE_SECURITY_PAM_MISC_H - # include -@@ -85,17 +88,17 @@ static int get_ifp_user(const char *user) - - error = sss_sifp_init(&sifp); - if (error != SSS_SIFP_OK) { -- fprintf(stderr, "Unable to connect to the InfoPipe"); -+ fprintf(stderr, _("Unable to connect to the InfoPipe")); - return EFAULT; - } - - error = sss_sifp_fetch_user_by_name(sifp, user, &user_obj); - if (error != SSS_SIFP_OK) { -- fprintf(stderr, "Unable to get user object"); -+ fprintf(stderr, _("Unable to get user object")); - return EIO; - } - -- fprintf(stdout, "SSSD InfoPipe user lookup result:\n"); -+ fprintf(stdout, _("SSSD InfoPipe user lookup result:\n")); - for (c = 0; ifp_user_attr[c].name != NULL; c++) { - if (ifp_user_attr[c].is_string) { - error = sss_sifp_find_attr_as_string(user_obj->attrs, -@@ -107,7 +110,7 @@ static int get_ifp_user(const char *user) - &tmp_uint32); - } - if (error != SSS_SIFP_OK) { -- fprintf(stderr, "Unable to get user name attr"); -+ fprintf(stderr, _("Unable to get user name attr")); - return EIO; - } - -@@ -118,6 +121,7 @@ static int get_ifp_user(const char *user) - tmp_uint32); - } - } -+ fprintf(stdout, "\n"); - - sss_sifp_free_object(sifp, &user_obj); - sss_sifp_free(&sifp); -@@ -139,14 +143,14 @@ static int sss_getpwnam_check(const char *user) - - dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW); - if (dl_handle == NULL) { -- fprintf(stderr, "dlopen failed with [%s].\n", dlerror()); -+ fprintf(stderr, _("dlopen failed with [%s].\n"), dlerror()); - ret = EIO; - goto done; - } - - sss_getpwnam_r = dlsym(dl_handle, "_nss_sss_getpwnam_r"); - if (sss_getpwnam_r == NULL) { -- fprintf(stderr, "dlsym failed with [%s].\n", dlerror()); -+ fprintf(stderr, _("dlsym failed with [%s].\n"), dlerror()); - ret = EIO; - goto done; - } -@@ -154,25 +158,25 @@ static int sss_getpwnam_check(const char *user) - buflen = DEFAULT_BUFSIZE; - buffer = malloc(buflen); - if (buffer == NULL) { -- fprintf(stderr, "malloc failed.\n"); -+ fprintf(stderr, _("malloc failed.\n")); - ret = ENOMEM; - goto done; - } - - status = sss_getpwnam_r(user, &pwd, buffer, buflen, &nss_errno); - if (status != NSS_STATUS_SUCCESS) { -- fprintf(stderr, "sss_getpwnam_r failed with [%d].\n", status); -+ fprintf(stderr, _("sss_getpwnam_r failed with [%d].\n"), status); - ret = EIO; - goto done; - } - -- fprintf(stdout, "SSSD nss user lookup result:\n"); -- fprintf(stdout, " - user name: %s\n", pwd.pw_name); -- fprintf(stdout, " - user id: %d\n", pwd.pw_uid); -- fprintf(stdout, " - group id: %d\n", pwd.pw_gid); -- fprintf(stdout, " - gecos: %s\n", pwd.pw_gecos); -- fprintf(stdout, " - home directory: %s\n", pwd.pw_dir); -- fprintf(stdout, " - shell: %s\n", pwd.pw_shell); -+ fprintf(stdout, _("SSSD nss user lookup result:\n")); -+ fprintf(stdout, _(" - user name: %s\n"), pwd.pw_name); -+ fprintf(stdout, _(" - user id: %d\n"), pwd.pw_uid); -+ fprintf(stdout, _(" - group id: %d\n"), pwd.pw_gid); -+ fprintf(stdout, _(" - gecos: %s\n"), pwd.pw_gecos); -+ fprintf(stdout, _(" - home directory: %s\n"), pwd.pw_dir); -+ fprintf(stdout, _(" - shell: %s\n\n"), pwd.pw_shell); - - ret = 0; - -@@ -186,87 +190,89 @@ done: - return ret; - } - --int main(int argc, char *argv[]) { -+errno_t sssctl_user_checks(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt) -+{ - - pam_handle_t *pamh; -- char *user; -- char *action; -- char *service; -+ const char *user = NULL; -+ const char *action = DEFAULT_ACTION; -+ const char *service = DEFAULT_SERVICE; - int ret; - size_t c; - char **pam_env; - -- if (argc == 1) { -- fprintf(stderr, "Usage: pam_test_client USERNAME " -- "[auth|acct|setc|chau|open|clos] [pam_service]\n"); -- return 0; -- } else if (argc == 2) { -- fprintf(stderr, "using first argument as user name and default action " -- "and service\n"); -- } else if (argc == 3) { -- fprintf(stderr, "using first argument as user name, second as action " -- "and default service\n"); -- } -- -- user = strdup(argv[1]); -- action = argc > 2 ? strdup(argv[2]) : strdup(DEFAULT_ACTION); -- service = argc > 3 ? strdup(argv[3]) : strdup(DEFAULT_SERVICE); -+ /* Parse command line. */ -+ struct poptOption options[] = { -+ { "action", 'a', POPT_ARG_STRING, &action, 0, -+ _("PAM action [auth|acct|setc|chau|open|clos], default: " -+ DEFAULT_ACTION), NULL }, -+ { "service", 's', POPT_ARG_STRING, &service, 0, -+ _("PAM service, default: " DEFAULT_SERVICE), NULL }, -+ POPT_TABLEEND -+ }; - -- if (action == NULL || user == NULL || service == NULL) { -- fprintf(stderr, "Out of memory!\n"); -- return 1; -+ ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL, -+ NULL, NULL, "USERNAME", _("Specify user name."), -+ &user, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); -+ return ret; - } - -- fprintf(stdout, "user: %s\naction: %s\nservice: %s\n", -+ fprintf(stdout, _("user: %s\naction: %s\nservice: %s\n\n"), - user, action, service); - - if (*user != '\0') { - ret = sss_getpwnam_check(user); - if (ret != 0) { -- fprintf(stderr, "User name lookup with [%s] failed.\n", user); -+ fprintf(stderr, _("User name lookup with [%s] failed.\n"), user); - } - - ret = get_ifp_user(user); - if (ret != 0) { -- fprintf(stderr, "InforPipe User lookup with [%s] failed.\n", user); -+ fprintf(stderr, _("InforPipe User lookup with [%s] failed.\n"), -+ user); - } - } - - ret = pam_start(service, user, &conv, &pamh); - if (ret != PAM_SUCCESS) { -- fprintf(stderr, "pam_start failed: %s\n", pam_strerror(pamh, ret)); -+ fprintf(stderr, _("pam_start failed: %s\n"), pam_strerror(pamh, ret)); - return 1; - } - - if ( strncmp(action, "auth", 4)== 0 ) { -- fprintf(stdout, "testing pam_authenticate\n"); -+ fprintf(stdout, _("testing pam_authenticate\n\n")); - ret = pam_authenticate(pamh, 0); -- fprintf(stderr, "pam_authenticate: %s\n", pam_strerror(pamh, ret)); -+ fprintf(stderr, _("pam_authenticate: %s\n\n"), pam_strerror(pamh, ret)); - } else if ( strncmp(action, "chau", 4)== 0 ) { -- fprintf(stdout, "testing pam_chauthtok\n"); -+ fprintf(stdout, _("testing pam_chauthtok\n\n")); - ret = pam_chauthtok(pamh, 0); -- fprintf(stderr, "pam_chauthtok: %s\n", pam_strerror(pamh, ret)); -+ fprintf(stderr, _("pam_chauthtok: %s\n\n"), pam_strerror(pamh, ret)); - } else if ( strncmp(action, "acct", 4)== 0 ) { -- fprintf(stdout, "testing pam_acct_mgmt\n"); -+ fprintf(stdout, _("testing pam_acct_mgmt\n\n")); - ret = pam_acct_mgmt(pamh, 0); -- fprintf(stderr, "pam_acct_mgmt: %s\n", pam_strerror(pamh, ret)); -+ fprintf(stderr, _("pam_acct_mgmt: %s\n\n"), pam_strerror(pamh, ret)); - } else if ( strncmp(action, "setc", 4)== 0 ) { -- fprintf(stdout, "testing pam_setcred\n"); -+ fprintf(stdout, _("testing pam_setcred\n\n")); - ret = pam_setcred(pamh, 0); -- fprintf(stderr, "pam_setcred: %d[%s]\n", ret, pam_strerror(pamh, ret)); -+ fprintf(stderr, _("pam_setcred: [%s]\n\n"), pam_strerror(pamh, ret)); - } else if ( strncmp(action, "open", 4)== 0 ) { -- fprintf(stdout, "testing pam_open_session\n"); -+ fprintf(stdout, _("testing pam_open_session\n\n")); - ret = pam_open_session(pamh, 0); -- fprintf(stderr, "pam_open_session: %s\n", pam_strerror(pamh, ret)); -+ fprintf(stderr, _("pam_open_session: %s\n\n"), pam_strerror(pamh, ret)); - } else if ( strncmp(action, "clos", 4)== 0 ) { -- fprintf(stdout, "testing pam_close_session\n"); -+ fprintf(stdout, _("testing pam_close_session\n\n")); - ret = pam_close_session(pamh, 0); -- fprintf(stderr, "pam_close_session: %s\n", pam_strerror(pamh, ret)); -+ fprintf(stderr, _("pam_close_session: %s\n\n"), -+ pam_strerror(pamh, ret)); - } else { -- fprintf(stderr, "unknown action\n"); -+ fprintf(stderr, _("unknown action\n")); - } - -- fprintf(stderr, "PAM Environment:\n"); -+ fprintf(stderr, _("PAM Environment:\n")); - pam_env = pam_getenvlist(pamh); - if (pam_env != NULL && pam_env[0] != NULL) { - for (c = 0; pam_env[c] != NULL; c++) { -@@ -274,15 +280,11 @@ int main(int argc, char *argv[]) { - free(pam_env[c]); - } - } else { -- fprintf(stderr, " - no env -\n"); -+ fprintf(stderr, _(" - no env -\n")); - } - free(pam_env); - - pam_end(pamh, ret); - -- free(user); -- free(action); -- free(service); -- - return 0; - } --- -2.9.3 - diff --git a/SOURCES/0096-i18n-adding-sssctl-files.patch b/SOURCES/0096-i18n-adding-sssctl-files.patch deleted file mode 100644 index 84984cf..0000000 --- a/SOURCES/0096-i18n-adding-sssctl-files.patch +++ /dev/null @@ -1,34 +0,0 @@ -From e66f1df979b47519f9f51b6064154dae7ba5b396 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 7 Apr 2017 14:24:10 +0200 -Subject: [PATCH 96/96] i18n: adding sssctl files -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Pavel Březina -(cherry picked from commit dbeae483464e42238a84c6a5b8c3c4f5312ae643) ---- - po/POTFILES.in | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/po/POTFILES.in b/po/POTFILES.in -index f4e4e095f9e4025d129b6b13422bdd0bc07c8e1a..33e7ed7f9e9bc19f33fca8a1f2649b69b79a882f 100644 ---- a/po/POTFILES.in -+++ b/po/POTFILES.in -@@ -23,4 +23,12 @@ src/tools/sss_cache.c - src/tools/sss_debuglevel.c - src/tools/tools_util.c - src/tools/tools_util.h -+src/tools/sssctl/sssctl.c -+src/tools/sssctl/sssctl_cache.c -+src/tools/sssctl/sssctl_config.c -+src/tools/sssctl/sssctl_data.c -+src/tools/sssctl/sssctl_domains.c -+src/tools/sssctl/sssctl_logs.c -+src/tools/sssctl/sssctl_sifp.c -+src/tools/sssctl/sssctl_user_checks.c - src/util/util.h --- -2.9.3 - diff --git a/SOURCES/0096-nss-idmap-check-timed-muted-return-code.patch b/SOURCES/0096-nss-idmap-check-timed-muted-return-code.patch new file mode 100644 index 0000000..974484c --- /dev/null +++ b/SOURCES/0096-nss-idmap-check-timed-muted-return-code.patch @@ -0,0 +1,73 @@ +From 63c09393b926f0d00317a1ca1dc6c7c992c40f4e Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 16 Jan 2018 18:09:00 +0100 +Subject: [PATCH 96/96] nss-idmap: check timed muted return code + +Check return values and make sure the mutex is released in case of +errors. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 3e32cb2ad36a9dd2654c7f63469dc595f1bb8593) +--- + src/sss_client/idmap/common_ex.c | 2 ++ + src/sss_client/idmap/sss_nss_ex.c | 5 ++++- + src/sss_client/idmap/sss_nss_idmap.c | 5 ++++- + 3 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/src/sss_client/idmap/common_ex.c b/src/sss_client/idmap/common_ex.c +index 5efe9fabed7896ce674615472dbb256c4eae2144..e655bb864e063665cb56bcd3ff419e46c766478b 100644 +--- a/src/sss_client/idmap/common_ex.c ++++ b/src/sss_client/idmap/common_ex.c +@@ -83,6 +83,7 @@ int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms) + if (ret == 0) { + ret = clock_gettime(CLOCK_REALTIME, &endtime); + if (ret != 0) { ++ sss_nss_unlock(); + return ret; + } + +@@ -92,6 +93,7 @@ int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms) + TIMESPECSUB(&endtime, &starttime, &diff); + left = timeout_ms - TIMESPEC_TO_MS(&diff); + if (left <= 0) { ++ sss_nss_unlock(); + return EIO; + } else if (left > SSS_CLI_SOCKET_TIMEOUT) { + *time_left_ms = SSS_CLI_SOCKET_TIMEOUT; +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +index 861b1e1e92db4f7e6e8d74a812dc3c9220711773..af6a95180656b598bcb94c209dfa821cb0275f02 100644 +--- a/src/sss_client/idmap/sss_nss_ex.c ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -202,7 +202,10 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + } + } + +- sss_nss_timedlock(timeout, &time_left); ++ ret = sss_nss_timedlock(timeout, &time_left); ++ if (ret != 0) { ++ return ret; ++ } + + if (!skip_mc && !skip_data) { + /* previous thread might already initialize entry in mmap cache */ +diff --git a/src/sss_client/idmap/sss_nss_idmap.c b/src/sss_client/idmap/sss_nss_idmap.c +index 6e7685d2b1d80956b6a6668e9bbb146abd9e86ed..cbf8c11f2870e3574c75fe109cb19268e8a0b56d 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.c ++++ b/src/sss_client/idmap/sss_nss_idmap.c +@@ -257,7 +257,10 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd, + if (timeout == NO_TIMEOUT) { + sss_nss_lock(); + } else { +- sss_nss_timedlock(timeout, &time_left); ++ ret = sss_nss_timedlock(timeout, &time_left); ++ if (ret != 0) { ++ return ret; ++ } + } + + nret = sss_nss_make_request_timeout(cmd, &rd, time_left, &repbuf, &replen, +-- +2.14.3 + diff --git a/SOURCES/0097-DESKPROFILE-Add-checks-for-user-and-host-category.patch b/SOURCES/0097-DESKPROFILE-Add-checks-for-user-and-host-category.patch new file mode 100644 index 0000000..1199481 --- /dev/null +++ b/SOURCES/0097-DESKPROFILE-Add-checks-for-user-and-host-category.patch @@ -0,0 +1,155 @@ +From 2349423ad813e8a4fe090c283603b4cf18919662 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 22 Jan 2018 00:02:43 +0100 +Subject: [PATCH 97/97] DESKPROFILE: Add checks for user and host category +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +freeipa-deskprofile-plugin can have both user and host category set as +"all" and when it happens, no users and groups or hosts or hostgroups +are going to be set. + +Let's treat this expected (but so far missed) situation on SSSD side. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3449 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +(cherry picked from commit b72e444bc1cd2fe8d9617f09b446c678d4684fff) +--- + src/providers/ipa/ipa_deskprofile_rules_util.c | 100 ++++++++++++++++++++----- + 1 file changed, 82 insertions(+), 18 deletions(-) + +diff --git a/src/providers/ipa/ipa_deskprofile_rules_util.c b/src/providers/ipa/ipa_deskprofile_rules_util.c +index 53c433145666af00a994420ccd1a926b11937fc9..01b7d0527c2a15e0f4d2bdce1867ad0482fca7b0 100644 +--- a/src/providers/ipa/ipa_deskprofile_rules_util.c ++++ b/src/providers/ipa/ipa_deskprofile_rules_util.c +@@ -684,6 +684,8 @@ ipa_deskprofile_rules_save_rule_to_disk( + TALLOC_CTX *tmp_ctx; + const char *rule_name; + const char *data; ++ const char *hostcat; ++ const char *usercat; + char *shortname; + char *domainname; + char *base_dn; +@@ -722,6 +724,28 @@ ipa_deskprofile_rules_save_rule_to_disk( + goto done; + } + ++ ret = sysdb_attrs_get_string(rule, IPA_HOST_CATEGORY, &hostcat); ++ if (ret == ENOENT) { ++ hostcat = NULL; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Failed to get the Desktop Profile Rule host category for rule " ++ "\"%s\" [%d]: %s\n", ++ rule_name, ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sysdb_attrs_get_string(rule, IPA_USER_CATEGORY, &usercat); ++ if (ret == ENOENT) { ++ usercat = NULL; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Failed to get the Desktop Profile Rule user category for rule " ++ "\"%s\" [%d]: %s\n", ++ rule_name, ret, sss_strerror(ret)); ++ goto done; ++ } ++ + rule_prio = talloc_asprintf(tmp_ctx, "%06d", prio); + if (rule_prio == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate rule priority\n"); +@@ -753,26 +777,66 @@ ipa_deskprofile_rules_save_rule_to_disk( + goto done; + } + +- ret = ipa_deskprofile_rule_check_memberuser(tmp_ctx, domain, rule, +- rule_name, rule_prio, +- base_dn, username, +- &user_prio, &group_prio); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "ipa_deskprofile_rule_check_memberuser() failed [%d]: %s\n", +- ret, sss_strerror(ret)); +- goto done; ++ if (usercat != NULL && strcasecmp(usercat, "all") == 0) { ++ user_prio = talloc_strdup(tmp_ctx, rule_prio); ++ if (user_prio == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to allocate the user priority " ++ "when user category is \"all\"\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ group_prio = talloc_strdup(tmp_ctx, rule_prio); ++ if (group_prio == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to allocate the group priority " ++ "when user category is \"all\"\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } else { ++ ret = ipa_deskprofile_rule_check_memberuser(tmp_ctx, domain, rule, ++ rule_name, rule_prio, ++ base_dn, username, ++ &user_prio, &group_prio); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ipa_deskprofile_rule_check_memberuser() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } + } + +- ret = ipa_deskprofile_rule_check_memberhost(tmp_ctx, domain, rule, +- rule_name, rule_prio, +- base_dn, hostname, +- &host_prio, &hostgroup_prio); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "ipa_deskprofile_rule_check_memberhost() failed [%d]: %s\n", +- ret, sss_strerror(ret)); +- goto done; ++ if (hostcat != NULL && strcasecmp(hostcat, "all") == 0) { ++ host_prio = talloc_strdup(tmp_ctx, rule_prio); ++ if (host_prio == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to allocate the host priority " ++ "when host category is \"all\"\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ hostgroup_prio = talloc_strdup(tmp_ctx, rule_prio); ++ if (hostgroup_prio == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to allocate the hostgroup priority " ++ "when host category is \"all\"\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } else { ++ ret = ipa_deskprofile_rule_check_memberhost(tmp_ctx, domain, rule, ++ rule_name, rule_prio, ++ base_dn, hostname, ++ &host_prio, &hostgroup_prio); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ipa_deskprofile_rule_check_memberhost() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } + } + + ret = ipa_deskprofile_get_normalized_rule_name(mem_ctx, rule_name, +-- +2.14.3 + diff --git a/SOURCES/0097-responders-do-not-leak-selinux-context-on-clients-de.patch b/SOURCES/0097-responders-do-not-leak-selinux-context-on-clients-de.patch deleted file mode 100644 index a38530b..0000000 --- a/SOURCES/0097-responders-do-not-leak-selinux-context-on-clients-de.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 3a07827a3722fd2166b94af1f5790273fbac01eb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Mon, 3 Apr 2017 12:56:01 +0200 -Subject: [PATCH 97/99] responders: do not leak selinux context on clients - destruction -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The SELinux context created in get_client_cred is not talloc bound and -we were leaking it if available with each client's destruction. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3360 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 05c2c3047912fca1c1a35ab1c8d3157b05383495) ---- - src/responder/common/responder_common.c | 20 +++++++++++++++++++- - 1 file changed, 19 insertions(+), 1 deletion(-) - -diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c -index 154d7dc7718c437d10e152fcba98161e2034fb14..67e1deefdfde19c95a68029b11099579d851513f 100644 ---- a/src/responder/common/responder_common.c -+++ b/src/responder/common/responder_common.c -@@ -97,7 +97,7 @@ static errno_t get_client_cred(struct cli_ctx *cctx) - SEC_CTX secctx; - int ret; - -- cctx->creds = talloc(cctx, struct cli_creds); -+ cctx->creds = talloc_zero(cctx, struct cli_creds); - if (!cctx->creds) return ENOMEM; - - #ifdef HAVE_UCRED -@@ -464,6 +464,22 @@ static void client_fd_handler(struct tevent_context *ev, - - static errno_t setup_client_idle_timer(struct cli_ctx *cctx); - -+static int cli_ctx_destructor(struct cli_ctx *cctx) -+{ -+ if (cctx->creds == NULL) { -+ return 0; -+ } -+ -+ if (cctx->creds->selinux_ctx == NULL) { -+ return 0; -+ } -+ -+ SELINUX_context_free(cctx->creds->selinux_ctx); -+ cctx->creds->selinux_ctx = NULL; -+ -+ return 0; -+} -+ - struct accept_fd_ctx { - struct resp_ctx *rctx; - bool is_private; -@@ -520,6 +536,8 @@ static void accept_fd_handler(struct tevent_context *ev, - return; - } - -+ talloc_set_destructor(cctx, cli_ctx_destructor); -+ - len = sizeof(cctx->addr); - cctx->cfd = accept(fd, (struct sockaddr *)&cctx->addr, &len); - if (cctx->cfd == -1) { --- -2.9.3 - diff --git a/SOURCES/0098-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch b/SOURCES/0098-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch new file mode 100644 index 0000000..c0912b0 --- /dev/null +++ b/SOURCES/0098-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch @@ -0,0 +1,203 @@ +From ae37ee533a791e038aab47683278fced2bc0b687 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Thu, 1 Feb 2018 11:34:21 +0100 +Subject: [PATCH 98/99] SELINUX: Check if SELinux is managed in selinux_child +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If SELinux policy is not managed at all, don't call any SELinux user +handling functions and instead return that no update is needed. + +Pair-Programmed-With: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +Reviewed-by: Fabiano Fidêncio + +Resolves: +https://pagure.io/SSSD/sssd/issue/3618 +(cherry picked from commit 450b472a68abf442479755c7916c757907b35ea5) +--- + src/providers/ipa/selinux_child.c | 3 +- + src/util/sss_semanage.c | 82 +++++++++++++++++++++++++++++++-------- + src/util/util.h | 3 ++ + 3 files changed, 70 insertions(+), 18 deletions(-) + +diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c +index a7e20f715626d0f3ecef7cc06f3de5d44b6a15c1..c659976e80cb7317671da52fe4777ee821589e36 100644 +--- a/src/providers/ipa/selinux_child.c ++++ b/src/providers/ipa/selinux_child.c +@@ -27,7 +27,6 @@ + #include + #include + #include +-#include + + #include "util/util.h" + #include "util/child_common.h" +@@ -173,7 +172,7 @@ static bool seuser_needs_update(struct input_buffer *ibuf) + char *db_mls_range = NULL; + errno_t ret; + +- ret = getseuserbyname(ibuf->username, &db_seuser, &db_mls_range); ++ ret = sss_get_seuser(ibuf->username, &db_seuser, &db_mls_range); + DEBUG(SSSDBG_TRACE_INTERNAL, + "getseuserbyname: ret: %d seuser: %s mls: %s\n", + ret, db_seuser ? db_seuser : "unknown", +diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c +index 37278cc986a1ea49dc2218a635d52b9d54ca089d..25b6bcdad2ad7e7ac710497f13d6a6e22360b0dd 100644 +--- a/src/util/sss_semanage.c ++++ b/src/util/sss_semanage.c +@@ -22,8 +22,9 @@ + #include "config.h" + + #include +-#ifdef HAVE_SEMANAGE ++#if defined(HAVE_SEMANAGE) && defined(HAVE_SELINUX) + #include ++#include + #endif + + #include "util/util.h" +@@ -32,7 +33,7 @@ + #define DEFAULT_SERANGE "s0" + #endif + +-#ifdef HAVE_SEMANAGE ++#if defined(HAVE_SEMANAGE) && defined(HAVE_SELINUX) + /* turn libselinux messages into SSSD DEBUG() calls */ + static void sss_semanage_error_callback(void *varg, + semanage_handle_t *handle, +@@ -73,33 +74,47 @@ static void sss_semanage_close(semanage_handle_t *handle) + semanage_handle_destroy(handle); + } + +-static int sss_semanage_init(semanage_handle_t **_handle) ++static int sss_is_selinux_managed(semanage_handle_t *handle) + { + int ret; +- semanage_handle_t *handle = NULL; + +- handle = semanage_handle_create(); +- if (!handle) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n"); +- ret = EIO; +- goto done; ++ if (handle == NULL) { ++ return EINVAL; + } + +- semanage_msg_set_callback(handle, +- sss_semanage_error_callback, +- NULL); +- + ret = semanage_is_managed(handle); + if (ret == 0) { + DEBUG(SSSDBG_TRACE_FUNC, "SELinux policy not managed via libsemanage\n"); +- ret = ERR_SELINUX_NOT_MANAGED; +- goto done; ++ return ERR_SELINUX_NOT_MANAGED; + } else if (ret == -1) { + DEBUG(SSSDBG_CRIT_FAILURE, "Call to semanage_is_managed failed\n"); ++ return EIO; ++ } ++ ++ return EOK; ++} ++ ++static int sss_semanage_init(semanage_handle_t **_handle) ++{ ++ int ret; ++ semanage_handle_t *handle = NULL; ++ ++ handle = semanage_handle_create(); ++ if (!handle) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n"); + ret = EIO; + goto done; + } + ++ semanage_msg_set_callback(handle, ++ sss_semanage_error_callback, ++ NULL); ++ ++ ret = sss_is_selinux_managed(handle); ++ if (ret != EOK) { ++ goto done; ++ } ++ + ret = semanage_access_check(handle); + if (ret < SEMANAGE_CAN_READ) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot read SELinux policy store\n"); +@@ -229,6 +244,34 @@ done: + return ret; + } + ++int sss_get_seuser(const char *linuxuser, ++ char **selinuxuser, ++ char **level) ++{ ++ int ret; ++ semanage_handle_t *handle; ++ ++ handle = semanage_handle_create(); ++ if (handle == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n"); ++ return EIO; ++ } ++ ++ semanage_msg_set_callback(handle, ++ sss_semanage_error_callback, ++ NULL); ++ ++ /* We only needed the handle for this call. Close the handle right ++ * after it */ ++ ret = sss_is_selinux_managed(handle); ++ sss_semanage_close(handle); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ return getseuserbyname(linuxuser, selinuxuser, level); ++} ++ + int set_seuser(const char *login_name, const char *seuser_name, + const char *mls) + { +@@ -382,7 +425,7 @@ done: + sss_semanage_close(handle); + return ret; + } +-#else /* HAVE_SEMANAGE */ ++#else /* HAVE_SEMANAGE && HAVE_SELINUX */ + int set_seuser(const char *login_name, const char *seuser_name, + const char *mls) + { +@@ -393,4 +436,11 @@ int del_seuser(const char *login_name) + { + return EOK; + } ++ ++int sss_get_seuser(const char *linuxuser, ++ char **selinuxuser, ++ char **level) ++{ ++ return EOK; ++} + #endif /* HAVE_SEMANAGE */ +diff --git a/src/util/util.h b/src/util/util.h +index 2521b1789b0b8701b1fbcce33890eedb7fe18d5e..be818a9531897e4f988cae48bf6ba30aea0e6d56 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -654,6 +654,9 @@ errno_t restore_creds(struct sss_creds *saved_creds); + int set_seuser(const char *login_name, const char *seuser_name, + const char *mlsrange); + int del_seuser(const char *login_name); ++int sss_get_seuser(const char *linuxuser, ++ char **selinuxuser, ++ char **level); + + /* convert time from generalized form to unix time */ + errno_t sss_utc_to_time_t(const char *str, const char *format, time_t *unix_time); +-- +2.14.3 + diff --git a/SOURCES/0098-ipa_s2n_get_acct_info_send-provide-correct-req_input.patch b/SOURCES/0098-ipa_s2n_get_acct_info_send-provide-correct-req_input.patch deleted file mode 100644 index 5a49b15..0000000 --- a/SOURCES/0098-ipa_s2n_get_acct_info_send-provide-correct-req_input.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 250777f65dc23917c436d3ecf0fe21abc65db65e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Mon, 3 Apr 2017 12:09:44 +0200 -Subject: [PATCH 98/99] ipa_s2n_get_acct_info_send: provide correct req_input - name -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -To avoid crash. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3358 - -Reviewed-by: Sumit Bose -Reviewed-by: Lukáš Slebodník -(cherry picked from commit b07bcd8b99590bd404733fa7ff1add37c55126bc) ---- - src/providers/ipa/ipa_s2n_exop.c | 40 ++++++++++++++++++++++++++++++++++++---- - 1 file changed, 36 insertions(+), 4 deletions(-) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index 8a3391b4093f1547d84fe44a0f24b1d063d1e28c..2173db357700499a6140aa61841e443139981483 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -1054,6 +1054,33 @@ static const char *ipa_s2n_reqtype2str(enum request_types request_type) - return "Unknown request type"; - } - -+static const char *ipa_s2n_reqinp2str(TALLOC_CTX *mem_ctx, -+ struct req_input *req_input) -+{ -+ const char *str = NULL; -+ -+ switch (req_input->type) { -+ case REQ_INP_NAME: -+ str = talloc_strdup(mem_ctx, req_input->inp.name); -+ break; -+ case REQ_INP_SECID: -+ str = talloc_strdup(mem_ctx, req_input->inp.secid); -+ break; -+ case REQ_INP_CERT: -+ str = talloc_strdup(mem_ctx, req_input->inp.cert); -+ break; -+ case REQ_INP_ID: -+ str = talloc_asprintf(mem_ctx, "%u", req_input->inp.id); -+ break; -+ } -+ -+ if (str == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); -+ } -+ -+ return str; -+} -+ - struct ipa_s2n_get_list_state { - struct tevent_context *ev; - struct ipa_id_ctx *ipa_ctx; -@@ -1410,6 +1437,7 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx, - struct tevent_req *req; - struct tevent_req *subreq; - struct berval *bv_req = NULL; -+ const char *input; - int ret = EFAULT; - bool is_v1 = false; - -@@ -1454,10 +1482,14 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx, - goto fail; - } - -- DEBUG(SSSDBG_TRACE_FUNC, "Sending request_type: [%s] for trust user [%s] " -- "to IPA server\n", -- ipa_s2n_reqtype2str(state->request_type), -- req_input->inp.name); -+ if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) { -+ input = ipa_s2n_reqinp2str(state, req_input); -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Sending request_type: [%s] for trust user [%s] to IPA server\n", -+ ipa_s2n_reqtype2str(state->request_type), -+ input); -+ talloc_zfree(input); -+ } - - subreq = ipa_s2n_exop_send(state, state->ev, state->sh, is_v1, - state->exop_timeout, bv_req); --- -2.9.3 - diff --git a/SOURCES/0099-config-check-Message-when-sssd.conf-is-missing.patch b/SOURCES/0099-config-check-Message-when-sssd.conf-is-missing.patch deleted file mode 100644 index 2862d4d..0000000 --- a/SOURCES/0099-config-check-Message-when-sssd.conf-is-missing.patch +++ /dev/null @@ -1,39 +0,0 @@ -From be05d577626835e3c72d71fc60e6abfa564c7cbe Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 14 Mar 2017 15:43:41 +0100 -Subject: [PATCH 99/99] config-check: Message when sssd.conf is missing -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -sssctl config-check should print a message for user -if no sssd.conf was found. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3330 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 955574eeb3a3b937abc3df150e9bbbb79b75c889) ---- - src/tools/sssctl/sssctl_config.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c -index 630df3c8ff5368ef253bb9753380e94c8c0a307d..7e3ebf5428ce3fef232eee7334c7fd90e904b2d3 100644 ---- a/src/tools/sssctl/sssctl_config.c -+++ b/src/tools/sssctl/sssctl_config.c -@@ -63,7 +63,10 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline, - - /* Open config file */ - ret = sss_ini_config_file_open(init_data, SSSD_CONFIG_FILE); -- if (ret != EOK) { -+ if (ret == ENOENT) { -+ ERROR("File %1$s does not exist.\n", SSSD_CONFIG_FILE); -+ goto done; -+ } else if (ret != EOK) { - DEBUG(SSSDBG_TRACE_FUNC, - "sss_ini_config_file_open failed: %s [%d]\n", - sss_strerror(ret), --- -2.9.3 - diff --git a/SOURCES/0099-util-Add-sss_-prefix-to-some-functions.patch b/SOURCES/0099-util-Add-sss_-prefix-to-some-functions.patch new file mode 100644 index 0000000..829aea5 --- /dev/null +++ b/SOURCES/0099-util-Add-sss_-prefix-to-some-functions.patch @@ -0,0 +1,142 @@ +From 9e1df30e737566ca92c93cb09028717415120f47 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Tue, 6 Feb 2018 19:17:55 +0100 +Subject: [PATCH 99/99] util: Add sss_ prefix to some functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add sss_ prefix to del_seuser and set_seuser for consistency +with sss_get_seuser. Also sss_ prefix makes it clear that +these functions come from SSSD. + +Reviewed-by: Lukáš Slebodník + +Resolves: +https://pagure.io/SSSD/sssd/issue/3618 +(cherry picked from commit 6b9c38df5712b951e31800efea2df0802e333e08) +--- + src/providers/ipa/selinux_child.c | 4 ++-- + src/tools/sss_useradd.c | 2 +- + src/tools/sss_userdel.c | 2 +- + src/tools/sss_usermod.c | 2 +- + src/util/sss_semanage.c | 12 ++++++------ + src/util/util.h | 6 +++--- + 6 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c +index c659976e80cb7317671da52fe4777ee821589e36..a601b28c4c68afca51758b1967d1bfc1d51fb450 100644 +--- a/src/providers/ipa/selinux_child.c ++++ b/src/providers/ipa/selinux_child.c +@@ -157,9 +157,9 @@ static int sc_set_seuser(const char *login_name, const char *seuser_name, + * default. We need to remove the SELinux user from the DB + * in that case + */ +- ret = del_seuser(login_name); ++ ret = sss_del_seuser(login_name); + } else { +- ret = set_seuser(login_name, seuser_name, mls); ++ ret = sss_set_seuser(login_name, seuser_name, mls); + } + umask(old_mask); + return ret; +diff --git a/src/tools/sss_useradd.c b/src/tools/sss_useradd.c +index 8521b83011b42c9e2acca4136f154acb3919440c..ca2cbd6c119e5a1735e5b3b524cddeccb68a2578 100644 +--- a/src/tools/sss_useradd.c ++++ b/src/tools/sss_useradd.c +@@ -205,7 +205,7 @@ int main(int argc, const char **argv) + + /* Set SELinux login context - must be done after transaction is done + * b/c libselinux calls getpwnam */ +- ret = set_seuser(tctx->octx->name, pc_selinux_user, NULL); ++ ret = sss_set_seuser(tctx->octx->name, pc_selinux_user, NULL); + if (ret != EOK) { + ERROR("Cannot set SELinux login context\n"); + ret = EXIT_FAILURE; +diff --git a/src/tools/sss_userdel.c b/src/tools/sss_userdel.c +index d085dc3cabd31b2ee82b13c6cbc39c7658b071d1..fb0f2c2ab6163738da2dcf4177c06cd5dc524345 100644 +--- a/src/tools/sss_userdel.c ++++ b/src/tools/sss_userdel.c +@@ -254,7 +254,7 @@ int main(int argc, const char **argv) + + /* Set SELinux login context - must be done after transaction is done + * b/c libselinux calls getpwnam */ +- ret = del_seuser(tctx->octx->name); ++ ret = sss_del_seuser(tctx->octx->name); + if (ret != EOK) { + ERROR("Cannot reset SELinux login context\n"); + ret = EXIT_FAILURE; +diff --git a/src/tools/sss_usermod.c b/src/tools/sss_usermod.c +index 55e94394766f5f46bb3c14c231186f2d79d6b6ab..6a818f13ad2a7e087e23fa2190b83aeb1eabdbac 100644 +--- a/src/tools/sss_usermod.c ++++ b/src/tools/sss_usermod.c +@@ -300,7 +300,7 @@ int main(int argc, const char **argv) + + /* Set SELinux login context - must be done after transaction is done + * b/c libselinux calls getpwnam */ +- ret = set_seuser(tctx->octx->name, pc_selinux_user, NULL); ++ ret = sss_set_seuser(tctx->octx->name, pc_selinux_user, NULL); + if (ret != EOK) { + ERROR("Cannot set SELinux login context\n"); + ret = EXIT_FAILURE; +diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c +index 25b6bcdad2ad7e7ac710497f13d6a6e22360b0dd..1150b6236c2c227fe2fc69f2505b6e254a1e64ec 100644 +--- a/src/util/sss_semanage.c ++++ b/src/util/sss_semanage.c +@@ -272,8 +272,8 @@ int sss_get_seuser(const char *linuxuser, + return getseuserbyname(linuxuser, selinuxuser, level); + } + +-int set_seuser(const char *login_name, const char *seuser_name, +- const char *mls) ++int sss_set_seuser(const char *login_name, const char *seuser_name, ++ const char *mls) + { + semanage_handle_t *handle = NULL; + semanage_seuser_key_t *key = NULL; +@@ -346,7 +346,7 @@ done: + return ret; + } + +-int del_seuser(const char *login_name) ++int sss_del_seuser(const char *login_name) + { + semanage_handle_t *handle = NULL; + semanage_seuser_key_t *key = NULL; +@@ -426,13 +426,13 @@ done: + return ret; + } + #else /* HAVE_SEMANAGE && HAVE_SELINUX */ +-int set_seuser(const char *login_name, const char *seuser_name, +- const char *mls) ++int sss_set_seuser(const char *login_name, const char *seuser_name, ++ const char *mls) + { + return EOK; + } + +-int del_seuser(const char *login_name) ++int sss_del_seuser(const char *login_name) + { + return EOK; + } +diff --git a/src/util/util.h b/src/util/util.h +index be818a9531897e4f988cae48bf6ba30aea0e6d56..ef8ef7f57d7949aa2735171f11195dbcdc42288a 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -651,9 +651,9 @@ errno_t restore_creds(struct sss_creds *saved_creds); + * certain permissions. Therefore the caller should make sure the umask is + * not too restricted (especially when called from the daemon code). + */ +-int set_seuser(const char *login_name, const char *seuser_name, +- const char *mlsrange); +-int del_seuser(const char *login_name); ++int sss_set_seuser(const char *login_name, const char *seuser_name, ++ const char *mlsrange); ++int sss_del_seuser(const char *login_name); + int sss_get_seuser(const char *linuxuser, + char **selinuxuser, + char **level); +-- +2.14.3 + diff --git a/SOURCES/0100-MAN-Explain-how-does-auto_private_groups-affect-subd.patch b/SOURCES/0100-MAN-Explain-how-does-auto_private_groups-affect-subd.patch new file mode 100644 index 0000000..ae772b2 --- /dev/null +++ b/SOURCES/0100-MAN-Explain-how-does-auto_private_groups-affect-subd.patch @@ -0,0 +1,43 @@ +From a09a7a03f5b330cc45a0007a56d4789116a91e46 Mon Sep 17 00:00:00 2001 +From: amitkuma +Date: Tue, 6 Feb 2018 16:27:00 +0530 +Subject: [PATCH 100/100] MAN: Explain how does auto_private_groups affect + subdomains + +Fix explains how auto_private_groups affects subdomains. +a. POSIX sudomains, gets inherited to subdomain. +b. ID-mapping subdomains, already enabled. + +Resolves: https://pagure.io/SSSD/sssd/issue/3627 + +Reviewed-by: Rob Crittenden +(cherry picked from commit 52ae76737f2df3012d67f6a0b5052c86022bffdd) +--- + src/man/sssd.conf.5.xml | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 47da07c33bdcfbf2fa94ff932492e9ea4bbfe846..8d06f57539e3fc55189234aab2aea950ba14713a 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -2830,7 +2830,16 @@ subdomain_inherit = ldap_purge_cache_timeout + If this option is enabled, SSSD will automatically + create user private groups based on user's + UID number. The GID number is ignored in this case. +- ++ ++ ++ For POSIX subdomains, setting the option in the main ++ domain is inherited in the subdomain. ++ ++ ++ For ID-mapping subdomains, auto_private_groups is ++ already enabled for the subdomains and setting it to ++ false will not have any effect for the subdomain. ++ + + NOTE: Because the GID number and the user private group + are inferred frm the UID number, it is not supported +-- +2.14.3 + diff --git a/SOURCES/0100-sbus-check-connection-for-NULL-before-unregister-it.patch b/SOURCES/0100-sbus-check-connection-for-NULL-before-unregister-it.patch deleted file mode 100644 index 66fee16..0000000 --- a/SOURCES/0100-sbus-check-connection-for-NULL-before-unregister-it.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 556eb1200a3754935f573ccffee87554bf9e9296 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 10 Apr 2017 13:45:27 +0200 -Subject: [PATCH 100/101] sbus: check connection for NULL before unregister it -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There seem to be code paths where the data is a added to the hash before -the connection is properly initialized, to avoid core dump during shut -down we only call dbus_conection_unregister_object_path() if there is a -connection. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3367 - -Reviewed-by: Pavel Březina -(cherry picked from commit 35186217d44d0138a1aedf7a4db72249b2c40e66) ---- - src/sbus/sssd_dbus_interface.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/src/sbus/sssd_dbus_interface.c b/src/sbus/sssd_dbus_interface.c -index 1a11c6abcf23053e3b8c77f4d469d7c202a88eb8..c9007a4814e09e26fedaf605ca7313234d5ebf2c 100644 ---- a/src/sbus/sssd_dbus_interface.c -+++ b/src/sbus/sssd_dbus_interface.c -@@ -490,7 +490,13 @@ sbus_opath_hash_delete_cb(hash_entry_t *item, - conn = talloc_get_type(pvt, struct sbus_connection); - path = sbus_opath_get_base_path(NULL, item->key.str); - -- dbus_connection_unregister_object_path(conn->dbus.conn, path); -+ /* There seem to be code paths where the data is added to the hash -+ * before the connection is properly initialized, to avoid core dump -+ * during shut down we only call dbus_connection_unregister_object_path() -+ * if there is a connection. */ -+ if (conn->dbus.conn != NULL) { -+ dbus_connection_unregister_object_path(conn->dbus.conn, path); -+ } - } - - hash_table_t * --- -2.9.3 - diff --git a/SOURCES/0101-AD-Use-the-right-sdap_domain-for-the-forest-root.patch b/SOURCES/0101-AD-Use-the-right-sdap_domain-for-the-forest-root.patch new file mode 100644 index 0000000..128a9ea --- /dev/null +++ b/SOURCES/0101-AD-Use-the-right-sdap_domain-for-the-forest-root.patch @@ -0,0 +1,201 @@ +From d56d41e76741f418e88e479b91193db3ee3f1688 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 17 Jan 2018 21:59:24 +0100 +Subject: [PATCH 101/101] AD: Use the right sdap_domain for the forest root +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Each ad_id_ctx structure which represents a trusted AD domain contains a +list of sdap_domain structures representing all the other domains. This +is used to e.g. be able to reach another domain's ad_id_ctx and use its +LDAP connection. + +However, the sdap search call that was searching for trusted domains in +the forest that the root domain knows about, was unconditionally using +the first sdap_domain structure in the list linked from the root_domain's +ad_id_ctx structure. + +It should be noted that this search only happens in case the machine is +joined to one of the non-root domains in the forest and searches the root +domain explicitly. + +In case sdap_domain structures linked from the ad_id_ctx representing +the root domain were ordered so that the first sdap_domain in the list +was representing a different domain than the one linked from the +ad_id_ctx, the sdap search would have used a wrong search base derived +from the unexpected sdap_domain which would result in a referral being +returned. + +This patch explicitly looks up the sdap_domain structure that +corresponds to the root domain. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3594 + +Reviewed-by: Sumit Bose +Reviewed-by: Lukáš Slebodník +(cherry picked from commit 9ac071272ce0152eb293d3181a5c12b395655521) +--- + src/providers/ad/ad_subdomains.c | 110 +++++++++++++++++++++++++++------------ + 1 file changed, 77 insertions(+), 33 deletions(-) + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 1b9483a5dce937d6acdd813486a1e8c18210d35f..bd94ba8ea93679df8d01508b3d4d85217d9c1c87 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -57,6 +57,71 @@ + /* do not refresh more often than every 5 seconds for now */ + #define AD_SUBDOMAIN_REFRESH_LIMIT 5 + ++static struct sss_domain_info * ++ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs) ++{ ++ struct sss_domain_info *dom; ++ const char *name; ++ errno_t ret; ++ ++ if (attrs == NULL) { ++ /* Clients joined to the forest root directly don't even discover ++ * the root domain, so the attrs are expected to be NULL in this ++ * case ++ */ ++ return be_ctx->domain; ++ } ++ ++ ret = sysdb_attrs_get_string(attrs, AD_AT_TRUST_PARTNER, &name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); ++ return NULL; ++ } ++ ++ /* With a subsequent run, the root should already be known */ ++ for (dom = be_ctx->domain; dom != NULL; ++ dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) { ++ ++ if (strcasecmp(dom->name, name) == 0) { ++ /* The forest root is special, although it might be disabled for ++ * general lookups we still want to try to get the domains in the ++ * forest from a DC of the forest root */ ++ if (sss_domain_get_state(dom) == DOM_DISABLED ++ && !sss_domain_is_forest_root(dom)) { ++ return NULL; ++ } ++ return dom; ++ } ++ } ++ ++ return NULL; ++} ++ ++static struct sdap_domain * ++ads_get_root_sdap_domain(struct be_ctx *be_ctx, ++ struct sdap_options *opts, ++ struct sysdb_attrs *attrs) ++{ ++ struct sdap_domain *root_sdom; ++ struct sss_domain_info *root_dom; ++ ++ root_dom = ads_get_root_domain(be_ctx, attrs); ++ if (root_dom == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ads_get_root_domain did not find the domain\n"); ++ return NULL; ++ } ++ ++ root_sdom = sdap_domain_get(opts, root_dom); ++ if (root_sdom == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to find sdap_domain for the root domain\n"); ++ return NULL; ++ } ++ ++ return root_sdom; ++} ++ + static errno_t ad_get_enabled_domains(TALLOC_CTX *mem_ctx, + struct ad_id_ctx *ad_id_ctx, + const char *ad_domain, +@@ -755,6 +820,7 @@ struct ad_get_slave_domain_state { + struct sdap_options *opts; + struct sdap_idmap_ctx *idmap_ctx; + struct sysdb_attrs *root_attrs; ++ struct sdap_domain *root_sdom; + struct sdap_id_op *sdap_op; + }; + +@@ -786,6 +852,13 @@ ad_get_slave_domain_send(TALLOC_CTX *mem_ctx, + state->opts = root_id_ctx->sdap_id_ctx->opts; + state->idmap_ctx = root_id_ctx->sdap_id_ctx->opts->idmap_ctx; + state->root_attrs = root_attrs; ++ state->root_sdom = ads_get_root_sdap_domain(state->be_ctx, ++ state->opts, ++ state->root_attrs); ++ if (state->root_sdom == NULL) { ++ ret = ERR_DOMAIN_NOT_FOUND; ++ goto immediately; ++ } + + state->sdap_op = sdap_id_op_create(state, root_id_ctx->ldap_ctx->conn_cache); + if (state->sdap_op == NULL) { +@@ -861,7 +934,7 @@ static void ad_get_slave_domain_connect_done(struct tevent_req *subreq) + + subreq = sdap_search_bases_send(state, state->ev, state->opts, + sdap_id_op_handle(state->sdap_op), +- state->opts->sdom->search_bases, ++ state->root_sdom->search_bases, + NULL, false, 0, + SLAVE_DOMAIN_FILTER, attrs); + if (subreq == NULL) { +@@ -965,38 +1038,6 @@ static errno_t ad_get_slave_domain_recv(struct tevent_req *req) + return EOK; + } + +-static struct sss_domain_info * +-ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs) +-{ +- struct sss_domain_info *dom; +- const char *name; +- errno_t ret; +- +- ret = sysdb_attrs_get_string(attrs, AD_AT_TRUST_PARTNER, &name); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); +- return NULL; +- } +- +- /* With a subsequent run, the root should already be known */ +- for (dom = be_ctx->domain; dom != NULL; +- dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) { +- +- if (strcasecmp(dom->name, name) == 0) { +- /* The forest root is special, although it might be disabled for +- * general lookups we still want to try to get the domains in the +- * forest from a DC of the forest root */ +- if (sss_domain_get_state(dom) == DOM_DISABLED +- && !sss_domain_is_forest_root(dom)) { +- return NULL; +- } +- return dom; +- } +- } +- +- return NULL; +-} +- + static struct ad_id_ctx * + ads_get_root_id_ctx(struct be_ctx *be_ctx, + struct ad_id_ctx *ad_id_ctx, +@@ -1416,6 +1457,9 @@ static void ad_subdomains_refresh_root_done(struct tevent_req *subreq) + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct ad_subdomains_refresh_state); + ++ /* Note: For clients joined to the root domain, root_attrs is NULL, ++ * see ad_get_root_domain_send() ++ */ + ret = ad_get_root_domain_recv(state, subreq, &root_attrs, &root_id_ctx); + talloc_zfree(subreq); + if (ret != EOK) { +-- +2.14.3 + diff --git a/SOURCES/0101-selinux-Do-not-fail-if-SELinux-is-not-managed.patch b/SOURCES/0101-selinux-Do-not-fail-if-SELinux-is-not-managed.patch deleted file mode 100644 index 1ae6353..0000000 --- a/SOURCES/0101-selinux-Do-not-fail-if-SELinux-is-not-managed.patch +++ /dev/null @@ -1,211 +0,0 @@ -From 9b7c29b67ec845b2004d6bcac2bcceabfd855f1e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 8 Feb 2017 12:01:37 +0100 -Subject: [PATCH 101/101] selinux: Do not fail if SELinux is not managed -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Previously we failed if semanage_is_managed returned 0 or -1 (not -managed or error). With this patch we only fail in case of error and -continue normally if selinux is not managed by libsemanage at all. - -Resolves: -https://fedorahosted.org/sssd/ticket/3297 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 78a08d30b5fbf6e1e3b589e0cf67022e0c1faa33) ---- - Makefile.am | 1 + - src/providers/ipa/selinux_child.c | 9 ++++-- - src/util/sss_semanage.c | 61 +++++++++++++++++++++++++-------------- - src/util/util_errors.c | 1 + - src/util/util_errors.h | 1 + - 5 files changed, 49 insertions(+), 24 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index f5ac363a35e4aae51e8b70bad27c7fc824be10f2..370d6442ec58a14946ad288a23c696f25ca98f47 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -4040,6 +4040,7 @@ selinux_child_SOURCES = \ - src/util/atomic_io.c \ - src/util/util.c \ - src/util/util_ext.c \ -+ src/util/util_errors.c - $(NULL) - selinux_child_CFLAGS = \ - $(AM_CFLAGS) \ -diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c -index 380005c7ad3269fc8113c62ceef30b076455b5dd..f8dd3954a7244df2dcbb910aabf8888f41306c09 100644 ---- a/src/providers/ipa/selinux_child.c -+++ b/src/providers/ipa/selinux_child.c -@@ -174,14 +174,19 @@ static bool seuser_needs_update(struct input_buffer *ibuf) - - ret = get_seuser(ibuf, ibuf->username, &db_seuser, &db_mls_range); - DEBUG(SSSDBG_TRACE_INTERNAL, -- "get_seuser: ret: %d seuser: %s mls: %s\n", -- ret, db_seuser ? db_seuser : "unknown", -+ "get_seuser: ret: %d msg: [%s] seuser: %s mls: %s\n", -+ ret, sss_strerror(ret), -+ db_seuser ? db_seuser : "unknown", - db_mls_range ? db_mls_range : "unknown"); - if (ret == EOK && db_seuser && db_mls_range && - strcmp(db_seuser, ibuf->seuser) == 0 && - strcmp(db_mls_range, ibuf->mls_range) == 0) { - needs_update = false; - } -+ /* OR */ -+ if (ret == ERR_SELINUX_NOT_MANAGED) { -+ needs_update = false; -+ } - - talloc_free(db_seuser); - talloc_free(db_mls_range); -diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c -index fe06bee1dfec3abca3aa3cd5e85e55386ac11343..0da97aad4d8eba733b131c2749932e03ca4242c4 100644 ---- a/src/util/sss_semanage.c -+++ b/src/util/sss_semanage.c -@@ -73,7 +73,7 @@ static void sss_semanage_close(semanage_handle_t *handle) - semanage_handle_destroy(handle); - } - --static semanage_handle_t *sss_semanage_init(void) -+static int sss_semanage_init(semanage_handle_t **_handle) - { - int ret; - semanage_handle_t *handle = NULL; -@@ -81,7 +81,8 @@ static semanage_handle_t *sss_semanage_init(void) - handle = semanage_handle_create(); - if (!handle) { - DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n"); -- return NULL; -+ ret = EIO; -+ goto done; - } - - semanage_msg_set_callback(handle, -@@ -89,28 +90,41 @@ static semanage_handle_t *sss_semanage_init(void) - NULL); - - ret = semanage_is_managed(handle); -- if (ret != 1) { -- DEBUG(SSSDBG_CRIT_FAILURE, "SELinux policy not managed\n"); -- goto fail; -+ if (ret == 0) { -+ DEBUG(SSSDBG_TRACE_FUNC, "SELinux policy not managed via libsemanage\n"); -+ ret = ERR_SELINUX_NOT_MANAGED; -+ goto done; -+ } else if (ret == -1) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Call to semanage_is_managed failed\n"); -+ ret = EIO; -+ goto done; - } - - ret = semanage_access_check(handle); - if (ret < SEMANAGE_CAN_READ) { - DEBUG(SSSDBG_CRIT_FAILURE, "Cannot read SELinux policy store\n"); -- goto fail; -+ ret = EACCES; -+ goto done; - } - - ret = semanage_connect(handle); - if (ret != 0) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Cannot estabilish SELinux management connection\n"); -- goto fail; -+ ret = EIO; -+ goto done; - } - -- return handle; --fail: -- sss_semanage_close(handle); -- return NULL; -+ ret = EOK; -+ -+done: -+ if (ret != EOK) { -+ sss_semanage_close(handle); -+ } else { -+ *_handle = handle; -+ } -+ -+ return ret; - } - - static int sss_semanage_user_add(semanage_handle_t *handle, -@@ -228,10 +242,11 @@ int set_seuser(const char *login_name, const char *seuser_name, - return EOK; - } - -- handle = sss_semanage_init(); -- if (!handle) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init SELinux management\n"); -- ret = EIO; -+ ret = sss_semanage_init(&handle); -+ if (ret == ERR_SELINUX_NOT_MANAGED) { -+ goto done; -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux handle\n"); - goto done; - } - -@@ -295,10 +310,11 @@ int del_seuser(const char *login_name) - int ret; - int exists = 0; - -- handle = sss_semanage_init(); -- if (!handle) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init SELinux management\n"); -- ret = EIO; -+ ret = sss_semanage_init(&handle); -+ if (ret == ERR_SELINUX_NOT_MANAGED) { -+ goto done; -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux handle\n"); - goto done; - } - -@@ -377,10 +393,11 @@ int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name, - semanage_seuser_t *sm_user = NULL; - semanage_seuser_key_t *sm_key = NULL; - -- sm_handle = sss_semanage_init(); -- if (sm_handle == NULL) { -+ ret = sss_semanage_init(&sm_handle); -+ if (ret == ERR_SELINUX_NOT_MANAGED) { -+ goto done; -+ } else if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux handle\n"); -- ret = EIO; - goto done; - } - -diff --git a/src/util/util_errors.c b/src/util/util_errors.c -index 466a3b4062f39b29d831a5d8a62dc8d576eb2e97..97eaf160f20bcc8cfe52254070a2d182e19addd4 100644 ---- a/src/util/util_errors.c -+++ b/src/util/util_errors.c -@@ -75,6 +75,7 @@ struct err_string error_to_str[] = { - { "Cannot connect to system bus" }, /* ERR_NO_SYSBUS */ - { "LDAP search returned a referral" }, /* ERR_REFERRAL */ - { "Error setting SELinux user context" }, /* ERR_SELINUX_CONTEXT */ -+ { "SELinux is not managed by libsemanage" }, /* ERR_SELINUX_NOT_MANAGED */ - { "Username format not allowed by re_expression" }, /* ERR_REGEX_NOMATCH */ - { "Time specification not supported" }, /* ERR_TIMESPEC_NOT_SUPPORTED */ - { "Invalid SSSD configuration detected" }, /* ERR_INVALID_CONFIG */ -diff --git a/src/util/util_errors.h b/src/util/util_errors.h -index 2f90c0a5d65325a431a8e4d9a480170808c9198e..4a250bf0339ba689680c155fa8e6d43f42c2467e 100644 ---- a/src/util/util_errors.h -+++ b/src/util/util_errors.h -@@ -97,6 +97,7 @@ enum sssd_errors { - ERR_NO_SYSBUS, - ERR_REFERRAL, - ERR_SELINUX_CONTEXT, -+ ERR_SELINUX_NOT_MANAGED, - ERR_REGEX_NOMATCH, - ERR_TIMESPEC_NOT_SUPPORTED, - ERR_INVALID_CONFIG, --- -2.9.3 - diff --git a/SOURCES/0102-AD-sdap_get_ad_tokengroups_done-allocate-temporary-d.patch b/SOURCES/0102-AD-sdap_get_ad_tokengroups_done-allocate-temporary-d.patch new file mode 100644 index 0000000..5f9991f --- /dev/null +++ b/SOURCES/0102-AD-sdap_get_ad_tokengroups_done-allocate-temporary-d.patch @@ -0,0 +1,47 @@ +From f6f8fca59937b746b3c47cf0aeb23ea554a43fab Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 16 Feb 2018 12:07:28 +0100 +Subject: [PATCH] AD: sdap_get_ad_tokengroups_done() allocate temporary data on + state + +Related to https://pagure.io/SSSD/sssd/issue/3639 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit db52090e33b8f1747b7d77bab64ab8c9f9f5ecc2) +--- + src/providers/ldap/sdap_async_initgroups_ad.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index 61aa69a2dfbe22cac37a5b7fddc07473527e5de5..ee0cd6707924b02d239ce4c329d9853268d49a80 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -372,7 +372,6 @@ immediately: + + static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq) + { +- TALLOC_CTX *tmp_ctx = NULL; + struct sdap_get_ad_tokengroups_state *state = NULL; + struct tevent_req *req = NULL; + struct sysdb_attrs **users = NULL; +@@ -386,7 +385,7 @@ static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq) + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_get_ad_tokengroups_state); + +- ret = sdap_get_generic_recv(subreq, tmp_ctx, &num_users, &users); ++ ret = sdap_get_generic_recv(subreq, state, &num_users, &users); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, +@@ -449,8 +448,6 @@ static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq) + ret = EOK; + + done: +- talloc_free(tmp_ctx); +- + if (ret != EOK) { + tevent_req_error(req, ret); + return; +-- +2.14.3 + diff --git a/SOURCES/0102-UTIL-Use-max-15-characters-for-AD-host-UPN.patch b/SOURCES/0102-UTIL-Use-max-15-characters-for-AD-host-UPN.patch deleted file mode 100644 index c91d390..0000000 --- a/SOURCES/0102-UTIL-Use-max-15-characters-for-AD-host-UPN.patch +++ /dev/null @@ -1,49 +0,0 @@ -From b2dcfa00dcb7b315a739d35ff6722a25b0ab5556 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Tue, 14 Mar 2017 10:34:00 +0100 -Subject: [PATCH 102/102] UTIL: Use max 15 characters for AD host UPN -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We do not want to use host principal with AD -"host/name.domain.tld@DOMAIN.TLD" because it does not work. -We need to use correct user principal for AD hosts. And we cannot -rely all fallback "*$" because of other principals in keytab. - -The NetBIOS naming convention allows for 16 characters in a NetBIOS -name. Microsoft, however, limits NetBIOS names to 15 characters and -uses the 16th character as a NetBIOS suffix. -https://support.microsoft.com/en-us/help/163409/netbios-suffixes-16th-character-of-the-netbios-name - -Resolves: -https://pagure.io/SSSD/sssd/issue/3329 - -Reviewed-by: Michal Židek -(cherry picked from commit c6f1bc32774a7cf2f8678499dfbced420be3a3a1) ---- - src/util/sss_krb5.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c -index d461cf881566af37f31524c16f6a5f1511a5dc89..a3f066e8add5b7d7575c1e0f537c5729e4a0dad0 100644 ---- a/src/util/sss_krb5.c -+++ b/src/util/sss_krb5.c -@@ -51,7 +51,13 @@ sss_krb5_get_primary(TALLOC_CTX *mem_ctx, - *c = toupper(*c); - } - -- primary = talloc_asprintf(mem_ctx, "%s$", shortname); -+ /* The samAccountName is recommended to be less than 20 characters. -+ * This is only for users and groups. For machine accounts, -+ * the real limit is caused by NetBIOS protocol. -+ * NetBIOS names are limited to 16 (15 + $) -+ * https://support.microsoft.com/en-us/help/163409/netbios-suffixes-16th-character-of-the-netbios-name -+ */ -+ primary = talloc_asprintf(mem_ctx, "%.15s$", shortname); - talloc_free(shortname); - return primary; - } --- -2.9.3 - diff --git a/SOURCES/0103-AD-do-not-allocate-temporary-data-on-long-living-con.patch b/SOURCES/0103-AD-do-not-allocate-temporary-data-on-long-living-con.patch new file mode 100644 index 0000000..7140380 --- /dev/null +++ b/SOURCES/0103-AD-do-not-allocate-temporary-data-on-long-living-con.patch @@ -0,0 +1,89 @@ +From 3dae415229a7a2526a886ea55a12377fdc62361e Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 16 Feb 2018 12:09:01 +0100 +Subject: [PATCH] AD: do not allocate temporary data on long living context + +Related to https://pagure.io/SSSD/sssd/issue/3639 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit e6ad16e05f42a1678a8c6cd14eb54ca75b8d775e) +--- + src/providers/ad/ad_common.c | 5 +++-- + src/providers/ad/ad_common.h | 3 ++- + src/providers/ad/ad_id.c | 2 +- + src/tests/cmocka/test_ad_common.c | 4 ++-- + 4 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c +index 84845e285bef336b503b9d27bfc6eb99d6ee43ff..2a1647173b76b410371315eb364e9a3785714a93 100644 +--- a/src/providers/ad/ad_common.c ++++ b/src/providers/ad/ad_common.c +@@ -1402,13 +1402,14 @@ ad_ldap_conn_list(TALLOC_CTX *mem_ctx, + } + + struct sdap_id_conn_ctx ** +-ad_user_conn_list(struct ad_id_ctx *ad_ctx, ++ad_user_conn_list(TALLOC_CTX *mem_ctx, ++ struct ad_id_ctx *ad_ctx, + struct sss_domain_info *dom) + { + struct sdap_id_conn_ctx **clist; + int cindex = 0; + +- clist = talloc_zero_array(ad_ctx, struct sdap_id_conn_ctx *, 3); ++ clist = talloc_zero_array(mem_ctx, struct sdap_id_conn_ctx *, 3); + if (clist == NULL) { + return NULL; + } +diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h +index ce33b37c75f45ae72adb268858cce34759b8b02f..931aafc6c031e0979460925a1402517b054b202c 100644 +--- a/src/providers/ad/ad_common.h ++++ b/src/providers/ad/ad_common.h +@@ -175,7 +175,8 @@ ad_ldap_conn_list(TALLOC_CTX *mem_ctx, + struct sss_domain_info *dom); + + struct sdap_id_conn_ctx ** +-ad_user_conn_list(struct ad_id_ctx *ad_ctx, ++ad_user_conn_list(TALLOC_CTX *mem_ctx, ++ struct ad_id_ctx *ad_ctx, + struct sss_domain_info *dom); + + struct sdap_id_conn_ctx * +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index 0b8f49819405c7dbbfa18b5359f7743441dc65e5..782d9bc402e71d6b20976367f6afbae82bd25750 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -367,7 +367,7 @@ get_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx, + + switch (ar->entry_type & BE_REQ_TYPE_MASK) { + case BE_REQ_USER: /* user */ +- clist = ad_user_conn_list(ad_ctx, dom); ++ clist = ad_user_conn_list(mem_ctx, ad_ctx, dom); + break; + case BE_REQ_BY_SECID: /* by SID */ + case BE_REQ_USER_AND_GROUP: /* get SID */ +diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c +index 80b3bb5599a95578b7734d5dfcd20a2a7428a084..a8a447e91bd5107bbfc9d8445d0508778a5012f8 100644 +--- a/src/tests/cmocka/test_ad_common.c ++++ b/src/tests/cmocka/test_ad_common.c +@@ -771,7 +771,7 @@ void test_user_conn_list(void **state) + struct ad_common_test_ctx); + assert_non_null(test_ctx); + +- conn_list = ad_user_conn_list(test_ctx->ad_ctx, ++ conn_list = ad_user_conn_list(test_ctx, test_ctx->ad_ctx, + test_ctx->dom); + assert_non_null(conn_list); + +@@ -780,7 +780,7 @@ void test_user_conn_list(void **state) + assert_null(conn_list[1]); + talloc_free(conn_list); + +- conn_list = ad_user_conn_list(test_ctx->ad_ctx, ++ conn_list = ad_user_conn_list(test_ctx, test_ctx->ad_ctx, + test_ctx->subdom); + assert_non_null(conn_list); + +-- +2.14.3 + diff --git a/SOURCES/0103-Move-sized_output_name-and-sized_domain_name-into-re.patch b/SOURCES/0103-Move-sized_output_name-and-sized_domain_name-into-re.patch deleted file mode 100644 index 89b507c..0000000 --- a/SOURCES/0103-Move-sized_output_name-and-sized_domain_name-into-re.patch +++ /dev/null @@ -1,300 +0,0 @@ -From 84be2901aeb36ac60760cc11c424b717df360e87 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 19 Apr 2017 17:44:40 +0200 -Subject: [PATCH 103/104] Move sized_output_name() and sized_domain_name() into - responder common code -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -These functions are used to format a name into a format that the user -configured for output, including case sensitiveness, replacing -whitespace and qualified format. They were used only in the NSS -responder, which typically returns strings to the NSS client library and -then the user. - -But it makes sense to just reuse the same code in the IFP responder as -well, since it does essentially the same job. - -The patch also renames sized_member_name to sized_domain_name. -Previously, the function was only used to format a group member, the IFP -responder would use the same function to format a group the user is a -member of. - -Related to: - https://pagure.io/SSSD/sssd/issue/3268 - -Reviewed-by: Pavel Březina -(cherry picked from commit 7c074ba2f923985ab0d4f9d6a5e01ff3f2f0a7a8) ---- - src/responder/common/responder.h | 21 ++++++++ - src/responder/common/responder_common.c | 90 +++++++++++++++++++++++++++++++++ - src/responder/nss/nss_private.h | 11 ---- - src/responder/nss/nss_protocol_grent.c | 2 +- - src/responder/nss/nss_utils.c | 87 ------------------------------- - 5 files changed, 112 insertions(+), 99 deletions(-) - -diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h -index 4210307489fe25829a1674f254ecc7d185029698..dfe1ec455e355de263c3550306e53fea3ada85df 100644 ---- a/src/responder/common/responder.h -+++ b/src/responder/common/responder.h -@@ -393,4 +393,25 @@ char *sss_resp_create_fqname(TALLOC_CTX *mem_ctx, - - errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx); - -+/** -+ * Helper functions to format output names -+ */ -+ -+/* Format orig_name into a sized_string in output format as prescribed -+ * by the name_dom domain -+ */ -+int sized_output_name(TALLOC_CTX *mem_ctx, -+ struct resp_ctx *rctx, -+ const char *orig_name, -+ struct sss_domain_info *name_dom, -+ struct sized_string **_name); -+ -+/* Format orig_name into a sized_string in output format as prescribed -+ * by the domain read from the fully qualified name. -+ */ -+int sized_domain_name(TALLOC_CTX *mem_ctx, -+ struct resp_ctx *rctx, -+ const char *member_name, -+ struct sized_string **_name); -+ - #endif /* __SSS_RESPONDER_H__ */ -diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c -index 67e1deefdfde19c95a68029b11099579d851513f..ac6320b08de09bc6c7e8dd1af72e0a493a449f7a 100644 ---- a/src/responder/common/responder_common.c -+++ b/src/responder/common/responder_common.c -@@ -1651,3 +1651,93 @@ done: - - return ret; - } -+ -+/** -+ * Helper functions to format output names -+ */ -+int sized_output_name(TALLOC_CTX *mem_ctx, -+ struct resp_ctx *rctx, -+ const char *orig_name, -+ struct sss_domain_info *name_dom, -+ struct sized_string **_name) -+{ -+ TALLOC_CTX *tmp_ctx = NULL; -+ errno_t ret; -+ char *username; -+ struct sized_string *name; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ username = sss_output_name(tmp_ctx, orig_name, name_dom->case_preserve, -+ rctx->override_space); -+ if (username == NULL) { -+ ret = EIO; -+ goto done; -+ } -+ -+ if (name_dom->fqnames) { -+ username = sss_tc_fqname(tmp_ctx, name_dom->names, name_dom, username); -+ if (username == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "sss_replace_space failed\n"); -+ ret = EIO; -+ goto done; -+ } -+ } -+ -+ name = talloc_zero(tmp_ctx, struct sized_string); -+ if (name == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ to_sized_string(name, username); -+ name->str = talloc_steal(name, username); -+ *_name = talloc_steal(mem_ctx, name); -+ ret = EOK; -+done: -+ talloc_zfree(tmp_ctx); -+ return ret; -+} -+ -+int sized_domain_name(TALLOC_CTX *mem_ctx, -+ struct resp_ctx *rctx, -+ const char *member_name, -+ struct sized_string **_name) -+{ -+ TALLOC_CTX *tmp_ctx = NULL; -+ errno_t ret; -+ char *domname; -+ struct sss_domain_info *member_dom; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = sss_parse_internal_fqname(tmp_ctx, member_name, NULL, &domname); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_internal_fqname failed\n"); -+ goto done; -+ } -+ -+ if (domname == NULL) { -+ ret = ERR_WRONG_NAME_FORMAT; -+ goto done; -+ } -+ -+ member_dom = find_domain_by_name(get_domains_head(rctx->domains), -+ domname, true); -+ if (member_dom == NULL) { -+ ret = ERR_DOMAIN_NOT_FOUND; -+ goto done; -+ } -+ -+ ret = sized_output_name(mem_ctx, rctx, member_name, -+ member_dom, _name); -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -diff --git a/src/responder/nss/nss_private.h b/src/responder/nss/nss_private.h -index acb3c4aa504e538ca56dca8d43ee04b0f60954a9..13de83226177bbaa8b8237e3e27b7e72da369194 100644 ---- a/src/responder/nss/nss_private.h -+++ b/src/responder/nss/nss_private.h -@@ -140,17 +140,6 @@ const char * - nss_get_name_from_msg(struct sss_domain_info *domain, - struct ldb_message *msg); - --int sized_output_name(TALLOC_CTX *mem_ctx, -- struct resp_ctx *rctx, -- const char *orig_name, -- struct sss_domain_info *name_dom, -- struct sized_string **_name); -- --int sized_member_name(TALLOC_CTX *mem_ctx, -- struct resp_ctx *rctx, -- const char *member_name, -- struct sized_string **_name); -- - const char * - nss_get_pwfield(struct nss_ctx *nctx, - struct sss_domain_info *dom); -diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c -index 283ab9f6731bc4c8261ca79075ab030005bf70db..fae1d47d7b217beafba75740e2e6d9cb8cdbc1d0 100644 ---- a/src/responder/nss/nss_protocol_grent.c -+++ b/src/responder/nss/nss_protocol_grent.c -@@ -163,7 +163,7 @@ nss_protocol_fill_members(struct sss_packet *packet, - } - } - -- ret = sized_member_name(tmp_ctx, rctx, member_name, &name); -+ ret = sized_domain_name(tmp_ctx, rctx, member_name, &name); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to get sized name [%d]: %s\n", - ret, sss_strerror(ret)); -diff --git a/src/responder/nss/nss_utils.c b/src/responder/nss/nss_utils.c -index f839930a275db56e8d729888af870562d7b6f260..2cd9c33b42f7e018ea89d2df206637f35646489e 100644 ---- a/src/responder/nss/nss_utils.c -+++ b/src/responder/nss/nss_utils.c -@@ -53,93 +53,6 @@ nss_get_name_from_msg(struct sss_domain_info *domain, - return ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); - } - --int sized_output_name(TALLOC_CTX *mem_ctx, -- struct resp_ctx *rctx, -- const char *orig_name, -- struct sss_domain_info *name_dom, -- struct sized_string **_name) --{ -- TALLOC_CTX *tmp_ctx = NULL; -- errno_t ret; -- char *username; -- struct sized_string *name; -- -- tmp_ctx = talloc_new(NULL); -- if (tmp_ctx == NULL) { -- return ENOMEM; -- } -- -- username = sss_output_name(tmp_ctx, orig_name, name_dom->case_preserve, -- rctx->override_space); -- if (username == NULL) { -- ret = EIO; -- goto done; -- } -- -- if (name_dom->fqnames) { -- username = sss_tc_fqname(tmp_ctx, name_dom->names, name_dom, username); -- if (username == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "sss_replace_space failed\n"); -- ret = EIO; -- goto done; -- } -- } -- -- name = talloc_zero(tmp_ctx, struct sized_string); -- if (name == NULL) { -- ret = ENOMEM; -- goto done; -- } -- -- to_sized_string(name, username); -- name->str = talloc_steal(name, username); -- *_name = talloc_steal(mem_ctx, name); -- ret = EOK; --done: -- talloc_zfree(tmp_ctx); -- return ret; --} -- --int sized_member_name(TALLOC_CTX *mem_ctx, -- struct resp_ctx *rctx, -- const char *member_name, -- struct sized_string **_name) --{ -- TALLOC_CTX *tmp_ctx = NULL; -- errno_t ret; -- char *domname; -- struct sss_domain_info *member_dom; -- -- tmp_ctx = talloc_new(NULL); -- if (tmp_ctx == NULL) { -- return ENOMEM; -- } -- -- ret = sss_parse_internal_fqname(tmp_ctx, member_name, NULL, &domname); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_internal_fqname failed\n"); -- goto done; -- } -- -- if (domname == NULL) { -- ret = ERR_WRONG_NAME_FORMAT; -- goto done; -- } -- -- member_dom = find_domain_by_name(get_domains_head(rctx->domains), -- domname, true); -- if (member_dom == NULL) { -- ret = ERR_DOMAIN_NOT_FOUND; -- goto done; -- } -- -- ret = sized_output_name(mem_ctx, rctx, member_name, -- member_dom, _name); --done: -- talloc_free(tmp_ctx); -- return ret; --} -- - const char * - nss_get_pwfield(struct nss_ctx *nctx, - struct sss_domain_info *dom) --- -2.9.3 - diff --git a/SOURCES/0104-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch b/SOURCES/0104-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch deleted file mode 100644 index 8d252f9..0000000 --- a/SOURCES/0104-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 956d7e794d6c07eec3c0009253c8a86320c3e741 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 19 Apr 2017 17:46:03 +0200 -Subject: [PATCH 104/104] IFP: Use sized_domain_name to format the groups the - user is a member of -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: - https://pagure.io/SSSD/sssd/issue/3268 - -Uses the common function sized_domain_name() to format a group the user -is a member of to the appropriate format. - -To see the code is working correctly, run: - dbus-send --system --print-reply --dest=org.freedesktop.sssd.infopipe - /org/freedesktop/sssd/infopipe - org.freedesktop.sssd.infopipe.GetUserGroups - string:trusted_user - -Where trusted_user is a user from a trusted domain that is a member of groups -from the joined domain and a trusted domain as well. The groups from the -joined domain should not be qualified, the groups from the trusted -domain should be qualified. - -Reviewed-by: Pavel Březina -(cherry picked from commit c9a73bb6ffa010ef206896a0d1c2801bc056fa45) ---- - src/responder/ifp/ifpsrv_cmd.c | 29 +++++++++++++++-------------- - 1 file changed, 15 insertions(+), 14 deletions(-) - -diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c -index d10f35e41dbb1623a0b9de37a4c43363cbefc1a3..e4d6c42ef35ef372472803d3d26b17d4181021a8 100644 ---- a/src/responder/ifp/ifpsrv_cmd.c -+++ b/src/responder/ifp/ifpsrv_cmd.c -@@ -369,10 +369,11 @@ ifp_user_get_groups_reply(struct sss_domain_info *domain, - struct ifp_req *ireq, - struct ldb_result *res) - { -- int i, num; -+ int i, gri, num; - const char *name; - const char **groupnames; -- char *out_name; -+ struct sized_string *group_name; -+ errno_t ret; - - /* one less, the first one is the user entry */ - num = res->count - 1; -@@ -381,6 +382,7 @@ ifp_user_get_groups_reply(struct sss_domain_info *domain, - return sbus_request_finish(ireq->dbus_req, NULL); - } - -+ gri = 0; - for (i = 0; i < num; i++) { - name = sss_view_ldb_msg_find_attr_as_string(domain, - res->msgs[i + 1], -@@ -390,22 +392,21 @@ ifp_user_get_groups_reply(struct sss_domain_info *domain, - continue; - } - -- out_name = sss_output_name(ireq, name, domain->case_preserve, -- ireq->ifp_ctx->rctx->override_space); -- if (out_name == NULL) { -+ ret = sized_domain_name(ireq, ireq->ifp_ctx->rctx, name, &group_name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Unable to get sized name for %s [%d]: %s\n", -+ name, ret, sss_strerror(ret)); - continue; - } - -- if (domain->fqnames) { -- groupnames[i] = sss_tc_fqname(groupnames, domain->names, -- domain, out_name); -- if (out_name == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "sss_tc_fqname failed\n"); -- continue; -- } -- } else { -- groupnames[i] = talloc_steal(groupnames, out_name); -+ groupnames[gri] = talloc_strndup(groupnames, -+ group_name->str, group_name->len); -+ if (groupnames[gri] == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "talloc_strndup failed\n"); -+ continue; - } -+ gri++; - - DEBUG(SSSDBG_TRACE_FUNC, "Adding group %s\n", groupnames[i]); - } --- -2.9.3 - diff --git a/SOURCES/0105-RESPONDER-Fallback-to-global-domain-resolution-order.patch b/SOURCES/0105-RESPONDER-Fallback-to-global-domain-resolution-order.patch deleted file mode 100644 index e0094c0..0000000 --- a/SOURCES/0105-RESPONDER-Fallback-to-global-domain-resolution-order.patch +++ /dev/null @@ -1,313 +0,0 @@ -From b7d2310e9ddd79bfdea2bc334bd11d4df9be37a2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 12 Apr 2017 10:43:25 +0200 -Subject: [PATCH 105/110] RESPONDER: Fallback to global domain resolution order - in case the view doesn't have this option set -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The current code has been ignoring the domain resolution order set -globally on IPA in case there's a view but this doesn't have any domain -resolution order set. - -It happens because we haven't been checking whether the view attribute -didn't exist and then we ended up populating the list cache_req domains' -list assuming that no order has been set instead of falling back to the -next preferred method. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Pavel Březina -(cherry picked from commit a3faad0e4dc1ca4473746c3822ecfc5aed876e6d) ---- - src/responder/common/cache_req/cache_req_domain.c | 14 ++- - src/responder/common/cache_req/cache_req_domain.h | 5 +- - src/responder/common/responder_common.c | 108 +++++++++++++--------- - 3 files changed, 74 insertions(+), 53 deletions(-) - -diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c -index bbabd695f1c6b6c29b7e61f571382ab9adfb0ea2..86a88efd54ca0f4a0748b44ece1b8515438d4628 100644 ---- a/src/responder/common/cache_req/cache_req_domain.c -+++ b/src/responder/common/cache_req/cache_req_domain.c -@@ -120,20 +120,21 @@ done: - return cr_domains; - } - --struct cache_req_domain * -+errno_t - cache_req_domain_new_list_from_domain_resolution_order( - TALLOC_CTX *mem_ctx, - struct sss_domain_info *domains, -- const char *domain_resolution_order) -+ const char *domain_resolution_order, -+ struct cache_req_domain **_cr_domains) - { - TALLOC_CTX *tmp_ctx; -- struct cache_req_domain *cr_domains = NULL; -+ struct cache_req_domain *cr_domains; - char **list = NULL; - errno_t ret; - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { -- return NULL; -+ return ENOMEM; - } - - if (domain_resolution_order != NULL) { -@@ -160,7 +161,10 @@ cache_req_domain_new_list_from_domain_resolution_order( - goto done; - } - -+ *_cr_domains = cr_domains; -+ ret = EOK; -+ - done: - talloc_free(tmp_ctx); -- return cr_domains; -+ return ret; - } -diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h -index 41c50e8c293d7b032cb2f05482c40e93e4f723dc..000087e5ca2074f22169a4af627810f4f287e430 100644 ---- a/src/responder/common/cache_req/cache_req_domain.h -+++ b/src/responder/common/cache_req/cache_req_domain.h -@@ -34,11 +34,12 @@ struct cache_req_domain * - cache_req_domain_get_domain_by_name(struct cache_req_domain *domains, - const char *name); - --struct cache_req_domain * -+errno_t - cache_req_domain_new_list_from_domain_resolution_order( - TALLOC_CTX *mem_ctx, - struct sss_domain_info *domains, -- const char *domain_resolution_order); -+ const char *domain_resolution_order, -+ struct cache_req_domain **_cr_domains); - - void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains); - -diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c -index ac6320b08de09bc6c7e8dd1af72e0a493a449f7a..62b71b5104fdbb585d086d44d2ca2ab9717dd788 100644 ---- a/src/responder/common/responder_common.c -+++ b/src/responder/common/responder_common.c -@@ -1486,10 +1486,11 @@ fail: - } - - /* ====== Helper functions for the domain resolution order ======= */ --static struct cache_req_domain * -+static errno_t - sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domains, -- struct sysdb_ctx *sysdb) -+ struct sysdb_ctx *sysdb, -+ struct cache_req_domain **_cr_domains) - { - TALLOC_CTX *tmp_ctx; - struct cache_req_domain *cr_domains = NULL; -@@ -1498,7 +1499,7 @@ sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx, - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { -- return NULL; -+ return ENOMEM; - } - - ret = sysdb_get_view_domain_resolution_order(tmp_ctx, sysdb, -@@ -1510,12 +1511,13 @@ sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx, - goto done; - } - -- /* Using mem_ctx (which is rctx) directly here to avoid copying -- * this memory around. */ -- cr_domains = cache_req_domain_new_list_from_domain_resolution_order( -- mem_ctx, domains, domain_resolution_order); -- if (cr_domains == NULL) { -- ret = ENOMEM; -+ if (ret == ENOENT) { -+ goto done; -+ } -+ -+ ret = cache_req_domain_new_list_from_domain_resolution_order( -+ mem_ctx, domains, domain_resolution_order, &cr_domains); -+ if (ret != EOK) { - DEBUG(SSSDBG_DEFAULT, - "cache_req_domain_new_list_from_domain_resolution_order() " - "failed [%d]: [%s].\n", -@@ -1523,25 +1525,31 @@ sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx, - goto done; - } - -+ *_cr_domains = cr_domains; -+ -+ ret = EOK; -+ - done: - talloc_free(tmp_ctx); -- return cr_domains; -+ return ret; - } - --static struct cache_req_domain * -+static errno_t - sss_resp_new_cr_domains_from_ipa_config(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domains, - struct sysdb_ctx *sysdb, -- const char *domain) -+ const char *domain, -+ struct cache_req_domain **_cr_domains) - { - TALLOC_CTX *tmp_ctx; -- struct cache_req_domain *cr_domains = NULL; - const char *domain_resolution_order = NULL; - errno_t ret; - -+ *_cr_domains = NULL; -+ - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { -- return NULL; -+ return ENOMEM; - } - - ret = sysdb_domain_get_domain_resolution_order(tmp_ctx, sysdb, domain, -@@ -1554,11 +1562,13 @@ sss_resp_new_cr_domains_from_ipa_config(TALLOC_CTX *mem_ctx, - goto done; - } - -- /* Using mem_ctx (which is rctx) directly here to avoid copying -- * this memory around. */ -- cr_domains = cache_req_domain_new_list_from_domain_resolution_order( -- mem_ctx, domains, domain_resolution_order); -- if (cr_domains == NULL) { -+ if (ret == ENOENT) { -+ goto done; -+ } -+ -+ ret = cache_req_domain_new_list_from_domain_resolution_order( -+ mem_ctx, domains, domain_resolution_order, _cr_domains); -+ if (ret != EOK) { - DEBUG(SSSDBG_DEFAULT, - "cache_req_domain_new_list_from_domain_resolution_order() " - "failed [%d]: [%s].\n", -@@ -1566,9 +1576,11 @@ sss_resp_new_cr_domains_from_ipa_config(TALLOC_CTX *mem_ctx, - goto done; - } - -+ ret = EOK; -+ - done: - talloc_free(tmp_ctx); -- return cr_domains; -+ return ret; - } - - errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) -@@ -1578,16 +1590,16 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) - errno_t ret; - - if (rctx->domain_resolution_order != NULL) { -- cr_domains = cache_req_domain_new_list_from_domain_resolution_order( -- rctx, rctx->domains, rctx->domain_resolution_order); -- -- if (cr_domains == NULL) { -+ ret = cache_req_domain_new_list_from_domain_resolution_order( -+ rctx, rctx->domains, -+ rctx->domain_resolution_order, &cr_domains); -+ if (ret == EOK) { -+ goto done; -+ } else { - DEBUG(SSSDBG_MINOR_FAILURE, - "Failed to use domain_resolution_order set in the config file.\n" - "Trying to fallback to use ipaDomainOrderResolution setup by " - "IPA.\n"); -- } else { -- goto done; - } - } - -@@ -1598,9 +1610,9 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) - } - - if (dom == NULL) { -- cr_domains = cache_req_domain_new_list_from_domain_resolution_order( -- rctx, rctx->domains, NULL); -- if (cr_domains == NULL) { -+ ret = cache_req_domain_new_list_from_domain_resolution_order( -+ rctx, rctx->domains, NULL, &cr_domains); -+ if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Failed to flatten the list of domains.\n"); - } -@@ -1608,44 +1620,48 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) - } - - if (dom->has_views) { -- cr_domains = sss_resp_new_cr_domains_from_ipa_id_view(rctx, -- rctx->domains, -- dom->sysdb); -- if (cr_domains == NULL) { -+ ret = sss_resp_new_cr_domains_from_ipa_id_view(rctx, rctx->domains, -+ dom->sysdb, -+ &cr_domains); -+ if (ret == EOK) { -+ goto done; -+ } -+ -+ if (ret != ENOENT) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Failed to use ipaDomainResolutionOrder set for the " - "view \"%s\".\n" - "Trying to fallback to use ipaDomainOrderResolution " - "set in ipaConfig for the domain: %s.\n", - dom->view_name, dom->name); -- } else { -- goto done; - } - } - -- cr_domains = sss_resp_new_cr_domains_from_ipa_config(rctx, rctx->domains, -- dom->sysdb, -- dom->name); -- if (cr_domains == NULL) { -+ ret = sss_resp_new_cr_domains_from_ipa_config(rctx, rctx->domains, -+ dom->sysdb, dom->name, -+ &cr_domains); -+ if (ret == EOK) { -+ goto done; -+ } -+ -+ if (ret != ENOENT) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Failed to use ipaDomainResolutionOrder set in ipaConfig " - "for the domain: \"%s\".\n" - "No ipaDomainResolutionOrder will be followed.\n", - dom->name); -- } else { -- goto done; - } - -- cr_domains = cache_req_domain_new_list_from_domain_resolution_order( -- rctx, rctx->domains, NULL); -- if (cr_domains == NULL) { -+ ret = cache_req_domain_new_list_from_domain_resolution_order( -+ rctx, rctx->domains, NULL, &cr_domains); -+ if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Failed to flatten the list of domains.\n"); - goto done; - } - --done: -- ret = cr_domains != NULL ? EOK : ENOMEM; -+ ret = EOK; - -+done: - cache_req_domain_list_zfree(&rctx->cr_domains); - rctx->cr_domains = cr_domains; - --- -2.9.3 - diff --git a/SOURCES/0106-NSS-TESTS-Improve-non-fqnames-tests.patch b/SOURCES/0106-NSS-TESTS-Improve-non-fqnames-tests.patch deleted file mode 100644 index fce885a..0000000 --- a/SOURCES/0106-NSS-TESTS-Improve-non-fqnames-tests.patch +++ /dev/null @@ -1,164 +0,0 @@ -From b4b409f2c5bd0f0b26015b0562ae0ee0e831da82 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Mon, 17 Apr 2017 09:32:39 +0200 -Subject: [PATCH 106/110] NSS/TESTS: Improve non-fqnames tests -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -With the changes that are about to happen we have to have the subdomain's -fqnames flag set by the time we populate the cr_domains list (as it -actually occurs with the real code), as this list may set its own fqnames -flag based on the subdomain's fqnames flag. - -Currently the flag is set to false only when running the tests itself so -the cr_domains list doesn't get populate properly (although it still -works with the current code). - -For the changes that are comming, let's introduce a new setup function -that ensures that the subdomain's fqnames flag is set up in the right -time. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Pavel Březina -(cherry picked from commit ed518f61f1a5d4cf5d87eec492c158725a73d6a1) ---- - src/tests/cmocka/test_nss_srv.c | 45 +++++++++++++++++++++++++++-------------- - 1 file changed, 30 insertions(+), 15 deletions(-) - -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 2f526660cbbbf2443dbae4e213c1336feb6c661e..8c72f44f1869558893627e1f2f91b5f3b96c6317 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -1709,8 +1709,6 @@ void test_nss_getgrnam_members_subdom_nonfqnames(void **state) - { - errno_t ret; - -- nss_test_ctx->subdom->fqnames = false; -- - mock_input_user_or_group("testsubdomgroup"); - mock_account_recv_simple(); - will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); -@@ -1802,8 +1800,6 @@ void test_nss_getgrnam_mix_dom_nonfqnames(void **state) - { - errno_t ret; - -- nss_test_ctx->subdom->fqnames = false; -- - ret = store_group_member(nss_test_ctx, - testgroup_members.gr_name, - nss_test_ctx->tctx->dom, -@@ -1917,6 +1913,7 @@ void test_nss_getgrnam_mix_dom_fqdn(void **state) - assert_int_equal(ret, EOK); - } - -+ - void test_nss_getgrnam_mix_dom_fqdn_nonfqnames(void **state) - { - errno_t ret; -@@ -1929,10 +1926,6 @@ void test_nss_getgrnam_mix_dom_fqdn_nonfqnames(void **state) - SYSDB_MEMBER_USER); - assert_int_equal(ret, EOK); - -- nss_test_ctx->tctx->dom->fqnames = false; -- nss_test_ctx->subdom->fqnames = false; -- -- - mock_input_user_or_group("testgroup_members"); - will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); - will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -@@ -2044,8 +2037,6 @@ void test_nss_getgrnam_mix_subdom_nonfqnames(void **state) - { - errno_t ret; - -- nss_test_ctx->subdom->fqnames = false; -- - ret = store_group_member(nss_test_ctx, - testsubdomgroup.gr_name, - nss_test_ctx->subdom, -@@ -3417,9 +3408,11 @@ static int nss_test_setup_extra_attr(void **state) - return 0; - } - --static int nss_subdom_test_setup(void **state) -+static int nss_subdom_test_setup_common(void **state, bool nonfqnames) - { - const char *const testdom[4] = { TEST_SUBDOM_NAME, "TEST.SUB", "test", "S-3" }; -+ struct sss_domain_info *dom; -+ - struct sss_domain_info *subdomain; - errno_t ret; - -@@ -3440,6 +3433,17 @@ static int nss_subdom_test_setup(void **state) - nss_test_ctx->tctx->confdb); - assert_int_equal(ret, EOK); - -+ if (nonfqnames) { -+ for (dom = nss_test_ctx->rctx->domains; -+ dom != NULL; -+ dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) { -+ if (strcmp(dom->name, subdomain->name) == 0) { -+ dom->fqnames = false; -+ break; -+ } -+ } -+ } -+ - ret = sss_resp_populate_cr_domains(nss_test_ctx->rctx); - assert_int_equal(ret, EOK); - assert_non_null(nss_test_ctx->rctx->cr_domains); -@@ -3475,6 +3479,17 @@ static int nss_subdom_test_setup(void **state) - assert_int_equal(ret, EOK); - - return 0; -+ -+} -+ -+static int nss_subdom_test_setup(void **state) -+{ -+ return nss_subdom_test_setup_common(state, false); -+} -+ -+static int nss_subdom_test_setup_nonfqnames(void **state) -+{ -+ return nss_subdom_test_setup_common(state, true); - } - - static int nss_fqdn_fancy_test_setup(void **state) -@@ -4192,25 +4207,25 @@ int main(int argc, const char *argv[]) - nss_subdom_test_setup, - nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_subdom_nonfqnames, -- nss_subdom_test_setup, -+ nss_subdom_test_setup_nonfqnames, - nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom, - nss_subdom_test_setup, - nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_nonfqnames, -- nss_subdom_test_setup, -+ nss_subdom_test_setup_nonfqnames, - nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn, - nss_subdom_test_setup, - nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn_nonfqnames, -- nss_subdom_test_setup, -+ nss_subdom_test_setup_nonfqnames, - nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom, - nss_subdom_test_setup, - nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom_nonfqnames, -- nss_subdom_test_setup, -+ nss_subdom_test_setup_nonfqnames, - nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getgrnam_space, - nss_test_setup, nss_test_teardown), --- -2.9.3 - diff --git a/SOURCES/0107-CACHE_REQ-Allow-configurationless-shortname-lookups.patch b/SOURCES/0107-CACHE_REQ-Allow-configurationless-shortname-lookups.patch deleted file mode 100644 index 352e52d..0000000 --- a/SOURCES/0107-CACHE_REQ-Allow-configurationless-shortname-lookups.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 7c6fd66fa9ca942bc240b49f903d9d3d85340c4c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Tue, 11 Apr 2017 17:19:29 +0200 -Subject: [PATCH 107/110] CACHE_REQ: Allow configurationless shortname lookups -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Configurationless shortnames lookups must be allowed when a domains' -resolution order is present and the (head) domain is not enforcing the -usage of fully-qualified-names. - -With this patch SSSD does not require any kind of changes from client -side for taking advantage of shortname lookups. - -Related: -https://pagure.io/SSSD/sssd/issue/3001 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Pavel Březina -(cherry picked from commit dae798231fc2c575f213785768bc24ed765ba243) ---- - src/responder/common/cache_req/cache_req.c | 2 +- - src/responder/common/cache_req/cache_req_domain.c | 48 +++++++++++++++++++++++ - src/responder/common/cache_req/cache_req_domain.h | 1 + - 3 files changed, 50 insertions(+), 1 deletion(-) - -diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c -index 3a5fecf34427437bbf95317e05c5bd8b07b4537d..797325a30e6c1ed5f1d4b4c147c65391d5204b52 100644 ---- a/src/responder/common/cache_req/cache_req.c -+++ b/src/responder/common/cache_req/cache_req.c -@@ -480,7 +480,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) - * qualified names on domain less search. We do not descend into - * subdomains here since those are implicitly qualified. - */ -- if (state->check_next && !allow_no_fqn && domain->fqnames) { -+ if (state->check_next && !allow_no_fqn && state->cr_domain->fqnames) { - state->cr_domain = state->cr_domain->next; - continue; - } -diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c -index 86a88efd54ca0f4a0748b44ece1b8515438d4628..bfdd2b7f640178f6d0a0d92f2fed329c856b478c 100644 ---- a/src/responder/common/cache_req/cache_req_domain.c -+++ b/src/responder/common/cache_req/cache_req_domain.c -@@ -60,6 +60,48 @@ void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains) - *cr_domains = NULL; - } - -+static bool -+cache_req_domain_use_fqnames(struct sss_domain_info *domain, -+ bool enforce_non_fqnames) -+{ -+ struct sss_domain_info *head; -+ -+ head = get_domains_head(domain); -+ -+ /* -+ * In order to decide whether fully_qualified_names must be used on the -+ * lookups we have to take into consideration: -+ * - use_fully_qualified_name value of the head of the domains; -+ * (head->fqnames) -+ * - the presence of a domains' resolution order list; -+ * (non_fqnames_enforced) -+ * -+ * The relationship between those two can be described by: -+ * - head->fqnames: -+ * - true: in this case doesn't matter whether it's enforced or not, -+ * fully-qualified-names will _always_ be used -+ * - false: in this case (which is also the default case), the usage -+ * depends on it being enforced; -+ * -+ * - enforce_non_fqnames: -+ * - true: in this case, the usage of fully-qualified-names is not -+ * needed; -+ * - false: in this case, the usage of fully-qualified-names will be -+ * done accordingly to what's set for the domain itself. -+ */ -+ switch (head->fqnames) { -+ case true: -+ return true; -+ case false: -+ switch (enforce_non_fqnames) { -+ case true: -+ return false; -+ case false: -+ return domain->fqnames; -+ } -+ } -+} -+ - static struct cache_req_domain * - cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domains, -@@ -71,9 +113,11 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, - char *name; - int flag = SSS_GND_ALL_DOMAINS; - int i; -+ bool enforce_non_fqnames = false; - errno_t ret; - - if (resolution_order != NULL) { -+ enforce_non_fqnames = true; - for (i = 0; resolution_order[i] != NULL; i++) { - name = resolution_order[i]; - for (dom = domains; dom; dom = get_next_domain(dom, flag)) { -@@ -87,6 +131,8 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, - goto done; - } - cr_domain->domain = dom; -+ cr_domain->fqnames = -+ cache_req_domain_use_fqnames(dom, enforce_non_fqnames); - - DLIST_ADD_END(cr_domains, cr_domain, - struct cache_req_domain *); -@@ -106,6 +152,8 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, - goto done; - } - cr_domain->domain = dom; -+ cr_domain->fqnames = -+ cache_req_domain_use_fqnames(dom, enforce_non_fqnames); - - DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *); - } -diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h -index 000087e5ca2074f22169a4af627810f4f287e430..5bcbb9b493caf05bf71aac5cf7633ded91f22e73 100644 ---- a/src/responder/common/cache_req/cache_req_domain.h -+++ b/src/responder/common/cache_req/cache_req_domain.h -@@ -25,6 +25,7 @@ - - struct cache_req_domain { - struct sss_domain_info *domain; -+ bool fqnames; - - struct cache_req_domain *prev; - struct cache_req_domain *next; --- -2.9.3 - diff --git a/SOURCES/0108-CACHE_REQ_DOMAIN-Add-some-comments-to-cache_req_doma.patch b/SOURCES/0108-CACHE_REQ_DOMAIN-Add-some-comments-to-cache_req_doma.patch deleted file mode 100644 index 86ba24f..0000000 --- a/SOURCES/0108-CACHE_REQ_DOMAIN-Add-some-comments-to-cache_req_doma.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 3d55506f2e6584d412ca07f2d0d77375aae48ba9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Mon, 24 Apr 2017 21:04:58 +0200 -Subject: [PATCH 108/110] CACHE_REQ_DOMAIN: Add some comments to - cache_req_domain_new_list_from_string_list() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Pavel Březina -(cherry picked from commit f9bac02756aa05cc9c6ac07ae581dba67240c1a4) ---- - src/responder/common/cache_req/cache_req_domain.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c -index bfdd2b7f640178f6d0a0d92f2fed329c856b478c..6d37db0f109d5343eb6d7f4272bea522d4c34cf7 100644 ---- a/src/responder/common/cache_req/cache_req_domain.c -+++ b/src/responder/common/cache_req/cache_req_domain.c -@@ -116,6 +116,8 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, - bool enforce_non_fqnames = false; - errno_t ret; - -+ /* Firstly, in case a domains' resolution order is passed ... iterate over -+ * the list adding its domains to the flatten cache req domains' list */ - if (resolution_order != NULL) { - enforce_non_fqnames = true; - for (i = 0; resolution_order[i] != NULL; i++) { -@@ -141,6 +143,8 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, - } - } - -+ /* Then iterate through all the other domains (and subdomains) and add them -+ * to the flatten cache req domains' list */ - for (dom = domains; dom; dom = get_next_domain(dom, flag)) { - if (string_in_list(dom->name, resolution_order, false)) { - continue; --- -2.9.3 - diff --git a/SOURCES/0109-RESPONDER_COMMON-Improve-domaiN_resolution_order-deb.patch b/SOURCES/0109-RESPONDER_COMMON-Improve-domaiN_resolution_order-deb.patch deleted file mode 100644 index a1abb10..0000000 --- a/SOURCES/0109-RESPONDER_COMMON-Improve-domaiN_resolution_order-deb.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 326442dc734de72b950a47c5fe2b3ac6a1dfc35e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Mon, 24 Apr 2017 21:09:02 +0200 -Subject: [PATCH 109/110] RESPONDER_COMMON: Improve domaiN_resolution_order - debug messages -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Indicate whether a domain_resolution_order has been used and where -it came from. - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Pavel Březina -(cherry picked from commit 213048fd9a5e800deb74cb5b7f0eaf465945c640) ---- - src/responder/common/responder_common.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c -index 62b71b5104fdbb585d086d44d2ca2ab9717dd788..7496d293fddb3e947d59a4f2aaeb2c83234dfcc7 100644 ---- a/src/responder/common/responder_common.c -+++ b/src/responder/common/responder_common.c -@@ -1594,6 +1594,8 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) - rctx, rctx->domains, - rctx->domain_resolution_order, &cr_domains); - if (ret == EOK) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Using domain_resolution_order from sssd.conf\n"); - goto done; - } else { - DEBUG(SSSDBG_MINOR_FAILURE, -@@ -1624,6 +1626,8 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) - dom->sysdb, - &cr_domains); - if (ret == EOK) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Using domain_resolution_order from IPA ID View\n"); - goto done; - } - -@@ -1641,6 +1645,8 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) - dom->sysdb, dom->name, - &cr_domains); - if (ret == EOK) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Using domain_resolution_order from IPA Config\n"); - goto done; - } - --- -2.9.3 - diff --git a/SOURCES/0110-CACHE_REQ_DOMAIN-debug-the-set-domain-resolution-ord.patch b/SOURCES/0110-CACHE_REQ_DOMAIN-debug-the-set-domain-resolution-ord.patch deleted file mode 100644 index 8507ad0..0000000 --- a/SOURCES/0110-CACHE_REQ_DOMAIN-debug-the-set-domain-resolution-ord.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 3671f188ff9e379022d62eaf7171f397f04ac153 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Tue, 25 Apr 2017 14:25:12 +0200 -Subject: [PATCH 110/110] CACHE_REQ_DOMAIN: debug the set domain resolution - order -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Pavel Březina -(cherry picked from commit b78febe4c579f86f8007a27599605d1eb9f97a62) ---- - src/responder/common/cache_req/cache_req_domain.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c -index 6d37db0f109d5343eb6d7f4272bea522d4c34cf7..2c238c9966d322bb542fa2047313ee9e5144edee 100644 ---- a/src/responder/common/cache_req/cache_req_domain.c -+++ b/src/responder/common/cache_req/cache_req_domain.c -@@ -191,6 +191,10 @@ cache_req_domain_new_list_from_domain_resolution_order( - - if (domain_resolution_order != NULL) { - if (strcmp(domain_resolution_order, ":") != 0) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Domain resolution order list (split by ':'): \"%s\"\n", -+ domain_resolution_order); -+ - ret = split_on_separator(tmp_ctx, domain_resolution_order, ':', - true, true, &list, NULL); - if (ret != EOK) { -@@ -199,7 +203,14 @@ cache_req_domain_new_list_from_domain_resolution_order( - ret, sss_strerror(ret)); - goto done; - } -+ } else { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Domain resolution order list: ':' " -+ "(do not use any specific order)\n"); - } -+ } else { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Domain resolution order list: not set\n"); - } - - cr_domains = cache_req_domain_new_list_from_string_list(mem_ctx, domains, --- -2.9.3 - diff --git a/SOURCES/0111-SECRETS-remove-unused-variable.patch b/SOURCES/0111-SECRETS-remove-unused-variable.patch deleted file mode 100644 index 1e1d87c..0000000 --- a/SOURCES/0111-SECRETS-remove-unused-variable.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 429c282e54feb0e1c9ac27d23be6a8c1d4119976 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Wed, 19 Apr 2017 17:56:20 +0200 -Subject: [PATCH 111/118] SECRETS: remove unused variable -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Pavel Březina -(cherry picked from commit 0e8f0c06cad5805b1a1161f60e3f2cdb7a5a2921) ---- - src/responder/secrets/proxy.c | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c -index fd96e985c897e2cb470a9b5d6eecbd34350fb7d2..9c2aa425d414728d10aa830f640632e98def3c1c 100644 ---- a/src/responder/secrets/proxy.c -+++ b/src/responder/secrets/proxy.c -@@ -570,11 +570,6 @@ static void proxy_secret_req_done(struct tevent_req *subreq) - } - } - --struct provider_handle proxy_secrets_handle = { -- .fn = proxy_secret_req, -- .context = NULL, --}; -- - int proxy_secrets_provider_handle(struct sec_ctx *sctx, - struct provider_handle **out_handle) - { --- -2.9.3 - diff --git a/SOURCES/0112-IPA-Improve-DEBUG-message-if-a-group-has-no-ipaNTSec.patch b/SOURCES/0112-IPA-Improve-DEBUG-message-if-a-group-has-no-ipaNTSec.patch deleted file mode 100644 index 77c2a5b..0000000 --- a/SOURCES/0112-IPA-Improve-DEBUG-message-if-a-group-has-no-ipaNTSec.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 396849b6160594dbb6dedec5d1bd7fbc3af12cdd Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 21 Apr 2017 12:39:44 +0200 -Subject: [PATCH 112/118] IPA: Improve DEBUG message if a group has no - ipaNTSecurityIdentifier -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There was an issue in a production deployment where the admin selected a -GID outside the IDM range for a group that contained a user from the -trusted domain. This resulted in not adding a SID for the IPA group, -which in turn meant the group couldn't be resolved on the client. - -This patch just improves the DEBUG message so that it's clearer for the -admins where the issue is. - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit ef019268d2d112ebff3577e551cd19478d73d93b) ---- - src/providers/ipa/ipa_s2n_exop.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index 2173db357700499a6140aa61841e443139981483..55ec904ca3188c7cf10ac41972e9ecf94ebf44bb 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -1308,7 +1308,10 @@ static void ipa_s2n_get_list_next(struct tevent_req *subreq) - ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR, - &sid_str); - if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Object [%s] has no SID, please check the " -+ "ipaNTSecurityIdentifier attribute on the server-side", -+ state->attrs->a.name); - goto fail; - } - --- -2.9.3 - diff --git a/SOURCES/0113-IPA-Improve-s2n-debug-message-for-missing-ipaNTSecur.patch b/SOURCES/0113-IPA-Improve-s2n-debug-message-for-missing-ipaNTSecur.patch deleted file mode 100644 index a2ccf0b..0000000 --- a/SOURCES/0113-IPA-Improve-s2n-debug-message-for-missing-ipaNTSecur.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 522dffca552146c0af74325b6ceab0ca950bbc1a Mon Sep 17 00:00:00 2001 -From: Justin Stephenson -Date: Tue, 25 Apr 2017 13:02:10 -0400 -Subject: [PATCH 113/118] IPA: Improve s2n debug message for missing - ipaNTSecurityIdentifier -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch improves the log message to be more information for -the SSSD user troubleshooting issues. - -If the IDM POSIX group used for AD trust HBAC/SUDO operation is missing -the ipaNTSecurityIdentifier it can cause client s2n operations failures -resolving the group which resulted in the inability to login for the AD -user. - -Reviewed-by: Pavel Březina -(cherry picked from commit 0c5f463e9629ac08d647c70cffb30bccdd57ae96) ---- - src/providers/ipa/ipa_s2n_exop.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index 55ec904ca3188c7cf10ac41972e9ecf94ebf44bb..f5f4401f86615dc7f81f844e1096ad43e965c384 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -2580,7 +2580,13 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, - ret = sysdb_attrs_get_string(attrs->sysdb_attrs, SYSDB_SID_STR, &sid_str); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, -- "Cannot find SID of object with override.\n"); -+ "Cannot find SID of object.\n"); -+ if (name != NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Object [%s] has no SID, please check the " -+ "ipaNTSecurityIdentifier attribute on the server-side.\n", -+ name); -+ } - goto done; - } - --- -2.9.3 - diff --git a/SOURCES/0114-CONFDB-Fix-standalone-application-domains.patch b/SOURCES/0114-CONFDB-Fix-standalone-application-domains.patch deleted file mode 100644 index 9d2968e..0000000 --- a/SOURCES/0114-CONFDB-Fix-standalone-application-domains.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 8441030009c22daa835f89dbc36365415524b320 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 31 Mar 2017 17:12:56 +0200 -Subject: [PATCH 114/118] CONFDB: Fix standalone application domains -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When a standalone application domain was configured, for example: - -------------------------------------------------- -[sssd] -domains = appdomain - -[application/appdomain] -id_provider=ldap -ldap_uri = ldap://dc.ipa.test -ldap_search_base = cn=accounts,dc=ipa,dc=test -ldap_schema = rfc2307bis -sudo_provider = none - -ldap_sasl_mech = gssapi -krb5_realm = IPA.TEST -krb5_server = dc.ipa.test - -ldap_user_uid_number = telephonenumber -ldap_user_gid_number = mobile -ldap_user_extra_attrs = location:l -------------------------------------------------- - -We would, when unrolling the application section into a domain section, -first add a domain stub, equivalent to: ------------------------------ -[domain/appdomain] -domain_type = application ------------------------------ - -Which in config.ldb also contains cn. Then, whem we would add the parameters -from the [application] section, but try to add the cn again. - -This didn't happen when inheriting from a POSIX domain, because there we -would set LDB_FLAG_REPLACE for any attributes that exist in the inherited -domain. - -This patch skips the cn attribute both when replacing an inherited -domain's attributes and when writing a standalone application domain. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3355 - -Reviewed-by: Pavel Březina -(cherry picked from commit 734e73257fff1c1884b72b8cf988f6d75c3a7567) ---- - src/confdb/confdb.c | 26 ++++++++++++++++++++++---- - 1 file changed, 22 insertions(+), 4 deletions(-) - -diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c -index 88e114457deac3ca50c291a131122624fb6f6fe4..5bb593de03cc2fb26218b883fd1d753e31bedc2d 100644 ---- a/src/confdb/confdb.c -+++ b/src/confdb/confdb.c -@@ -1909,7 +1909,7 @@ static int confdb_add_app_domain(TALLOC_CTX *mem_ctx, - - cdb_path = talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL, name); - if (cdb_path == NULL) { -- return ENOMEM; -+ return ENOMEM; - } - - val[0] = CONFDB_DOMAIN_TYPE_APP; -@@ -1933,6 +1933,7 @@ static int confdb_merge_parent_domain(const char *name, - struct ldb_message *replace_msg = NULL; - struct ldb_message *app_msg = NULL; - struct ldb_dn *domain_dn; -+ struct ldb_message_element *el = NULL; - TALLOC_CTX *tmp_ctx = NULL; - - tmp_ctx = talloc_new(NULL); -@@ -1974,6 +1975,12 @@ static int confdb_merge_parent_domain(const char *name, - replace_msg->elements[i].flags = LDB_FLAG_MOD_ADD; - } - -+ el = ldb_msg_find_element(replace_msg, "cn"); -+ if (el != NULL) { -+ /* Don't add second cn */ -+ ldb_msg_remove_element(replace_msg, el); -+ } -+ - ret = ldb_modify(cdb->ldb, replace_msg); - if (ret != LDB_SUCCESS) { - ret = sysdb_error_to_errno(ret); -@@ -1993,7 +2000,14 @@ static int confdb_merge_parent_domain(const char *name, - app_msg->dn = domain_dn; - - for (unsigned i = 0; i < app_section->msgs[0]->num_elements; i++) { -- struct ldb_message_element *el = NULL; -+ struct ldb_message_element *app_el = &app_section->msgs[0]->elements[i]; -+ -+ /* These elements will be skipped when replacing attributes in -+ * a domain to avoid EEXIST errors -+ */ -+ if (strcasecmp(app_el->name, "cn") == 0) { -+ continue; -+ } - - if (replace_msg != NULL) { - el = ldb_msg_find_element(replace_msg, -@@ -2013,12 +2027,16 @@ static int confdb_merge_parent_domain(const char *name, - ret = ldb_msg_add(app_msg, - &app_section->msgs[0]->elements[i], - ldb_flag); -- if (ret != EOK) { -+ if (ret != LDB_SUCCESS) { - continue; - } - } - -- ret = ldb_modify(cdb->ldb, app_msg); -+ /* We use permissive modification here because adding cn or -+ * distinguishedName from the app_section to the application -+ * message would throw EEXIST -+ */ -+ ret = sss_ldb_modify_permissive(cdb->ldb, app_msg); - if (ret != LDB_SUCCESS) { - ret = sysdb_error_to_errno(ret); - DEBUG(SSSDBG_OP_FAILURE, --- -2.9.3 - diff --git a/SOURCES/0115-utils-add-sss_domain_is_forest_root.patch b/SOURCES/0115-utils-add-sss_domain_is_forest_root.patch deleted file mode 100644 index f46b9e2..0000000 --- a/SOURCES/0115-utils-add-sss_domain_is_forest_root.patch +++ /dev/null @@ -1,48 +0,0 @@ -From dc8a5bc411403b3d216947e317dfce9dbc5f79d3 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 4 Apr 2017 14:35:47 +0200 -Subject: [PATCH 115/118] utils: add sss_domain_is_forest_root() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related to https://pagure.io/SSSD/sssd/issue/3361 - -Reviewed-by: Pavel Březina -(cherry picked from commit 712e5b2e4465812c00a8667c75813322373bc657) ---- - src/util/domain_info_utils.c | 5 +++++ - src/util/util.h | 1 + - 2 files changed, 6 insertions(+) - -diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c -index 2af7852f03f89b61f5b9fd8a244e98fb27b7e6a2..541058a16d585155b3b51511740f7db45281e2fd 100644 ---- a/src/util/domain_info_utils.c -+++ b/src/util/domain_info_utils.c -@@ -844,6 +844,11 @@ void sss_domain_set_state(struct sss_domain_info *dom, - "Domain %s is %s\n", dom->name, domain_state_str(dom)); - } - -+bool sss_domain_is_forest_root(struct sss_domain_info *dom) -+{ -+ return (dom->forest_root == dom); -+} -+ - bool is_email_from_domain(const char *email, struct sss_domain_info *dom) - { - const char *p; -diff --git a/src/util/util.h b/src/util/util.h -index 436550f5078cc173b8ed8cb58836d366f813146b..4ef13ced48addc19403402d7d880176da24ceec6 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -539,6 +539,7 @@ enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom); - void sss_domain_set_state(struct sss_domain_info *dom, - enum sss_domain_state state); - bool is_email_from_domain(const char *email, struct sss_domain_info *dom); -+bool sss_domain_is_forest_root(struct sss_domain_info *dom); - const char *sss_domain_type_str(struct sss_domain_info *dom); - - struct sss_domain_info* --- -2.9.3 - diff --git a/SOURCES/0116-ad-handle-forest-root-not-listed-in-ad_enabled_domai.patch b/SOURCES/0116-ad-handle-forest-root-not-listed-in-ad_enabled_domai.patch deleted file mode 100644 index 28f65d5..0000000 --- a/SOURCES/0116-ad-handle-forest-root-not-listed-in-ad_enabled_domai.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 5ca331e80520035d7de2680cd2803fa508d15287 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 3 Apr 2017 21:27:32 +0200 -Subject: [PATCH 116/118] ad: handle forest root not listed in - ad_enabled_domains -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Although users and groups from the forest root should be ignored SSSD -will still try to get information about the forest topology from a DC -from the forest root. So even if the forest root domain is disabled we -should makes sure it is usable for those searches. - -Resolves https://pagure.io/SSSD/sssd/issue/3361 - -Reviewed-by: Pavel Březina -(cherry picked from commit feeabf273aa7af580552366ce58655e6a482a0cd) ---- - src/providers/ad/ad_subdomains.c | 39 ++++++++++++++++++++++++++++++++++++--- - 1 file changed, 36 insertions(+), 3 deletions(-) - -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index bc659b2cb0a02723437d24d0021ec3592381e84c..ef166446e837c3f7cd824c1abf4b5cc587aec9da 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -433,6 +433,14 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx, - if (c >= num_subdomains) { - /* ok this subdomain does not exist anymore, let's clean up */ - sss_domain_set_state(dom, DOM_DISABLED); -+ -+ /* Just disable the forest root but do not remove sdap data */ -+ if (sss_domain_is_forest_root(dom)) { -+ DEBUG(SSSDBG_TRACE_ALL, -+ "Skipping removal of forest root sdap data.\n"); -+ continue; -+ } -+ - ret = sysdb_subdomain_delete(dom->sysdb, dom->name); - if (ret != EOK) { - goto done; -@@ -633,6 +641,7 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx) - const char *path; - errno_t ret; - bool canonicalize = false; -+ struct sss_domain_info *dom; - - path = dp_opt_get_string(subdoms_ctx->ad_id_ctx->ad_options->basic, - AD_KRB5_CONFD_PATH); -@@ -675,6 +684,17 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx) - return ret; - } - -+ /* Make sure disabled domains are not re-enabled accidentially */ -+ if (subdoms_ctx->ad_enabled_domains != NULL) { -+ for (dom = subdoms_ctx->be_ctx->domain->subdomains; dom; -+ dom = get_next_domain(dom, false)) { -+ if (!is_domain_enabled(dom->name, -+ subdoms_ctx->ad_enabled_domains)) { -+ sss_domain_set_state(dom, DOM_DISABLED); -+ } -+ } -+ } -+ - return EOK; - } - -@@ -898,7 +918,7 @@ static errno_t ad_get_slave_domain_recv(struct tevent_req *req) - static struct sss_domain_info * - ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs) - { -- struct sss_domain_info *root; -+ struct sss_domain_info *dom; - const char *name; - errno_t ret; - -@@ -909,9 +929,22 @@ ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs) - } - - /* With a subsequent run, the root should already be known */ -- root = find_domain_by_name(be_ctx->domain, name, false); -+ for (dom = be_ctx->domain; dom != NULL; -+ dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) { - -- return root; -+ if (strcasecmp(dom->name, name) == 0) { -+ /* The forest root is special, although it might be disabled for -+ * general lookups we still want to try to get the domains in the -+ * forest from a DC of the forest root */ -+ if (sss_domain_get_state(dom) == DOM_DISABLED -+ && !sss_domain_is_forest_root(dom)) { -+ return NULL; -+ } -+ return dom; -+ } -+ } -+ -+ return NULL; - } - - static struct ad_id_ctx * --- -2.9.3 - diff --git a/SOURCES/0117-SDAP-Fix-handling-of-search-bases.patch b/SOURCES/0117-SDAP-Fix-handling-of-search-bases.patch deleted file mode 100644 index 52c114d..0000000 --- a/SOURCES/0117-SDAP-Fix-handling-of-search-bases.patch +++ /dev/null @@ -1,168 +0,0 @@ -From ef6d1aaaa416bca3318e2961269620db7720a55b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 11 Apr 2017 19:56:37 +0200 -Subject: [PATCH 117/118] SDAP: Fix handling of search bases - -We were rewriting the sdap_domain's search bases for only the first -sdap_domain in the list, which does not work for subdomains. - -Also when search bases were already initialized in sdap_domain_subdom_add, -we should only rewrite them when they were explicitly set in sssd.conf. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3351 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 4c49edbd8df651b1737c59459637962c117212c6) ---- - src/providers/ad/ad_common.c | 39 +++++++++++++++++++++---------- - src/providers/ad/ad_common.h | 3 ++- - src/providers/ipa/ipa_subdomains_server.c | 2 +- - src/providers/ldap/ldap_options.c | 2 -- - 4 files changed, 30 insertions(+), 16 deletions(-) - -diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c -index f893b748a2ddcff1eab6e8d919d2aa950b825446..1a9d8dc0bfdf18e76e3c97a7ac7e297c4d24fd44 100644 ---- a/src/providers/ad/ad_common.c -+++ b/src/providers/ad/ad_common.c -@@ -29,7 +29,8 @@ struct ad_server_data { - bool gc; - }; - --errno_t ad_set_search_bases(struct sdap_options *id_opts); -+errno_t ad_set_search_bases(struct sdap_options *id_opts, -+ struct sdap_domain *sdap); - static errno_t ad_set_sdap_options(struct ad_options *ad_opts, - struct sdap_options *id_opts); - -@@ -1074,7 +1075,7 @@ ad_get_id_options(struct ad_options *ad_opts, - } - - /* Set up search bases if they were assigned explicitly */ -- ret = ad_set_search_bases(id_opts); -+ ret = ad_set_search_bases(id_opts, NULL); - if (ret != EOK) { - talloc_free(id_opts); - return ret; -@@ -1116,11 +1117,14 @@ ad_get_autofs_options(struct ad_options *ad_opts, - } - - errno_t --ad_set_search_bases(struct sdap_options *id_opts) -+ad_set_search_bases(struct sdap_options *id_opts, -+ struct sdap_domain *sdom) - { - errno_t ret; -- char *default_search_base; -+ char *default_search_base = NULL; - size_t o; -+ struct sdap_domain *sdap_dom; -+ bool has_default; - const int search_base_options[] = { SDAP_USER_SEARCH_BASE, - SDAP_GROUP_SEARCH_BASE, - SDAP_NETGROUP_SEARCH_BASE, -@@ -1132,10 +1136,21 @@ ad_set_search_bases(struct sdap_options *id_opts) - * been specifically overridden. - */ - -- default_search_base = -- dp_opt_get_string(id_opts->basic, SDAP_SEARCH_BASE); -+ if (sdom != NULL) { -+ sdap_dom = sdom; -+ } else { -+ /* If no specific sdom was given, use the first in the list. */ -+ sdap_dom = id_opts->sdom; -+ } - -- if (default_search_base) { -+ has_default = sdap_dom->search_bases != NULL; -+ -+ if (has_default == false) { -+ default_search_base = -+ dp_opt_get_string(id_opts->basic, SDAP_SEARCH_BASE); -+ } -+ -+ if (default_search_base && has_default == false) { - /* set search bases if they are not */ - for (o = 0; search_base_options[o] != -1; o++) { - if (NULL == dp_opt_get_string(id_opts->basic, -@@ -1162,31 +1177,31 @@ ad_set_search_bases(struct sdap_options *id_opts) - /* Default search */ - ret = sdap_parse_search_base(id_opts, id_opts->basic, - SDAP_SEARCH_BASE, -- &id_opts->sdom->search_bases); -+ &sdap_dom->search_bases); - if (ret != EOK && ret != ENOENT) goto done; - - /* User search */ - ret = sdap_parse_search_base(id_opts, id_opts->basic, - SDAP_USER_SEARCH_BASE, -- &id_opts->sdom->user_search_bases); -+ &sdap_dom->user_search_bases); - if (ret != EOK && ret != ENOENT) goto done; - - /* Group search base */ - ret = sdap_parse_search_base(id_opts, id_opts->basic, - SDAP_GROUP_SEARCH_BASE, -- &id_opts->sdom->group_search_bases); -+ &sdap_dom->group_search_bases); - if (ret != EOK && ret != ENOENT) goto done; - - /* Netgroup search */ - ret = sdap_parse_search_base(id_opts, id_opts->basic, - SDAP_NETGROUP_SEARCH_BASE, -- &id_opts->sdom->netgroup_search_bases); -+ &sdap_dom->netgroup_search_bases); - if (ret != EOK && ret != ENOENT) goto done; - - /* Service search */ - ret = sdap_parse_search_base(id_opts, id_opts->basic, - SDAP_SERVICE_SEARCH_BASE, -- &id_opts->sdom->service_search_bases); -+ &sdap_dom->service_search_bases); - if (ret != EOK && ret != ENOENT) goto done; - - ret = EOK; -diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h -index 2981550f6c390929501ec8942e861b16ea0a5cb0..ce33b37c75f45ae72adb268858cce34759b8b02f 100644 ---- a/src/providers/ad/ad_common.h -+++ b/src/providers/ad/ad_common.h -@@ -130,7 +130,8 @@ struct ad_options *ad_create_1way_trust_options(TALLOC_CTX *mem_ctx, - const char *keytab, - const char *sasl_authid); - --errno_t ad_set_search_bases(struct sdap_options *id_opts); -+errno_t ad_set_search_bases(struct sdap_options *id_opts, -+ struct sdap_domain *sdap); - - errno_t - ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, -diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c -index e8ee30392d84f84e30bcdaa3d2110ba130b1ad73..b02ea67af964a03e5466067cdb2b3ba4498120eb 100644 ---- a/src/providers/ipa/ipa_subdomains_server.c -+++ b/src/providers/ipa/ipa_subdomains_server.c -@@ -332,7 +332,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, - return EFAULT; - } - -- ret = ad_set_search_bases(ad_options->id); -+ ret = ad_set_search_bases(ad_options->id, sdom); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD search bases\n"); - talloc_free(ad_options); -diff --git a/src/providers/ldap/ldap_options.c b/src/providers/ldap/ldap_options.c -index 15a2609f07506b6dd442b180651a7e25461976c0..eb4e177b456253ebdfa06ee52886a5dffe0d3351 100644 ---- a/src/providers/ldap/ldap_options.c -+++ b/src/providers/ldap/ldap_options.c -@@ -581,8 +581,6 @@ errno_t sdap_parse_search_base(TALLOC_CTX *mem_ctx, - char *unparsed_base; - const char *old_filter = NULL; - -- *_search_bases = NULL; -- - switch (class) { - case SDAP_SEARCH_BASE: - class_name = "DEFAULT"; --- -2.9.3 - diff --git a/SOURCES/0118-overrides-add-certificates-to-mapped-attribute.patch b/SOURCES/0118-overrides-add-certificates-to-mapped-attribute.patch deleted file mode 100644 index 2bfa2c1..0000000 --- a/SOURCES/0118-overrides-add-certificates-to-mapped-attribute.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 4a3f3c675e360c888da7d23ab6ec4cca10876b08 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 27 Apr 2017 09:28:55 +0200 -Subject: [PATCH 118/118] overrides: add certificates to mapped attribute -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Certificates in overrides are explicitly used to map users to -certificates, so we add them to SYSDB_USER_MAPPED_CERT as well. - -Resolves https://pagure.io/SSSD/sssd/issue/3373 - -Reviewed-by: Pavel Březina -(cherry picked from commit 2e5fc89ef25434fab7febe2c52e97ef989b50d5b) ---- - src/db/sysdb_views.c | 41 +++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 41 insertions(+) - -diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c -index 20db9b06183d68b33bb19f498513d7f5cf84b1cf..3773dda77e16b35fa217be0aa7974da7e34c09f4 100644 ---- a/src/db/sysdb_views.c -+++ b/src/db/sysdb_views.c -@@ -777,6 +777,7 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain, - int ret; - TALLOC_CTX *tmp_ctx; - struct sysdb_attrs *attrs; -+ struct sysdb_attrs *mapped_attrs = NULL; - size_t c; - size_t d; - size_t num_values; -@@ -791,6 +792,7 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain, - SYSDB_USER_CERT, - NULL }; - bool override_attrs_found = false; -+ bool is_cert = false; - - if (override_attrs == NULL) { - /* nothing to do */ -@@ -846,6 +848,24 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain, - num_values = 1; - } - -+ is_cert = false; -+ if (strcmp(allowed_attrs[c], SYSDB_USER_CERT) == 0) { -+ /* Certificates in overrides are explicitly used to map -+ * users to certificates, so we add them to -+ * SYSDB_USER_MAPPED_CERT as well. */ -+ is_cert = true; -+ -+ if (mapped_attrs == NULL) { -+ mapped_attrs = sysdb_new_attrs(tmp_ctx); -+ if (mapped_attrs == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_new_attrs failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ } -+ - for (d = 0; d < num_values; d++) { - ret = sysdb_attrs_add_val(attrs, allowed_attrs[c], - &el->values[d]); -@@ -854,6 +874,18 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain, - "sysdb_attrs_add_val failed.\n"); - goto done; - } -+ -+ if (is_cert) { -+ ret = sysdb_attrs_add_val(mapped_attrs, -+ SYSDB_USER_MAPPED_CERT, -+ &el->values[d]); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_attrs_add_val failed.\n"); -+ goto done; -+ } -+ } -+ - DEBUG(SSSDBG_TRACE_ALL, - "Override [%s] with [%.*s] for [%s].\n", - allowed_attrs[c], (int) el->values[d].length, -@@ -878,6 +910,15 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain, - DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_entry_attr failed.\n"); - goto done; - } -+ -+ if (mapped_attrs != NULL) { -+ ret = sysdb_set_entry_attr(domain->sysdb, obj_dn, mapped_attrs, -+ SYSDB_MOD_ADD); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_set_entry_attr failed, ignored.\n"); -+ } -+ } - } - - ret = EOK; --- -2.9.3 - diff --git a/SOURCES/0119-AD-Make-ad_account_can_shortcut-reusable-by-SSSD-on-.patch b/SOURCES/0119-AD-Make-ad_account_can_shortcut-reusable-by-SSSD-on-.patch deleted file mode 100644 index c9874b9..0000000 --- a/SOURCES/0119-AD-Make-ad_account_can_shortcut-reusable-by-SSSD-on-.patch +++ /dev/null @@ -1,243 +0,0 @@ -From 54790675d0fd0627f7db8449ef97d59c0632006e Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 24 Apr 2017 10:13:44 +0200 -Subject: [PATCH 119/119] AD: Make ad_account_can_shortcut() reusable by SSSD - on an IPA server -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: - https://pagure.io/SSSD/sssd/issue/3318 - -The ad_account_can_shortcut() function is helpful to avoid unnecessary -searches when SSSD is configured with an Active Directory domain that -uses ID-mapping in the sense that if we find that an ID is outside our -range, we can just abort the search in this domain and carry on. - -This function was only used in the AD provider functions which are used -when SSSD is enrolled direcly with an AD server. This patch moves the -function to a codepath that is shared between directly enrolled SSSD and -SSSD running on an IPA server. - -Apart from moving the code, there are some minor changes to the function -signature, namely the domain is passed as as struct (previously the -domain name from the DP input was passed). - -Reviewed-by: Michal Židek -(cherry picked from commit dfe05f505dcfea16e7d66ca1a44206aa2570e861) ---- - src/providers/ad/ad_id.c | 162 ++++++++++++++++++++++++----------------------- - 1 file changed, 84 insertions(+), 78 deletions(-) - -diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c -index 8f26cb8744d2372c6180342c0d1bca025b16f52c..d1f6c444f5ddbcbbac6ff7f41fb6c8bf9ca976cb 100644 ---- a/src/providers/ad/ad_id.c -+++ b/src/providers/ad/ad_id.c -@@ -50,6 +50,77 @@ disable_gc(struct ad_options *ad_options) - } - } - -+static bool ad_account_can_shortcut(struct sdap_idmap_ctx *idmap_ctx, -+ struct sss_domain_info *domain, -+ int filter_type, -+ const char *filter_value) -+{ -+ struct sss_domain_info *dom_head = NULL; -+ struct sss_domain_info *sid_dom = NULL; -+ enum idmap_error_code err; -+ char *sid = NULL; -+ const char *csid = NULL; -+ uint32_t id; -+ bool shortcut = false; -+ errno_t ret; -+ -+ if (!sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, domain->name, -+ domain->domain_id)) { -+ goto done; -+ } -+ -+ switch (filter_type) { -+ case BE_FILTER_IDNUM: -+ /* convert value to ID */ -+ errno = 0; -+ id = strtouint32(filter_value, NULL, 10); -+ if (errno != 0) { -+ ret = errno; -+ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to convert filter value to " -+ "number [%d]: %s\n", ret, strerror(ret)); -+ goto done; -+ } -+ -+ /* convert the ID to its SID equivalent */ -+ err = sss_idmap_unix_to_sid(idmap_ctx->map, id, &sid); -+ if (err != IDMAP_SUCCESS) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "Mapping ID [%s] to SID failed: " -+ "[%s]\n", filter_value, idmap_error_string(err)); -+ goto done; -+ } -+ /* fall through */ -+ SSS_ATTRIBUTE_FALLTHROUGH; -+ case BE_FILTER_SECID: -+ csid = sid == NULL ? filter_value : sid; -+ -+ dom_head = get_domains_head(domain); -+ if (dom_head == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find domain head\n"); -+ goto done; -+ } -+ -+ sid_dom = find_domain_by_sid(dom_head, csid); -+ if (sid_dom == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Invalid domain for SID:%s\n", csid); -+ goto done; -+ } -+ -+ if (strcasecmp(sid_dom->name, domain->name) != 0) { -+ shortcut = true; -+ } -+ break; -+ default: -+ break; -+ } -+ -+done: -+ if (sid != NULL) { -+ sss_idmap_free_sid(idmap_ctx->map, sid); -+ } -+ -+ return shortcut; -+} -+ - struct ad_handle_acct_info_state { - struct dp_id_data *ar; - struct sdap_id_ctx *ctx; -@@ -78,6 +149,7 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx, - struct ad_handle_acct_info_state *state; - struct be_ctx *be_ctx = ctx->be; - errno_t ret; -+ bool shortcut; - - req = tevent_req_create(mem_ctx, &state, struct ad_handle_acct_info_state); - if (req == NULL) { -@@ -90,6 +162,18 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx, - state->ad_options = ad_options; - state->cindex = 0; - -+ /* Try to shortcut if this is ID or SID search and it belongs to -+ * other domain range than is in ar->domain. */ -+ shortcut = ad_account_can_shortcut(ctx->opts->idmap_ctx, -+ sdom->dom, -+ ar->filter_type, -+ ar->filter_value); -+ if (shortcut) { -+ DEBUG(SSSDBG_TRACE_FUNC, "This ID is from different domain\n"); -+ ret = EOK; -+ goto immediate; -+ } -+ - if (sss_domain_get_state(sdom->dom) == DOM_INACTIVE) { - ret = ERR_SUBDOM_INACTIVE; - goto immediate; -@@ -297,72 +381,6 @@ get_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx, - return clist; - } - --static bool ad_account_can_shortcut(struct be_ctx *be_ctx, -- struct sdap_idmap_ctx *idmap_ctx, -- int filter_type, -- const char *filter_value, -- const char *filter_domain) --{ -- struct sss_domain_info *domain = be_ctx->domain; -- struct sss_domain_info *req_dom = NULL; -- enum idmap_error_code err; -- char *sid = NULL; -- const char *csid = NULL; -- uint32_t id; -- bool shortcut = false; -- errno_t ret; -- -- if (!sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, domain->name, -- domain->domain_id)) { -- goto done; -- } -- -- switch (filter_type) { -- case BE_FILTER_IDNUM: -- /* convert value to ID */ -- errno = 0; -- id = strtouint32(filter_value, NULL, 10); -- if (errno != 0) { -- ret = errno; -- DEBUG(SSSDBG_MINOR_FAILURE, "Unable to convert filter value to " -- "number [%d]: %s\n", ret, strerror(ret)); -- goto done; -- } -- -- /* convert the ID to its SID equivalent */ -- err = sss_idmap_unix_to_sid(idmap_ctx->map, id, &sid); -- if (err != IDMAP_SUCCESS) { -- DEBUG(SSSDBG_MINOR_FAILURE, "Mapping ID [%s] to SID failed: " -- "[%s]\n", filter_value, idmap_error_string(err)); -- goto done; -- } -- /* fall through */ -- SSS_ATTRIBUTE_FALLTHROUGH; -- case BE_FILTER_SECID: -- csid = sid == NULL ? filter_value : sid; -- -- req_dom = find_domain_by_sid(domain, csid); -- if (req_dom == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "Invalid domain for SID:%s\n", csid); -- goto done; -- } -- -- if (strcasecmp(req_dom->name, filter_domain) != 0) { -- shortcut = true; -- } -- break; -- default: -- break; -- } -- --done: -- if (sid != NULL) { -- sss_idmap_free_sid(idmap_ctx->map, sid); -- } -- -- return shortcut; --} -- - struct ad_account_info_handler_state { - struct sss_domain_info *domain; - struct dp_reply_std reply; -@@ -384,7 +402,6 @@ ad_account_info_handler_send(TALLOC_CTX *mem_ctx, - struct tevent_req *subreq; - struct tevent_req *req; - struct be_ctx *be_ctx; -- bool shortcut; - errno_t ret; - - sdap_id_ctx = id_ctx->sdap_id_ctx; -@@ -403,17 +420,6 @@ ad_account_info_handler_send(TALLOC_CTX *mem_ctx, - goto immediately; - } - -- /* Try to shortcut if this is ID or SID search and it belongs to -- * other domain range than is in ar->domain. */ -- shortcut = ad_account_can_shortcut(be_ctx, sdap_id_ctx->opts->idmap_ctx, -- data->filter_type, data->filter_value, -- data->domain); -- if (shortcut) { -- DEBUG(SSSDBG_TRACE_FUNC, "This ID is from different domain\n"); -- ret = EOK; -- goto immediately; -- } -- - domain = be_ctx->domain; - if (strcasecmp(data->domain, be_ctx->domain->name) != 0) { - /* Subdomain request, verify subdomain. */ --- -2.9.3 - diff --git a/SOURCES/0120-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch b/SOURCES/0120-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch deleted file mode 100644 index abe44ec..0000000 --- a/SOURCES/0120-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 428909abd59f1eb8bb02b6627f37f61af3de2691 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Mon, 1 May 2017 14:49:50 +0200 -Subject: [PATCH 120/120] LDAP/AD: Do not fail in case - rfc2307bis_nested_groups_recv() returns ENOENT -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Commit 25699846 introduced a regression seen when an initgroup lookup is -done and there's no nested groups involved. - -In this scenario the whole lookup fails due to an ENOENT returned by -rfc2307bis_nested_groups_recv(), which leads to the user removal from -sysdb causing some authentication issues. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3331 - -Signed-off-by: Fabiano Fidêncio -Reviewed-by: Sumit Bose ---- - src/providers/ldap/sdap_async_initgroups_ad.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c -index f75b9211e2a06616dbf9b948e60b023a818c7e19..2831be9776293260aeec0e2ff85160f1938bdb32 100644 ---- a/src/providers/ldap/sdap_async_initgroups_ad.c -+++ b/src/providers/ldap/sdap_async_initgroups_ad.c -@@ -1746,7 +1746,13 @@ static void sdap_ad_get_domain_local_groups_done(struct tevent_req *subreq) - - ret = rfc2307bis_nested_groups_recv(subreq); - talloc_zfree(subreq); -- if (ret != EOK) { -+ if (ret == ENOENT) { -+ /* In case of ENOENT we can just proceed without making -+ * sdap_get_initgr_user() fail because there's no nested -+ * groups for this user/group. */ -+ ret = EOK; -+ goto done; -+ } else if (ret != EOK) { - tevent_req_error(req, ret); - return; - } --- -2.9.3 - diff --git a/SOURCES/0121-PAM-check-matching-certificates-from-all-domains.patch b/SOURCES/0121-PAM-check-matching-certificates-from-all-domains.patch deleted file mode 100644 index 55c7c61..0000000 --- a/SOURCES/0121-PAM-check-matching-certificates-from-all-domains.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 52514960f5b0609cd9f31f3c4455b61fbe4c04c5 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 26 Apr 2017 17:16:19 +0200 -Subject: [PATCH 121/121] PAM: check matching certificates from all domains - -Although the cache_req lookup found matching in multiple domains only -the results from the first domain were used. With this patch the results -from all domains are checked. - -Resolves https://pagure.io/SSSD/sssd/issue/3385 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 92d8b072f8c521e1b4effe109b5caedabd36ed6f) ---- - src/responder/pam/pamsrv_cmd.c | 69 ++++++++++++++++++++++++++++++++++++++---- - 1 file changed, 63 insertions(+), 6 deletions(-) - -diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c -index f2b3c74b483e527932dda42279d14a9ac184b475..10a178f839ec011c09a6da4575efbb026f3f7700 100644 ---- a/src/responder/pam/pamsrv_cmd.c -+++ b/src/responder/pam/pamsrv_cmd.c -@@ -1352,15 +1352,71 @@ done: - pam_check_user_done(preq, ret); - } - -+static errno_t get_results_from_all_domains(TALLOC_CTX *mem_ctx, -+ struct cache_req_result **results, -+ struct ldb_result **ldb_results) -+{ -+ int ret; -+ size_t count = 0; -+ size_t c; -+ size_t d; -+ size_t r = 0; -+ struct ldb_result *res; -+ -+ for (d = 0; results != NULL && results[d] != NULL; d++) { -+ count += results[d]->count; -+ } -+ -+ res = talloc_zero(mem_ctx, struct ldb_result); -+ if (res == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); -+ return ENOMEM; -+ } -+ -+ if (count == 0) { -+ *ldb_results = res; -+ return EOK; -+ } -+ -+ res->msgs = talloc_zero_array(res, struct ldb_message *, count); -+ if (res->msgs == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n"); -+ return ENOMEM; -+ } -+ res->count = count; -+ -+ for (d = 0; results != NULL && results[d] != NULL; d++) { -+ for (c = 0; c < results[d]->count; c++) { -+ if (r >= count) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "More results found then counted before.\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ res->msgs[r++] = talloc_steal(res->msgs, results[d]->msgs[c]); -+ } -+ } -+ -+ *ldb_results = res; -+ ret = EOK; -+ -+done: -+ if (ret != EOK) { -+ talloc_free(res); -+ } -+ -+ return ret; -+} -+ - static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) - { - int ret; -- struct cache_req_result *result; -+ struct cache_req_result **results; - struct pam_auth_req *preq = tevent_req_callback_data(req, - struct pam_auth_req); - const char *cert_user; - -- ret = cache_req_user_by_cert_recv(preq, req, &result); -+ ret = cache_req_recv(preq, req, &results); - talloc_zfree(req); - if (ret != EOK && ret != ENOENT) { - DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert request failed.\n"); -@@ -1368,12 +1424,13 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) - } - - if (ret == EOK) { -- if (preq->domain == NULL) { -- preq->domain = result->domain; -+ ret = get_results_from_all_domains(preq, results, -+ &preq->cert_user_objs); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "get_results_from_all_domains failed.\n"); -+ goto done; - } - -- preq->cert_user_objs = talloc_steal(preq, result->ldb_result); -- - if (preq->pd->logon_name == NULL) { - if (preq->pd->cmd != SSS_PAM_PREAUTH) { - DEBUG(SSSDBG_CRIT_FAILURE, --- -2.9.3 - diff --git a/SOURCES/0122-DP-Reduce-Data-Provider-log-level-noise.patch b/SOURCES/0122-DP-Reduce-Data-Provider-log-level-noise.patch deleted file mode 100644 index b7dfbd3..0000000 --- a/SOURCES/0122-DP-Reduce-Data-Provider-log-level-noise.patch +++ /dev/null @@ -1,80 +0,0 @@ -From b818bb3f27ce672df0a6cadf2fd90716d2a576dc Mon Sep 17 00:00:00 2001 -From: Justin Stephenson -Date: Wed, 26 Apr 2017 15:45:33 -0400 -Subject: [PATCH 122/127] DP: Reduce Data Provider log level noise -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Certain operations are not supported with certain providers -causing informational Data Provider log messages to be logged as -errors or failures. This patch lowers the log level to reduce overall -log noise and ensure only critical log messages are logged when -a low debug_level value is used. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3287 -https://pagure.io/SSSD/sssd/issue/3278 - -Reviewed-by: Fabiano Fidêncio -Reviewed-by: Pavel Březina -(cherry picked from commit e98d085b529e0ae5e07a717ce3b30f3943be0ee0) ---- - src/providers/data_provider/dp_methods.c | 2 +- - src/providers/data_provider/dp_targets.c | 2 +- - src/responder/common/responder_dp.c | 13 +++++++++++-- - 3 files changed, 13 insertions(+), 4 deletions(-) - -diff --git a/src/providers/data_provider/dp_methods.c b/src/providers/data_provider/dp_methods.c -index 498676d1bec2da300ca4b33f7110debcbf0aac00..9e49c5f5d65b869b3699fdc682a535e0111b6fd4 100644 ---- a/src/providers/data_provider/dp_methods.c -+++ b/src/providers/data_provider/dp_methods.c -@@ -109,7 +109,7 @@ errno_t dp_find_method(struct data_provider *provider, - } - - if (!dp_target_initialized(provider->targets, target)) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Target [%s] is not initialized\n", -+ DEBUG(SSSDBG_CONF_SETTINGS, "Target [%s] is not initialized\n", - dp_target_to_string(target)); - return ERR_MISSING_DP_TARGET; - } -diff --git a/src/providers/data_provider/dp_targets.c b/src/providers/data_provider/dp_targets.c -index 26d20a8ef79b80d56df76d7a73ec8e63d001ecbc..e2a45bbac969ca7b9b13729f26b8cded8ab7eebc 100644 ---- a/src/providers/data_provider/dp_targets.c -+++ b/src/providers/data_provider/dp_targets.c -@@ -284,7 +284,7 @@ static errno_t dp_target_init(struct be_ctx *be_ctx, - if (!target->explicitly_configured && (ret == ELIBBAD || ret == ENOTSUP)) { - /* Target not found but it wasn't explicitly - * configured so we shall just continue. */ -- DEBUG(SSSDBG_CRIT_FAILURE, "Target [%s] is not supported by " -+ DEBUG(SSSDBG_CONF_SETTINGS, "Target [%s] is not supported by " - "module [%s].\n", target->name, target->module_name); - ret = EOK; - goto done; -diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c -index 080f70fd5945ffd234e0ef226d8139df071c4752..a75a611960801f5f5bdc95f00aea9ab921e8e293 100644 ---- a/src/responder/common/responder_dp.c -+++ b/src/responder/common/responder_dp.c -@@ -218,8 +218,17 @@ static int sss_dp_get_reply(DBusPendingCall *pending, - err = ETIME; - goto done; - } -- DEBUG(SSSDBG_FATAL_FAILURE,"The Data Provider returned an error [%s]\n", -- dbus_message_get_error_name(reply)); -+ -+ if (strcmp(dbus_message_get_error_name(reply), -+ SBUS_ERROR_DP_NOTSUP) == 0) { -+ DEBUG(SSSDBG_CONF_SETTINGS, -+ "Data Provider does not support this operation.\n"); -+ } else { -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "The Data Provider returned an error [%s]\n", -+ dbus_message_get_error_name(reply)); -+ } -+ - /* Falling through to default intentionally*/ - SSS_ATTRIBUTE_FALLTHROUGH; - default: --- -2.9.3 - diff --git a/SOURCES/0123-NSS-Move-output-name-formatting-to-utils.patch b/SOURCES/0123-NSS-Move-output-name-formatting-to-utils.patch deleted file mode 100644 index abc8b99..0000000 --- a/SOURCES/0123-NSS-Move-output-name-formatting-to-utils.patch +++ /dev/null @@ -1,249 +0,0 @@ -From 43b07b3fe8794a6e19db5cd2e9036e3d4d6c43ad Mon Sep 17 00:00:00 2001 -From: Nikolai Kondrashov -Date: Wed, 22 Mar 2017 14:32:35 +0200 -Subject: [PATCH 123/127] NSS: Move output name formatting to utils -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Move NSS nss_get_name_from_msg and the core of sized_output_name to the -utils to make them available to provider and other responders. - -Reviewed-by: Pavel Březina -(cherry picked from commit a012a71f21bf1a4687e58085f19c18cc5b2bbadd) ---- - src/responder/common/responder_common.c | 27 ++++--------- - src/responder/nss/nss_protocol_grent.c | 2 +- - src/responder/nss/nss_protocol_pwent.c | 2 +- - src/responder/nss/nss_protocol_sid.c | 2 +- - src/responder/nss/nss_utils.c | 27 ------------- - src/util/usertools.c | 67 +++++++++++++++++++++++++++++++++ - src/util/util.h | 9 +++++ - 7 files changed, 87 insertions(+), 49 deletions(-) - -diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c -index 7496d293fddb3e947d59a4f2aaeb2c83234dfcc7..9d4889be652c6d6fb974b59001a9ac77b496e9ab 100644 ---- a/src/responder/common/responder_common.c -+++ b/src/responder/common/responder_common.c -@@ -1685,7 +1685,7 @@ int sized_output_name(TALLOC_CTX *mem_ctx, - { - TALLOC_CTX *tmp_ctx = NULL; - errno_t ret; -- char *username; -+ char *name_str; - struct sized_string *name; - - tmp_ctx = talloc_new(NULL); -@@ -1693,30 +1693,19 @@ int sized_output_name(TALLOC_CTX *mem_ctx, - return ENOMEM; - } - -- username = sss_output_name(tmp_ctx, orig_name, name_dom->case_preserve, -- rctx->override_space); -- if (username == NULL) { -- ret = EIO; -- goto done; -- } -- -- if (name_dom->fqnames) { -- username = sss_tc_fqname(tmp_ctx, name_dom->names, name_dom, username); -- if (username == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "sss_replace_space failed\n"); -- ret = EIO; -- goto done; -- } -- } -- - name = talloc_zero(tmp_ctx, struct sized_string); - if (name == NULL) { - ret = ENOMEM; - goto done; - } - -- to_sized_string(name, username); -- name->str = talloc_steal(name, username); -+ ret = sss_output_fqname(mem_ctx, name_dom, orig_name, -+ rctx->override_space, &name_str); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ to_sized_string(name, name_str); - *_name = talloc_steal(mem_ctx, name); - ret = EOK; - done: -diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c -index fae1d47d7b217beafba75740e2e6d9cb8cdbc1d0..947463df93e188729959737efa4ac4f44a8459c4 100644 ---- a/src/responder/nss/nss_protocol_grent.c -+++ b/src/responder/nss/nss_protocol_grent.c -@@ -41,7 +41,7 @@ nss_get_grent(TALLOC_CTX *mem_ctx, - } - - /* Get fields. */ -- name = nss_get_name_from_msg(domain, msg); -+ name = sss_get_name_from_msg(domain, msg); - gid = sss_view_ldb_msg_find_attr_as_uint64(domain, msg, SYSDB_GIDNUM, 0); - - if (name == NULL || gid == 0) { -diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c -index edda9d3c87389898435a34fe7927868bc1cd9ac5..cb643f29e2d5f0a0c55c51afd9def73813061aa7 100644 ---- a/src/responder/nss/nss_protocol_pwent.c -+++ b/src/responder/nss/nss_protocol_pwent.c -@@ -225,7 +225,7 @@ nss_get_pwent(TALLOC_CTX *mem_ctx, - - /* Get fields. */ - upn = ldb_msg_find_attr_as_string(msg, SYSDB_UPN, NULL); -- name = nss_get_name_from_msg(domain, msg); -+ name = sss_get_name_from_msg(domain, msg); - gid = nss_get_gid(domain, msg); - uid = sss_view_ldb_msg_find_attr_as_uint64(domain, msg, SYSDB_UIDNUM, 0); - -diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c -index a6a4e27d039c67ef98f6d5900d5e3fcadb3ee717..d4b7ee22d7c68a9e6f7c668f7268cdc5f36768b3 100644 ---- a/src/responder/nss/nss_protocol_sid.c -+++ b/src/responder/nss/nss_protocol_sid.c -@@ -532,7 +532,7 @@ nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, - return ret; - } - -- tmp_str = nss_get_name_from_msg(result->domain, result->msgs[c]); -+ tmp_str = sss_get_name_from_msg(result->domain, result->msgs[c]); - if (tmp_str == NULL) { - return EINVAL; - } -diff --git a/src/responder/nss/nss_utils.c b/src/responder/nss/nss_utils.c -index 2cd9c33b42f7e018ea89d2df206637f35646489e..b4950e5a6eaec6a4511f7251dcf2e623c0177230 100644 ---- a/src/responder/nss/nss_utils.c -+++ b/src/responder/nss/nss_utils.c -@@ -27,33 +27,6 @@ - #include "responder/nss/nss_private.h" - - const char * --nss_get_name_from_msg(struct sss_domain_info *domain, -- struct ldb_message *msg) --{ -- const char *name; -- -- /* If domain has a view associated we return overridden name -- * if possible. */ -- if (DOM_HAS_VIEWS(domain)) { -- name = ldb_msg_find_attr_as_string(msg, OVERRIDE_PREFIX SYSDB_NAME, -- NULL); -- if (name != NULL) { -- return name; -- } -- } -- -- /* Otherwise we try to return name override from -- * Default Truest View for trusted users. */ -- name = ldb_msg_find_attr_as_string(msg, SYSDB_DEFAULT_OVERRIDE_NAME, NULL); -- if (name != NULL) { -- return name; -- } -- -- /* If no override is found we return the original name. */ -- return ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); --} -- --const char * - nss_get_pwfield(struct nss_ctx *nctx, - struct sss_domain_info *dom) - { -diff --git a/src/util/usertools.c b/src/util/usertools.c -index 7b87c567a6c2dc7e9c267407434b2a7a9edeaa00..5dfe6d7765b8032c7447de75e10c6c2a1d4c49ec 100644 ---- a/src/util/usertools.c -+++ b/src/util/usertools.c -@@ -816,3 +816,70 @@ done: - talloc_free(tmp_ctx); - return outname; - } -+ -+const char * -+sss_get_name_from_msg(struct sss_domain_info *domain, -+ struct ldb_message *msg) -+{ -+ const char *name; -+ -+ /* If domain has a view associated we return overridden name -+ * if possible. */ -+ if (DOM_HAS_VIEWS(domain)) { -+ name = ldb_msg_find_attr_as_string(msg, OVERRIDE_PREFIX SYSDB_NAME, -+ NULL); -+ if (name != NULL) { -+ return name; -+ } -+ } -+ -+ /* Otherwise we try to return name override from -+ * Default Truest View for trusted users. */ -+ name = ldb_msg_find_attr_as_string(msg, SYSDB_DEFAULT_OVERRIDE_NAME, NULL); -+ if (name != NULL) { -+ return name; -+ } -+ -+ /* If no override is found we return the original name. */ -+ return ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); -+} -+ -+int sss_output_fqname(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domain, -+ const char *name, -+ char override_space, -+ char **_output_name) -+{ -+ TALLOC_CTX *tmp_ctx = NULL; -+ errno_t ret; -+ char *output_name; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ output_name = sss_output_name(tmp_ctx, name, domain->case_preserve, -+ override_space); -+ if (output_name == NULL) { -+ ret = EIO; -+ goto done; -+ } -+ -+ if (domain->fqnames) { -+ output_name = sss_tc_fqname(tmp_ctx, domain->names, -+ domain, output_name); -+ if (output_name == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "sss_tc_fqname failed\n"); -+ ret = EIO; -+ goto done; -+ } -+ } -+ -+ *_output_name = talloc_steal(mem_ctx, output_name); -+ ret = EOK; -+done: -+ talloc_zfree(tmp_ctx); -+ return ret; -+} -diff --git a/src/util/util.h b/src/util/util.h -index 4ef13ced48addc19403402d7d880176da24ceec6..5ba4c36ca88e325c20a3b1ecc8080a11ca276dcf 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -304,6 +304,15 @@ char *sss_output_name(TALLOC_CTX *mem_ctx, - bool case_sensitive, - const char replace_space); - -+int sss_output_fqname(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domain, -+ const char *name, -+ char override_space, -+ char **_output_name); -+ -+const char *sss_get_name_from_msg(struct sss_domain_info *domain, -+ struct ldb_message *msg); -+ - /* from backup-file.c */ - int backup_file(const char *src, int dbglvl); - --- -2.9.3 - diff --git a/SOURCES/0124-CACHE_REQ-Add-a-new-cache_req_ncache_filter_fn-plugi.patch b/SOURCES/0124-CACHE_REQ-Add-a-new-cache_req_ncache_filter_fn-plugi.patch deleted file mode 100644 index fd0780e..0000000 --- a/SOURCES/0124-CACHE_REQ-Add-a-new-cache_req_ncache_filter_fn-plugi.patch +++ /dev/null @@ -1,322 +0,0 @@ -From da437bb72fc6ab072fc9b3e6d6809bac323de1e2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Tue, 25 Apr 2017 14:14:05 +0200 -Subject: [PATCH 124/127] CACHE_REQ: Add a new cache_req_ncache_filter_fn() - plugin function -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This function will be responsible for filtering out all the results that -we have that are also present in the negative cache. - -This is useful mainly for plugins which don't use name as an input token -but can still be affected by filter_{users,groups} options. - -For now this new function is not being used anywhere. - -Related: -https://pagure.io/SSSD/sssd/issue/3362 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Pavel Březina -(cherry picked from commit f24ee5cca4cd43e7edf26fec453fbd99392bbe4b) ---- - src/responder/common/cache_req/cache_req_plugin.h | 13 +++++++++++++ - .../common/cache_req/plugins/cache_req_enum_groups.c | 1 + - src/responder/common/cache_req/plugins/cache_req_enum_svc.c | 1 + - .../common/cache_req/plugins/cache_req_enum_users.c | 1 + - .../common/cache_req/plugins/cache_req_group_by_filter.c | 1 + - .../common/cache_req/plugins/cache_req_group_by_id.c | 1 + - .../common/cache_req/plugins/cache_req_group_by_name.c | 1 + - .../common/cache_req/plugins/cache_req_host_by_name.c | 1 + - .../common/cache_req/plugins/cache_req_initgroups_by_name.c | 1 + - .../common/cache_req/plugins/cache_req_initgroups_by_upn.c | 1 + - .../common/cache_req/plugins/cache_req_netgroup_by_name.c | 1 + - .../common/cache_req/plugins/cache_req_object_by_id.c | 1 + - .../common/cache_req/plugins/cache_req_object_by_name.c | 1 + - .../common/cache_req/plugins/cache_req_object_by_sid.c | 1 + - .../common/cache_req/plugins/cache_req_svc_by_name.c | 1 + - .../common/cache_req/plugins/cache_req_svc_by_port.c | 1 + - .../common/cache_req/plugins/cache_req_user_by_cert.c | 1 + - .../common/cache_req/plugins/cache_req_user_by_filter.c | 1 + - .../common/cache_req/plugins/cache_req_user_by_id.c | 1 + - .../common/cache_req/plugins/cache_req_user_by_name.c | 1 + - .../common/cache_req/plugins/cache_req_user_by_upn.c | 1 + - 21 files changed, 33 insertions(+) - -diff --git a/src/responder/common/cache_req/cache_req_plugin.h b/src/responder/common/cache_req/cache_req_plugin.h -index e0b619528f6aa31a10a5b48c3c5acc96de90caa1..8117325506b2951c3966fa50506ed0d55273ee81 100644 ---- a/src/responder/common/cache_req/cache_req_plugin.h -+++ b/src/responder/common/cache_req/cache_req_plugin.h -@@ -93,6 +93,18 @@ typedef errno_t - struct cache_req_data *data); - - /** -+ * Filter the result through the negative cache. -+ * -+ * This is useful for plugins which don't use name as an input -+ * token but can be affected by filter_users and filter_groups -+ * options. -+ */ -+typedef errno_t -+(*cache_req_ncache_filter_fn)(struct sss_nc_ctx *ncache, -+ struct sss_domain_info *domain, -+ const char *name); -+ -+/** - * Add an object into global negative cache. - * - * @return EOK If everything went fine. -@@ -207,6 +219,7 @@ struct cache_req_plugin { - cache_req_global_ncache_add_fn global_ncache_add_fn; - cache_req_ncache_check_fn ncache_check_fn; - cache_req_ncache_add_fn ncache_add_fn; -+ cache_req_ncache_filter_fn ncache_filter_fn; - cache_req_lookup_fn lookup_fn; - cache_req_dp_send_fn dp_send_fn; - cache_req_dp_recv_fn dp_recv_fn; -diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c -index 49ce3508e678862e4389657187b9659ce90fbd1c..11ce9e90ff28f77078b025a44593a44be8f1f5c5 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c -+++ b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c -@@ -75,6 +75,7 @@ const struct cache_req_plugin cache_req_enum_groups = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = NULL, - .ncache_add_fn = NULL, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_enum_groups_lookup, - .dp_send_fn = cache_req_enum_groups_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c -index 499b994738d62707b4e86d5a8383e3e2b82e8c57..72b2f1a7d2d2e02ce1a995098d1f26003444bddb 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c -+++ b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c -@@ -76,6 +76,7 @@ const struct cache_req_plugin cache_req_enum_svc = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = NULL, - .ncache_add_fn = NULL, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_enum_svc_lookup, - .dp_send_fn = cache_req_enum_svc_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_users.c b/src/responder/common/cache_req/plugins/cache_req_enum_users.c -index b635354be6e9d2e2e2af1a6f867ac68e6cf7f085..e0647a0102d9568abdcebfbf0fb99fc2624d5565 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_enum_users.c -+++ b/src/responder/common/cache_req/plugins/cache_req_enum_users.c -@@ -75,6 +75,7 @@ const struct cache_req_plugin cache_req_enum_users = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = NULL, - .ncache_add_fn = NULL, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_enum_users_lookup, - .dp_send_fn = cache_req_enum_users_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c -index 4377a476c36e5e03c8533bc62335b84fa1cee3ff..aa89953b88313605041cce599999fc5bbc741525 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c -+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c -@@ -131,6 +131,7 @@ const struct cache_req_plugin cache_req_group_by_filter = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = NULL, - .ncache_add_fn = NULL, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_group_by_filter_lookup, - .dp_send_fn = cache_req_group_by_filter_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -index ad5b7d890a42f29b586ab8e0943fef3dfab1162d..5613bf67c6acd1b2ace00cf75221462f45ef6743 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -@@ -144,6 +144,7 @@ const struct cache_req_plugin cache_req_group_by_id = { - .global_ncache_add_fn = cache_req_group_by_id_global_ncache_add, - .ncache_check_fn = cache_req_group_by_id_ncache_check, - .ncache_add_fn = NULL, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_group_by_id_lookup, - .dp_send_fn = cache_req_group_by_id_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c -index de1e8f9442273acf386a2278b06f28ee63a7e3c6..7706051818590af77da75d3e4c7f671c89170f82 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c -@@ -194,6 +194,7 @@ const struct cache_req_plugin cache_req_group_by_name = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = cache_req_group_by_name_ncache_check, - .ncache_add_fn = cache_req_group_by_name_ncache_add, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_group_by_name_lookup, - .dp_send_fn = cache_req_group_by_name_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c -index 1171cd63fac5cc1d36b31bf8a069f059705cae90..9cb32f6b18327873ba4b96fa177e8295be461db0 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c -@@ -92,6 +92,7 @@ const struct cache_req_plugin cache_req_host_by_name = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = NULL, - .ncache_add_fn = NULL, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_host_by_name_lookup, - .dp_send_fn = cache_req_host_by_name_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c -index f100aefe5c92279cde7e3209c7f48f5e2b35f135..75ac44e1ad36238f01342eced9188d07daa50720 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c -@@ -209,6 +209,7 @@ const struct cache_req_plugin cache_req_initgroups_by_name = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = cache_req_initgroups_by_name_ncache_check, - .ncache_add_fn = cache_req_initgroups_by_name_ncache_add, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_initgroups_by_name_lookup, - .dp_send_fn = cache_req_initgroups_by_name_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c -index 266ec7b8a28d496d9603bd9b6cdfef268ffa8559..b6fb43ee02d2f041fb3d992b375ae65a02db8b03 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c -+++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c -@@ -120,6 +120,7 @@ const struct cache_req_plugin cache_req_initgroups_by_upn = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = cache_req_initgroups_by_upn_ncache_check, - .ncache_add_fn = cache_req_initgroups_by_upn_ncache_add, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_initgroups_by_upn_lookup, - .dp_send_fn = cache_req_initgroups_by_upn_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -index ab3e553d3ecb8ae09094dcfc938ed0ac01925327..4d8bb18579a286042b00528190dadd52fdd7c75c 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -@@ -128,6 +128,7 @@ const struct cache_req_plugin cache_req_netgroup_by_name = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = cache_req_netgroup_by_name_ncache_check, - .ncache_add_fn = cache_req_netgroup_by_name_ncache_add, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_netgroup_by_name_lookup, - .dp_send_fn = cache_req_netgroup_by_name_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -index 9557bd15270b2eb1a0671f9ef91033efac29c3ac..ff3d0e67862be365c56ab24396b4982e8addded0 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -@@ -111,6 +111,7 @@ const struct cache_req_plugin cache_req_object_by_id = { - .global_ncache_add_fn = cache_req_object_by_id_global_ncache_add, - .ncache_check_fn = cache_req_object_by_id_ncache_check, - .ncache_add_fn = NULL, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_object_by_id_lookup, - .dp_send_fn = cache_req_object_by_id_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c -index e236d1fa4aadcd87b192d34ebaf5f9ad8908b6c2..854d0b83c420ebebcb5e0e079c707081fa313632 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c -@@ -204,6 +204,7 @@ const struct cache_req_plugin cache_req_object_by_name = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = cache_req_object_by_name_ncache_check, - .ncache_add_fn = cache_req_object_by_name_ncache_add, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_object_by_name_lookup, - .dp_send_fn = cache_req_object_by_name_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c -index dfec79da07d669165205a767cab22c2254686134..039a79df7bb1ab213ce4334835e9fc18e6d0faac 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c -+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c -@@ -120,6 +120,7 @@ const struct cache_req_plugin cache_req_object_by_sid = { - .global_ncache_add_fn = cache_req_object_by_sid_global_ncache_add, - .ncache_check_fn = cache_req_object_by_sid_ncache_check, - .ncache_add_fn = NULL, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_object_by_sid_lookup, - .dp_send_fn = cache_req_object_by_sid_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c -index b2bfb26ffed1a60ed8389fa89b0e728c8c6cf76c..4c32d9977cc06e43eed3a90e7dcf107e91efefb5 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c -@@ -152,6 +152,7 @@ const struct cache_req_plugin cache_req_svc_by_name = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = cache_req_svc_by_name_ncache_check, - .ncache_add_fn = cache_req_svc_by_name_ncache_add, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_svc_by_name_lookup, - .dp_send_fn = cache_req_svc_by_name_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c -index 0e48437f4b64d26112be88af1eebc20f012b70fd..1e998f642c766d15d3f6fe777aa5c789629508e2 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c -+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c -@@ -125,6 +125,7 @@ const struct cache_req_plugin cache_req_svc_by_port = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = cache_req_svc_by_port_ncache_check, - .ncache_add_fn = cache_req_svc_by_port_ncache_add, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_svc_by_port_lookup, - .dp_send_fn = cache_req_svc_by_port_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c -index 286a34db276e0098060982c572e2a68ceceebf60..7a0c7d8ce1644f1c41b64c6903e4e20eb3c2c081 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c -@@ -94,6 +94,7 @@ const struct cache_req_plugin cache_req_user_by_cert = { - .global_ncache_add_fn = cache_req_user_by_cert_global_ncache_add, - .ncache_check_fn = cache_req_user_by_cert_ncache_check, - .ncache_add_fn = NULL, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_user_by_cert_lookup, - .dp_send_fn = cache_req_user_by_cert_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c -index c476814373cd784bf8dbbea1da7b010afe5bb4e4..dd3f42e855389ecc73690e4d18c4977253b108a6 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c -@@ -131,6 +131,7 @@ const struct cache_req_plugin cache_req_user_by_filter = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = NULL, - .ncache_add_fn = NULL, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_user_by_filter_lookup, - .dp_send_fn = cache_req_user_by_filter_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -index 9ba73292e5dc518e86c6e00e7e493d6871f28e70..b14b3738aa7721723f524ebd46301a3a9a1c712f 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -@@ -144,6 +144,7 @@ const struct cache_req_plugin cache_req_user_by_id = { - .global_ncache_add_fn = cache_req_user_by_id_global_ncache_add, - .ncache_check_fn = cache_req_user_by_id_ncache_check, - .ncache_add_fn = NULL, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_user_by_id_lookup, - .dp_send_fn = cache_req_user_by_id_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c -index 15da7d0d20b1ac97511a226daecc8ef7e7d2e7e4..2e49de938d0af50089d0cf49860441c2b6ea679c 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c -@@ -199,6 +199,7 @@ const struct cache_req_plugin cache_req_user_by_name = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = cache_req_user_by_name_ncache_check, - .ncache_add_fn = cache_req_user_by_name_ncache_add, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_user_by_name_lookup, - .dp_send_fn = cache_req_user_by_name_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c -index 40a097b1634d2b2d089b7feb377ea2389a58672c..b8bcd241ed79c510aca214ad3788215ae2997d20 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c -@@ -125,6 +125,7 @@ const struct cache_req_plugin cache_req_user_by_upn = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = cache_req_user_by_upn_ncache_check, - .ncache_add_fn = cache_req_user_by_upn_ncache_add, -+ .ncache_filter_fn = NULL, - .lookup_fn = cache_req_user_by_upn_lookup, - .dp_send_fn = cache_req_user_by_upn_dp_send, - .dp_recv_fn = cache_req_common_dp_recv --- -2.9.3 - diff --git a/SOURCES/0125-CACHE_REQ_RESULT-Introduce-cache_req_create_ldb_resu.patch b/SOURCES/0125-CACHE_REQ_RESULT-Introduce-cache_req_create_ldb_resu.patch deleted file mode 100644 index 2508964..0000000 --- a/SOURCES/0125-CACHE_REQ_RESULT-Introduce-cache_req_create_ldb_resu.patch +++ /dev/null @@ -1,92 +0,0 @@ -From a2bfa4d2074cacc5d30f17a3b3af260ec9eaaa59 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Thu, 27 Apr 2017 11:24:45 +0200 -Subject: [PATCH 125/127] CACHE_REQ_RESULT: Introduce - cache_req_create_ldb_result_from_msg_list() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Similarly to what cache_req_create_ldb_result_from_msg() does this new -function creates a new ldb_result from a list of ldb_message. - -It's going to be used in the follow-up patch where some messages from -ldb_result may be filtered and then a new ldb_result has to be created. - -Related: -https://pagure.io/SSSD/sssd/issue/3362 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Pavel Březina -(cherry picked from commit 180e0b282be6aeb047c4b24b46e0b56afba1fdc8) ---- - src/responder/common/cache_req/cache_req_private.h | 5 ++++ - src/responder/common/cache_req/cache_req_result.c | 35 ++++++++++++++++++++++ - 2 files changed, 40 insertions(+) - -diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h -index 851005c389f994b1bd2d04cda9b68df8b18492cc..c0ee5f969f2a171b8a6eb396b3d14b593d157b76 100644 ---- a/src/responder/common/cache_req/cache_req_private.h -+++ b/src/responder/common/cache_req/cache_req_private.h -@@ -137,6 +137,11 @@ cache_req_create_and_add_result(TALLOC_CTX *mem_ctx, - size_t *_num_results); - - struct ldb_result * -+cache_req_create_ldb_result_from_msg_list(TALLOC_CTX *mem_ctx, -+ struct ldb_message **ldb_msgs, -+ size_t ldb_msg_count); -+ -+struct ldb_result * - cache_req_create_ldb_result_from_msg(TALLOC_CTX *mem_ctx, - struct ldb_message *ldb_msg); - -diff --git a/src/responder/common/cache_req/cache_req_result.c b/src/responder/common/cache_req/cache_req_result.c -index e20ae5653acf22a2e0190ef6a88836c7fab9868e..366ba748082336c7c752b576cfd7b8fb8cd82fcf 100644 ---- a/src/responder/common/cache_req/cache_req_result.c -+++ b/src/responder/common/cache_req/cache_req_result.c -@@ -122,6 +122,41 @@ cache_req_create_and_add_result(TALLOC_CTX *mem_ctx, - } - - struct ldb_result * -+cache_req_create_ldb_result_from_msg_list(TALLOC_CTX *mem_ctx, -+ struct ldb_message **ldb_msgs, -+ size_t ldb_msg_count) -+{ -+ struct ldb_result *ldb_result; -+ -+ if (ldb_msgs == NULL || ldb_msgs[0] == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "No message set!\n"); -+ return NULL; -+ } -+ -+ ldb_result = talloc_zero(NULL, struct ldb_result); -+ if (ldb_result == NULL) { -+ return NULL; -+ } -+ -+ ldb_result->extended = NULL; -+ ldb_result->controls = NULL; -+ ldb_result->refs = NULL; -+ ldb_result->count = ldb_msg_count; -+ ldb_result->msgs = talloc_zero_array(ldb_result, struct ldb_message *, -+ ldb_msg_count + 1); -+ if (ldb_result->msgs == NULL) { -+ talloc_free(ldb_result); -+ return NULL; -+ } -+ -+ for (size_t i = 0; i < ldb_msg_count; i++) { -+ ldb_result->msgs[i] = talloc_steal(ldb_result->msgs, ldb_msgs[i]); -+ } -+ -+ return ldb_result; -+} -+ -+struct ldb_result * - cache_req_create_ldb_result_from_msg(TALLOC_CTX *mem_ctx, - struct ldb_message *ldb_msg) - { --- -2.9.3 - diff --git a/SOURCES/0126-CACHE_REQ-Make-use-of-cache_req_ncache_filter_fn.patch b/SOURCES/0126-CACHE_REQ-Make-use-of-cache_req_ncache_filter_fn.patch deleted file mode 100644 index d36136a..0000000 --- a/SOURCES/0126-CACHE_REQ-Make-use-of-cache_req_ncache_filter_fn.patch +++ /dev/null @@ -1,392 +0,0 @@ -From 4c3780ced1b1507ebd8c3d0b91a3ef50b74e0b52 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Tue, 25 Apr 2017 16:33:58 +0200 -Subject: [PATCH 126/127] CACHE_REQ: Make use of cache_req_ncache_filter_fn() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch makes use of cache_req_ncache_filter_fn() in order to process -the result of a cache_req search and then filter out all the results -that are present in the negative cache. - -The "post cache_req search" result processing is done basically in two -different cases: -- plugins which don't use name as an input token (group_by_id, user_by_id - and object_by_id), but still can be affected by filter_{users,groups} - options; -- plugins responsible for groups and users enumeration (enum_groups and - enum_users); - -Resolves: -https://pagure.io/SSSD/sssd/issue/3362 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Pavel Březina -(cherry picked from commit 4ef0b19a5e8a327443d027e57487c8a1e4f654ce) ---- - src/responder/common/cache_req/cache_req_search.c | 124 +++++++++++++++++++-- - .../cache_req/plugins/cache_req_enum_groups.c | 10 +- - .../cache_req/plugins/cache_req_enum_users.c | 10 +- - .../cache_req/plugins/cache_req_group_by_id.c | 10 +- - .../cache_req/plugins/cache_req_object_by_id.c | 17 ++- - .../cache_req/plugins/cache_req_user_by_id.c | 10 +- - src/responder/nss/nss_protocol_grent.c | 12 -- - src/responder/nss/nss_protocol_pwent.c | 11 -- - 8 files changed, 165 insertions(+), 39 deletions(-) - -diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c -index 8bc1530b341f587cb502fdf0ca3ed8d37cfb7d13..793dbc5042ae329b2cade5d1eb5a6d41102e264f 100644 ---- a/src/responder/common/cache_req/cache_req_search.c -+++ b/src/responder/common/cache_req/cache_req_search.c -@@ -84,6 +84,87 @@ static void cache_req_search_ncache_add(struct cache_req *cr) - return; - } - -+static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, -+ struct cache_req *cr, -+ struct ldb_result *result, -+ struct ldb_result **_result) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct ldb_result *filtered_result; -+ struct ldb_message **msgs; -+ size_t msg_count; -+ const char *name; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ if (cr->plugin->ncache_filter_fn == NULL) { -+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, -+ "This request type does not support filtering " -+ "result by negative cache\n"); -+ -+ *_result = talloc_steal(mem_ctx, result); -+ -+ ret = EOK; -+ goto done; -+ } -+ -+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, -+ "Filtering out results by negative cache\n"); -+ -+ msgs = talloc_zero_array(tmp_ctx, struct ldb_message *, result->count); -+ msg_count = 0; -+ -+ for (size_t i = 0; i < result->count; i++) { -+ name = sss_get_name_from_msg(cr->domain, result->msgs[i]); -+ if (name == NULL) { -+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, -+ "sss_get_name_from_msg() returned NULL, which should never " -+ "happen in this scenario!\n"); -+ ret = ERR_INTERNAL; -+ goto done; -+ } -+ -+ ret = cr->plugin->ncache_filter_fn(cr->ncache, cr->domain, name); -+ if (ret == EEXIST) { -+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, -+ "[%s] filtered out! (negative cache)\n", -+ name); -+ continue; -+ } else if (ret != EOK && ret != ENOENT) { -+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, -+ "Unable to check negative cache [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ msgs[msg_count] = talloc_steal(msgs, result->msgs[i]); -+ msg_count++; -+ } -+ -+ if (msg_count == 0) { -+ ret = ENOENT; -+ goto done; -+ } -+ -+ filtered_result = cache_req_create_ldb_result_from_msg_list(tmp_ctx, msgs, -+ msg_count); -+ if (filtered_result == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ *_result = talloc_steal(mem_ctx, filtered_result); -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ - static errno_t cache_req_search_cache(TALLOC_CTX *mem_ctx, - struct cache_req *cr, - struct ldb_result **_result) -@@ -338,10 +419,18 @@ static void cache_req_search_oob_done(struct tevent_req *subreq) - - static void cache_req_search_done(struct tevent_req *subreq) - { -+ TALLOC_CTX *tmp_ctx; - struct cache_req_search_state *state; - struct tevent_req *req; -+ struct ldb_result *result = NULL; - errno_t ret; - -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct cache_req_search_state); - -@@ -349,23 +438,36 @@ static void cache_req_search_done(struct tevent_req *subreq) - talloc_zfree(subreq); - - /* Get result from cache again. */ -- ret = cache_req_search_cache(state, state->cr, &state->result); -- if (ret == ENOENT) { -- /* Only store entry in negative cache if DP request succeeded -- * because only then we know that the entry does not exist. */ -- if (state->dp_success) { -- cache_req_search_ncache_add(state->cr); -+ ret = cache_req_search_cache(tmp_ctx, state->cr, &result); -+ if (ret != EOK) { -+ if (ret == ENOENT) { -+ /* Only store entry in negative cache if DP request succeeded -+ * because only then we know that the entry does not exist. */ -+ if (state->dp_success) { -+ cache_req_search_ncache_add(state->cr); -+ } - } -- tevent_req_error(req, ENOENT); -- return; -- } else if (ret != EOK) { -- tevent_req_error(req, ret); -- return; -+ goto done; -+ } -+ -+ /* ret == EOK */ -+ ret = cache_req_search_ncache_filter(state, state->cr, result, -+ &state->result); -+ if (ret != EOK) { -+ goto done; - } - - CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, - "Returning updated object [%s]\n", state->cr->debugobj); - -+done: -+ talloc_free(tmp_ctx); -+ -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ - tevent_req_done(req); - return; - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c -index 11ce9e90ff28f77078b025a44593a44be8f1f5c5..15350ca8279bc77c73bcc4abe51c97a8a37cb8c8 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c -+++ b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c -@@ -55,6 +55,14 @@ cache_req_enum_groups_dp_send(TALLOC_CTX *mem_ctx, - SSS_DP_GROUP, NULL, 0, NULL); - } - -+static errno_t -+cache_req_enum_groups_ncache_filter(struct sss_nc_ctx *ncache, -+ struct sss_domain_info *domain, -+ const char *name) -+{ -+ return sss_ncache_check_group(ncache, domain, name); -+} -+ - const struct cache_req_plugin cache_req_enum_groups = { - .name = "Enumerate groups", - .attr_expiration = SYSDB_CACHE_EXPIRE, -@@ -75,7 +83,7 @@ const struct cache_req_plugin cache_req_enum_groups = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = NULL, - .ncache_add_fn = NULL, -- .ncache_filter_fn = NULL, -+ .ncache_filter_fn = cache_req_enum_groups_ncache_filter, - .lookup_fn = cache_req_enum_groups_lookup, - .dp_send_fn = cache_req_enum_groups_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_users.c b/src/responder/common/cache_req/plugins/cache_req_enum_users.c -index e0647a0102d9568abdcebfbf0fb99fc2624d5565..a3ddcdd45548a2fa7c367f3fb3be103c115dedb4 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_enum_users.c -+++ b/src/responder/common/cache_req/plugins/cache_req_enum_users.c -@@ -55,6 +55,14 @@ cache_req_enum_users_dp_send(TALLOC_CTX *mem_ctx, - SSS_DP_USER, NULL, 0, NULL); - } - -+static errno_t -+cache_req_enum_users_ncache_filter(struct sss_nc_ctx *ncache, -+ struct sss_domain_info *domain, -+ const char *name) -+{ -+ return sss_ncache_check_user(ncache, domain, name); -+} -+ - const struct cache_req_plugin cache_req_enum_users = { - .name = "Enumerate users", - .attr_expiration = SYSDB_CACHE_EXPIRE, -@@ -75,7 +83,7 @@ const struct cache_req_plugin cache_req_enum_users = { - .global_ncache_add_fn = NULL, - .ncache_check_fn = NULL, - .ncache_add_fn = NULL, -- .ncache_filter_fn = NULL, -+ .ncache_filter_fn = cache_req_enum_users_ncache_filter, - .lookup_fn = cache_req_enum_users_lookup, - .dp_send_fn = cache_req_enum_users_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -index 5613bf67c6acd1b2ace00cf75221462f45ef6743..5ca64283a781318bc4e4d6920fff989c3f3919b4 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -@@ -43,6 +43,14 @@ cache_req_group_by_id_ncache_check(struct sss_nc_ctx *ncache, - } - - static errno_t -+cache_req_group_by_id_ncache_filter(struct sss_nc_ctx *ncache, -+ struct sss_domain_info *domain, -+ const char *name) -+{ -+ return sss_ncache_check_group(ncache, domain, name); -+} -+ -+static errno_t - cache_req_group_by_id_global_ncache_add(struct sss_nc_ctx *ncache, - struct cache_req_data *data) - { -@@ -144,7 +152,7 @@ const struct cache_req_plugin cache_req_group_by_id = { - .global_ncache_add_fn = cache_req_group_by_id_global_ncache_add, - .ncache_check_fn = cache_req_group_by_id_ncache_check, - .ncache_add_fn = NULL, -- .ncache_filter_fn = NULL, -+ .ncache_filter_fn = cache_req_group_by_id_ncache_filter, - .lookup_fn = cache_req_group_by_id_lookup, - .dp_send_fn = cache_req_group_by_id_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -index ff3d0e67862be365c56ab24396b4982e8addded0..339bd4f5fef827acc1aa3c123d041e426d9e4782 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -@@ -50,6 +50,21 @@ cache_req_object_by_id_ncache_check(struct sss_nc_ctx *ncache, - } - - static errno_t -+cache_req_object_by_id_ncache_filter(struct sss_nc_ctx *ncache, -+ struct sss_domain_info *domain, -+ const char *name) -+{ -+ errno_t ret; -+ -+ ret = sss_ncache_check_user(ncache, domain, name); -+ if (ret == EEXIST) { -+ ret = sss_ncache_check_group(ncache, domain, name); -+ } -+ -+ return ret; -+} -+ -+static errno_t - cache_req_object_by_id_global_ncache_add(struct sss_nc_ctx *ncache, - struct cache_req_data *data) - { -@@ -111,7 +126,7 @@ const struct cache_req_plugin cache_req_object_by_id = { - .global_ncache_add_fn = cache_req_object_by_id_global_ncache_add, - .ncache_check_fn = cache_req_object_by_id_ncache_check, - .ncache_add_fn = NULL, -- .ncache_filter_fn = NULL, -+ .ncache_filter_fn = cache_req_object_by_id_ncache_filter, - .lookup_fn = cache_req_object_by_id_lookup, - .dp_send_fn = cache_req_object_by_id_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -index b14b3738aa7721723f524ebd46301a3a9a1c712f..913f9be5bcc2dfd074b52cb3b15fb6948826e831 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -@@ -43,6 +43,14 @@ cache_req_user_by_id_ncache_check(struct sss_nc_ctx *ncache, - } - - static errno_t -+cache_req_user_by_id_ncache_filter(struct sss_nc_ctx *ncache, -+ struct sss_domain_info *domain, -+ const char *name) -+{ -+ return sss_ncache_check_user(ncache, domain, name); -+} -+ -+static errno_t - cache_req_user_by_id_global_ncache_add(struct sss_nc_ctx *ncache, - struct cache_req_data *data) - { -@@ -144,7 +152,7 @@ const struct cache_req_plugin cache_req_user_by_id = { - .global_ncache_add_fn = cache_req_user_by_id_global_ncache_add, - .ncache_check_fn = cache_req_user_by_id_ncache_check, - .ncache_add_fn = NULL, -- .ncache_filter_fn = NULL, -+ .ncache_filter_fn = cache_req_user_by_id_ncache_filter, - .lookup_fn = cache_req_user_by_id_lookup, - .dp_send_fn = cache_req_user_by_id_dp_send, - .dp_recv_fn = cache_req_common_dp_recv -diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c -index 947463df93e188729959737efa4ac4f44a8459c4..ee228c722a153a1ba7aa8a1b30a1e551108424bb 100644 ---- a/src/responder/nss/nss_protocol_grent.c -+++ b/src/responder/nss/nss_protocol_grent.c -@@ -241,18 +241,6 @@ nss_protocol_fill_grent(struct nss_ctx *nss_ctx, - continue; - } - -- /* Check negative cache during enumeration. */ -- if (cmd_ctx->enumeration) { -- ret = sss_ncache_check_group(nss_ctx->rctx->ncache, -- result->domain, name->str); -- if (ret == EEXIST) { -- DEBUG(SSSDBG_TRACE_FUNC, -- "User [%s] filtered out! (negative cache)\n", -- name->str); -- continue; -- } -- } -- - /* Adjust packet size: gid, num_members + string fields. */ - - ret = sss_packet_grow(packet, 2 * sizeof(uint32_t) -diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c -index cb643f29e2d5f0a0c55c51afd9def73813061aa7..b355d4fc90397f51e82545e56940be850f144d49 100644 ---- a/src/responder/nss/nss_protocol_pwent.c -+++ b/src/responder/nss/nss_protocol_pwent.c -@@ -309,17 +309,6 @@ nss_protocol_fill_pwent(struct nss_ctx *nss_ctx, - continue; - } - -- /* Check negative cache during enumeration. */ -- if (cmd_ctx->enumeration) { -- ret = sss_ncache_check_user(nss_ctx->rctx->ncache, -- result->domain, name->str); -- if (ret == EEXIST) { -- DEBUG(SSSDBG_TRACE_FUNC, -- "User [%s] filtered out! (negative cache)\n", name->str); -- continue; -- } -- } -- - /* Adjust packet size: uid, gid + string fields. */ - - ret = sss_packet_grow(packet, 2 * sizeof(uint32_t) --- -2.9.3 - diff --git a/SOURCES/0127-SERVER_MODE-Update-sdap-lists-for-each-ad_ctx.patch b/SOURCES/0127-SERVER_MODE-Update-sdap-lists-for-each-ad_ctx.patch deleted file mode 100644 index 772f302..0000000 --- a/SOURCES/0127-SERVER_MODE-Update-sdap-lists-for-each-ad_ctx.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 9b9d3e2817fdcf16f2949641d4130b39856a4bf6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Fri, 28 Apr 2017 20:49:56 +0200 -Subject: [PATCH 127/127] SERVER_MODE: Update sdap lists for each ad_ctx - -We use separate AD context for each subdomain in the server mode. -Every such context has it's own sdap_domain list witch represents -sdap options such as filter and search bases for every domain. - -However AD context can only fully initialize sdap_domain structure -for the same domain for which the whole context was created, which -resulted in the other sdap_domain structures to be have automaticily -detected settings. This can cause problems if user is member of -groups from multiple domains. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3381 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 21f3d6124ea28218d02e1e345d38e2b948e4ec23) ---- - src/providers/ipa/ipa_subdomains_server.c | 36 +++++++++++++++++++++++++++++++ - 1 file changed, 36 insertions(+) - -diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c -index b02ea67af964a03e5466067cdb2b3ba4498120eb..443d83824f329b9d8c3d8e820113e1029f832240 100644 ---- a/src/providers/ipa/ipa_subdomains_server.c -+++ b/src/providers/ipa/ipa_subdomains_server.c -@@ -870,6 +870,7 @@ static errno_t ipa_server_create_trusts_step(struct tevent_req *req) - { - struct tevent_req *subreq = NULL; - struct ipa_ad_server_ctx *trust_iter; -+ struct ipa_ad_server_ctx *trust_i; - struct ipa_server_create_trusts_state *state = NULL; - - state = tevent_req_data(req, struct ipa_server_create_trusts_state); -@@ -900,6 +901,41 @@ static errno_t ipa_server_create_trusts_step(struct tevent_req *req) - } - } - -+ /* Refresh all sdap_dom lists in all ipa_ad_server_ctx contexts */ -+ DLIST_FOR_EACH(trust_iter, state->id_ctx->server_mode->trusts) { -+ struct sdap_domain *sdom_a; -+ -+ sdom_a = sdap_domain_get(trust_iter->ad_id_ctx->sdap_id_ctx->opts, -+ trust_iter->dom); -+ if (sdom_a == NULL) { -+ continue; -+ } -+ -+ DLIST_FOR_EACH(trust_i, state->id_ctx->server_mode->trusts) { -+ struct sdap_domain *sdom_b; -+ -+ if (strcmp(trust_iter->dom->name, trust_i->dom->name) == 0) { -+ continue; -+ } -+ -+ sdom_b = sdap_domain_get(trust_i->ad_id_ctx->sdap_id_ctx->opts, -+ sdom_a->dom); -+ if (sdom_b == NULL) { -+ continue; -+ } -+ -+ /* Replace basedn and search bases from sdom_b with values -+ * from sdom_a */ -+ sdom_b->search_bases = sdom_a->search_bases; -+ sdom_b->user_search_bases = sdom_a->user_search_bases; -+ sdom_b->group_search_bases = sdom_a->group_search_bases; -+ sdom_b->netgroup_search_bases = sdom_a->netgroup_search_bases; -+ sdom_b->sudo_search_bases = sdom_a->sudo_search_bases; -+ sdom_b->service_search_bases = sdom_a->service_search_bases; -+ sdom_b->autofs_search_bases = sdom_a->autofs_search_bases; -+ } -+ } -+ - return EOK; - } - --- -2.9.3 - diff --git a/SOURCES/0128-sss_nss_getlistbycert-return-results-from-multiple-d.patch b/SOURCES/0128-sss_nss_getlistbycert-return-results-from-multiple-d.patch deleted file mode 100644 index 26092f6..0000000 --- a/SOURCES/0128-sss_nss_getlistbycert-return-results-from-multiple-d.patch +++ /dev/null @@ -1,348 +0,0 @@ -From 71731d26dc4f2c36989779f327b0e9a399486e14 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 9 May 2017 16:57:43 +0200 -Subject: [PATCH] sss_nss_getlistbycert: return results from multiple domains -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Currently only the results from one domain were returned although all -domains were searched and the results were available. Unit tests are -updated to cover this case as well. - -Resolves https://pagure.io/SSSD/sssd/issue/3393 - -Reviewed-by: Pavel Březina ---- - src/responder/nss/nss_cmd.c | 87 +++++++++++++++++++++++++++++++++++- - src/responder/nss/nss_protocol.h | 6 +++ - src/responder/nss/nss_protocol_sid.c | 78 ++++++++++++++++++++++++++++++++ - src/tests/cmocka/test_nss_srv.c | 33 +++++++++----- - 4 files changed, 192 insertions(+), 12 deletions(-) - -diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c -index 1931bf62a686c7f30852dac547866609cf54a81b..a4727c18786a86c28b5415ba82295967a47a8ec0 100644 ---- a/src/responder/nss/nss_cmd.c -+++ b/src/responder/nss/nss_cmd.c -@@ -51,6 +51,7 @@ nss_cmd_ctx_create(TALLOC_CTX *mem_ctx, - } - - static void nss_getby_done(struct tevent_req *subreq); -+static void nss_getlistby_done(struct tevent_req *subreq); - - static errno_t nss_getby_name(struct cli_ctx *cli_ctx, - enum cache_req_type type, -@@ -212,6 +213,89 @@ done: - return EOK; - } - -+static errno_t nss_getlistby_cert(struct cli_ctx *cli_ctx, -+ enum cache_req_type type) -+{ -+ struct nss_cmd_ctx *cmd_ctx; -+ struct tevent_req *subreq; -+ const char *cert; -+ errno_t ret; -+ -+ cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, NULL); -+ if (cmd_ctx == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ cmd_ctx->sid_id_type = SSS_ID_TYPE_UID; -+ -+ ret = nss_protocol_parse_cert(cli_ctx, &cert); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request message!\n"); -+ goto done; -+ } -+ -+ DEBUG(SSSDBG_TRACE_FUNC, "Input cert: %s\n", get_last_x_chars(cert, 10)); -+ -+ subreq = cache_req_user_by_cert_send(cmd_ctx, cli_ctx->ev, cli_ctx->rctx, -+ cli_ctx->rctx->ncache, 0, -+ CACHE_REQ_ANY_DOM, NULL, -+ cert); -+ if (subreq == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ tevent_req_set_callback(subreq, nss_getlistby_done, cmd_ctx); -+ -+ ret = EOK; -+ -+done: -+ if (ret != EOK) { -+ talloc_free(cmd_ctx); -+ return nss_protocol_done(cli_ctx, ret); -+ } -+ -+ return EOK; -+} -+ -+static void nss_getlistby_done(struct tevent_req *subreq) -+{ -+ struct cache_req_result **results; -+ struct nss_cmd_ctx *cmd_ctx; -+ errno_t ret; -+ struct cli_protocol *pctx; -+ -+ cmd_ctx = tevent_req_callback_data(subreq, struct nss_cmd_ctx); -+ -+ ret = cache_req_recv(cmd_ctx, subreq, &results); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert request failed.\n"); -+ goto done; -+ } -+ -+ pctx = talloc_get_type(cmd_ctx->cli_ctx->protocol_ctx, struct cli_protocol); -+ -+ ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in), -+ &pctx->creq->out); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ ret = nss_protocol_fill_name_list_all_domains(cmd_ctx->nss_ctx, cmd_ctx, -+ pctx->creq->out, results); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ sss_packet_set_error(pctx->creq->out, EOK); -+ -+done: -+ nss_protocol_done(cmd_ctx->cli_ctx, ret); -+ talloc_free(cmd_ctx); -+} -+ - static errno_t nss_getby_cert(struct cli_ctx *cli_ctx, - enum cache_req_type type, - nss_protocol_fill_packet_fn fill_fn) -@@ -934,8 +1018,7 @@ static errno_t nss_cmd_getnamebycert(struct cli_ctx *cli_ctx) - - static errno_t nss_cmd_getlistbycert(struct cli_ctx *cli_ctx) - { -- return nss_getby_cert(cli_ctx, CACHE_REQ_USER_BY_CERT, -- nss_protocol_fill_name_list); -+ return nss_getlistby_cert(cli_ctx, CACHE_REQ_USER_BY_CERT); - } - - struct sss_cmd_table *get_nss_cmds(void) -diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h -index e4c0e52c0e642e885ef2c8423ea564beff7242cf..417b0891615dcb8771d49f7b2f4d276342ca3150 100644 ---- a/src/responder/nss/nss_protocol.h -+++ b/src/responder/nss/nss_protocol.h -@@ -181,6 +181,12 @@ nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, - struct cache_req_result *result); - - errno_t -+nss_protocol_fill_name_list_all_domains(struct nss_ctx *nss_ctx, -+ struct nss_cmd_ctx *cmd_ctx, -+ struct sss_packet *packet, -+ struct cache_req_result **results); -+ -+errno_t - nss_protocol_fill_id(struct nss_ctx *nss_ctx, - struct nss_cmd_ctx *cmd_ctx, - struct sss_packet *packet, -diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c -index d4b7ee22d7c68a9e6f7c668f7268cdc5f36768b3..61357c2bf92e2f15d978b64a15ad5bd5aa354445 100644 ---- a/src/responder/nss/nss_protocol_sid.c -+++ b/src/responder/nss/nss_protocol_sid.c -@@ -561,3 +561,81 @@ nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, - - return EOK; - } -+ -+errno_t -+nss_protocol_fill_name_list_all_domains(struct nss_ctx *nss_ctx, -+ struct nss_cmd_ctx *cmd_ctx, -+ struct sss_packet *packet, -+ struct cache_req_result **results) -+{ -+ enum sss_id_type *id_types; -+ size_t rp = 0; -+ size_t body_len; -+ uint8_t *body; -+ errno_t ret; -+ struct sized_string *sz_names; -+ size_t len; -+ size_t c; -+ const char *tmp_str; -+ size_t d; -+ size_t total = 0; -+ size_t iter = 0; -+ -+ if (results == NULL) { -+ return EINVAL; -+ } -+ -+ for (d = 0; results[d] != NULL; d++) { -+ total += results[d]->count; -+ } -+ -+ sz_names = talloc_array(cmd_ctx, struct sized_string, total); -+ if (sz_names == NULL) { -+ return ENOMEM; -+ } -+ -+ id_types = talloc_array(cmd_ctx, enum sss_id_type, total); -+ if (id_types == NULL) { -+ return ENOMEM; -+ } -+ -+ len = 0; -+ for (d = 0; results[d] != NULL; d++) { -+ for (c = 0; c < results[d]->count; c++) { -+ ret = nss_get_id_type(cmd_ctx, results[d], &(id_types[iter])); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ tmp_str = sss_get_name_from_msg(results[d]->domain, -+ results[d]->msgs[c]); -+ if (tmp_str == NULL) { -+ return EINVAL; -+ } -+ to_sized_string(&(sz_names[iter]), tmp_str); -+ -+ len += sz_names[iter].len; -+ iter++; -+ } -+ } -+ -+ len += (2 + total) * sizeof(uint32_t); -+ -+ ret = sss_packet_grow(packet, len); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n"); -+ return ret; -+ } -+ -+ sss_packet_get_body(packet, &body, &body_len); -+ -+ SAFEALIGN_SET_UINT32(&body[rp], total, &rp); /* Num results. */ -+ SAFEALIGN_SET_UINT32(&body[rp], 0, &rp); /* Reserved. */ -+ for (c = 0; c < total; c++) { -+ SAFEALIGN_SET_UINT32(&body[rp], id_types[c], &rp); -+ SAFEALIGN_SET_STRING(&body[rp], sz_names[c].str, sz_names[c].len, -+ &rp); -+ } -+ -+ return EOK; -+} -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 8c72f44f1869558893627e1f2f91b5f3b96c6317..03b5bcc302322551a32f5b8cfe4b7698947abbe7 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -3808,7 +3808,8 @@ static int test_nss_getnamebycert_check(uint32_t status, uint8_t *body, size_t b - return EOK; - } - --static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t blen) -+static int test_nss_getlistbycert_check_exp(uint32_t status, uint8_t *body, -+ size_t blen, size_t exp) - { - size_t rp = 0; - uint32_t id_type; -@@ -3817,13 +3818,13 @@ static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t b - const char *name; - int found = 0; - const char *fq_name1 = "testcertuser@"TEST_DOM_NAME ; -- const char *fq_name2 = "testcertuser2@"TEST_DOM_NAME; -+ const char *fq_name2 = "testcertuser2@"TEST_SUBDOM_NAME; - - assert_int_equal(status, EOK); - - /* num_results and reserved */ - SAFEALIGN_COPY_UINT32(&num, body + rp, &rp); -- assert_in_range(num, 1, 2); -+ assert_int_equal(num, exp); - SAFEALIGN_COPY_UINT32(&reserved, body + rp, &rp); - assert_int_equal(reserved, 0); - -@@ -3858,6 +3859,17 @@ static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t b - return EOK; - } - -+static int test_nss_getlistbycert_check_one(uint32_t status, uint8_t *body, -+ size_t blen) -+{ -+ return test_nss_getlistbycert_check_exp(status, body, blen, 1); -+} -+ -+static int test_nss_getlistbycert_check_two(uint32_t status, uint8_t *body, -+ size_t blen) -+{ -+ return test_nss_getlistbycert_check_exp(status, body, blen, 2); -+} - - static void test_nss_getnamebycert(void **state) - { -@@ -3949,7 +3961,7 @@ static void test_nss_getlistbycert(void **state) - der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size); - assert_non_null(der); - -- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); -+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); - talloc_free(der); - assert_int_equal(ret, EOK); - -@@ -3967,7 +3979,7 @@ static void test_nss_getlistbycert(void **state) - /* Should go straight to back end, without contacting DP. */ - /* If there is only a single user mapped the result will look like the */ - /* result of getnamebycert. */ -- set_cmd_cb(test_nss_getlistbycert_check); -+ set_cmd_cb(test_nss_getlistbycert_check_one); - ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT, - nss_test_ctx->nss_cmds); - assert_int_equal(ret, EOK); -@@ -3990,7 +4002,7 @@ static void test_nss_getlistbycert_multi(void **state) - attrs = sysdb_new_attrs(nss_test_ctx); - assert_non_null(attrs); - -- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); -+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); - assert_int_equal(ret, EOK); - - /* Prime the cache with two valid user */ -@@ -4004,11 +4016,11 @@ static void test_nss_getlistbycert_multi(void **state) - attrs = sysdb_new_attrs(nss_test_ctx); - assert_non_null(attrs); - -- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); -+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); - talloc_free(der); - assert_int_equal(ret, EOK); - -- ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, -+ ret = store_user(nss_test_ctx, nss_test_ctx->subdom, - &testbycert2, attrs, 0); - assert_int_equal(ret, EOK); - talloc_free(attrs); -@@ -4019,7 +4031,7 @@ static void test_nss_getlistbycert_multi(void **state) - - /* Query for that user, call a callback when command finishes */ - /* Should go straight to back end, without contacting DP */ -- set_cmd_cb(test_nss_getlistbycert_check); -+ set_cmd_cb(test_nss_getlistbycert_check_two); - ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT, - nss_test_ctx->nss_cmds); - assert_int_equal(ret, EOK); -@@ -4290,7 +4302,8 @@ int main(int argc, const char *argv[]) - cmocka_unit_test_setup_teardown(test_nss_getlistbycert, - nss_test_setup, nss_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getlistbycert_multi, -- nss_test_setup, nss_test_teardown), -+ nss_subdom_test_setup, -+ nss_subdom_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getsidbyname, - nss_test_setup, nss_test_teardown), - cmocka_unit_test_setup_teardown(test_nss_getsidbyupn, --- -2.9.3 - diff --git a/SOURCES/0129-CACHE_REQ-Avoid-using-of-uninitialized-value.patch b/SOURCES/0129-CACHE_REQ-Avoid-using-of-uninitialized-value.patch deleted file mode 100644 index d11d711..0000000 --- a/SOURCES/0129-CACHE_REQ-Avoid-using-of-uninitialized-value.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 6a1da829eaa1eee3e854f0cadc0b6effff776ab4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Mon, 15 May 2017 11:54:00 +0200 -Subject: [PATCH 1/2] CACHE_REQ: Avoid using of uninitialized value -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Commit 4ef0b19a introduced the following warning, as "req" may be used -without being initialized: -src/responder/common/cache_req/cache_req_search.c: - In function 'cache_req_search_done': -src/responder/common/cache_req/cache_req_search.c:467:9: - error: 'req' may be used uninitialized in this function - [-Werror=maybe-uninitialized] - tevent_req_error(req, ret); - ^ -src/responder/common/cache_req/cache_req_search.c:424:24: - note: 'req' was declared here - struct tevent_req *req; - ^ -cc1: all warnings being treated as errors - -In order to fix the issue above, let's just allocate tmp_ctx after "req" -is already set. - -Related: -https://pagure.io/SSSD/sssd/issue/3362 - -Signed-off-by: Fabiano Fidêncio -Co-Author: Lukáš Slebodník -Reviewed-by: Sumit Bose ---- - src/responder/common/cache_req/cache_req_search.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c -index 793dbc5042ae329b2cade5d1eb5a6d41102e264f..70448a7639bc9f98d380b8edce9d130adfa0ceb2 100644 ---- a/src/responder/common/cache_req/cache_req_search.c -+++ b/src/responder/common/cache_req/cache_req_search.c -@@ -425,18 +425,18 @@ static void cache_req_search_done(struct tevent_req *subreq) - struct ldb_result *result = NULL; - errno_t ret; - -- tmp_ctx = talloc_new(NULL); -- if (tmp_ctx == NULL) { -- ret = ENOMEM; -- goto done; -- } -- - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct cache_req_search_state); - - state->dp_success = state->cr->plugin->dp_recv_fn(subreq, state->cr); - talloc_zfree(subreq); - -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ - /* Get result from cache again. */ - ret = cache_req_search_cache(tmp_ctx, state->cr, &result); - if (ret != EOK) { --- -2.9.3 - diff --git a/SOURCES/0130-CACHE_REQ-Ensure-the-domains-are-updated-for-filter-.patch b/SOURCES/0130-CACHE_REQ-Ensure-the-domains-are-updated-for-filter-.patch deleted file mode 100644 index 1063c09..0000000 --- a/SOURCES/0130-CACHE_REQ-Ensure-the-domains-are-updated-for-filter-.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 1a89fc33d1b9b1070c7ab83fb0314e538ac46736 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 3 May 2017 13:24:40 +0200 -Subject: [PATCH 2/2] CACHE_REQ: Ensure the domains are updated for "filter" - related calls -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -As contacting the infopipe responder on a "filter" related call may lead -to the situation where the cr_domains' list is not populated yet (as the -domains and subdomains lists from the data provider are not processed -yet), let's explicitly call sss_dp_get_domains() for those cases and -avoid returning a wrong result to the caller. - -This situation may happen only because the schedule_get_domains_task(), -that's called when the infopipe responder is initialized, may take some -time to run/finish. - -While I'm not exactly sure whether it's the best solution to avoid the -"race", it seems to be sane enough to avoid the issues. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3387 - -Signed-off-by: Fabiano Fidêncio -Reviewed-by: Sumit Bose -Reviewed-by: Pavel Březina ---- - src/responder/common/cache_req/cache_req.c | 86 ++++++++++++++++++++++++++++-- - 1 file changed, 81 insertions(+), 5 deletions(-) - -diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c -index 797325a30e6c1ed5f1d4b4c147c65391d5204b52..7d77eb7dd72a7ccf3d687eee8f746ab84176b487 100644 ---- a/src/responder/common/cache_req/cache_req.c -+++ b/src/responder/common/cache_req/cache_req.c -@@ -698,6 +698,13 @@ static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx, - struct cache_req *cr, - const char *domain); - -+static errno_t cache_req_update_domains(TALLOC_CTX *mem_ctx, -+ struct tevent_req *req, -+ struct cache_req *cr, -+ const char *domain); -+ -+static void cache_req_domains_updated(struct tevent_req *subreq); -+ - static void cache_req_input_parsed(struct tevent_req *subreq); - - static errno_t cache_req_select_domains(struct tevent_req *req, -@@ -753,13 +760,13 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, - goto done; - } - -+ state->domain_name = domain; - ret = cache_req_process_input(state, req, cr, domain); - if (ret != EOK) { - goto done; - } - -- state->domain_name = domain; -- ret = cache_req_select_domains(req, domain); -+ ret = cache_req_select_domains(req, state->domain_name); - - done: - if (ret == EOK) { -@@ -780,14 +787,25 @@ static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx, - { - struct tevent_req *subreq; - const char *default_domain; -+ errno_t ret; - - if (cr->data->name.input == NULL) { -- /* Input was not name, there is no need to process it further. */ -- return EOK; -+ /* Call cache_req_update_domains() in order to get a up to date list -+ * of domains and subdomains, if needed. Otherwise just return EOK as -+ * the input was not a name, thus there's no need to process it -+ * further. */ -+ return cache_req_update_domains(mem_ctx, req, cr, domain); - } - - if (cr->plugin->parse_name == false || domain != NULL) { -- /* We do not want to parse the name. */ -+ /* Call cache_req_update_domains() in order to get a up to date list -+ * of domains and subdomains, if needed. Otherwise, just use the input -+ * name as it is. */ -+ ret = cache_req_update_domains(mem_ctx, req, cr, domain); -+ if (ret != EOK) { -+ return ret; -+ } -+ - return cache_req_set_name(cr, cr->data->name.input); - } - -@@ -812,6 +830,64 @@ static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx, - return EAGAIN; - } - -+static errno_t cache_req_update_domains(TALLOC_CTX *mem_ctx, -+ struct tevent_req *req, -+ struct cache_req *cr, -+ const char *domain) -+{ -+ struct tevent_req *subreq; -+ -+ if (cr->rctx->get_domains_last_call.tv_sec != 0) { -+ return EOK; -+ } -+ -+ subreq = sss_dp_get_domains_send(mem_ctx, cr->rctx, false, domain); -+ if (subreq == NULL) { -+ return ENOMEM; -+ } -+ -+ tevent_req_set_callback(subreq, cache_req_domains_updated, req); -+ return EAGAIN; -+} -+ -+static void cache_req_domains_updated(struct tevent_req *subreq) -+{ -+ struct tevent_req *req; -+ struct cache_req_state *state; -+ errno_t ret; -+ -+ req = tevent_req_callback_data(subreq, struct tevent_req); -+ state = tevent_req_data(req, struct cache_req_state); -+ -+ ret = sss_dp_get_domains_recv(subreq); -+ talloc_free(subreq); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ if (state->cr->data->name.input == NULL) { -+ /* Input was not name, there is no need to process it further. */ -+ goto immediately; -+ } -+ -+ if (state->cr->plugin->parse_name == false || state->domain_name != NULL) { -+ /* We do not want to parse the name. */ -+ ret = cache_req_set_name(state->cr, state->cr->data->name.input); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ -+immediately: -+ ret = cache_req_select_domains(req, state->domain_name); -+ -+done: -+ if (ret != EOK && ret != EAGAIN) { -+ tevent_req_error(req, ret); -+ return; -+ } -+} -+ - static void cache_req_input_parsed(struct tevent_req *subreq) - { - struct tevent_req *req; --- -2.9.3 - diff --git a/SOURCES/0131-AD-SUBDOMAINS-Fix-search-bases-for-child-domains.patch b/SOURCES/0131-AD-SUBDOMAINS-Fix-search-bases-for-child-domains.patch deleted file mode 100644 index 50c99ed..0000000 --- a/SOURCES/0131-AD-SUBDOMAINS-Fix-search-bases-for-child-domains.patch +++ /dev/null @@ -1,102 +0,0 @@ -From f994343e9ffc8f8d2917678ae61bcdf68c316a20 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 9 May 2017 11:21:02 +0200 -Subject: [PATCH 131/131] AD SUBDOMAINS: Fix search bases for child domains - -When using direct AD integration, child domains did not respect -the sssd.conf configuration of search bases. - -There were few issues all of which are fixed in this small -patch. - -First problem was that the sdap domain list was not properly -inherited from the parent in the child domains and the children -always created their own sdap domains lists that were disconnected -from the parent context and never used. - -Second issue was that the child domain did not call the function -to reinit the search bases after the sdap_domain was added to the -list of sdap domains. This caused that child domains always used -automatically detected search bases and never used the configured -ones even though they were properly read into the ID options -context attached to the subdomain. - -Also there has been an issue that the sdap search bases -were rewritten by the new child domain initialization -(this only happened with more than one child domain) -because the sdap domain list was 'updated' every time -a new child domain was initialized, which caused that -only the main domain and the last child domain had proper -search bases, the others only the auto-discovered ones -(because they were overwritten with the 'update'). - -Resolves: -https://pagure.io/SSSD/sssd/issue/3397 - -Reviewed-by: Sumit Bose ---- - src/providers/ad/ad_subdomains.c | 17 +++++++++++++++++ - src/providers/ldap/sdap_domain.c | 5 +++++ - 2 files changed, 22 insertions(+) - -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index ef166446e837c3f7cd824c1abf4b5cc587aec9da..c9b79dd9d6840802cddc067eef9d5110cf8d0778 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -221,6 +221,9 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, - ad_id_ctx->sdap_id_ctx->opts = ad_options->id; - ad_options->id_ctx = ad_id_ctx; - -+ /* We need to pass the sdap list from parent */ -+ ad_id_ctx->sdap_id_ctx->opts->sdom = id_ctx->sdap_id_ctx->opts->sdom; -+ - /* use AD plugin */ - srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res, - default_host_dbs, -@@ -257,6 +260,13 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, - ad_id_ctx->sdap_id_ctx->opts->idmap_ctx = - id_ctx->sdap_id_ctx->opts->idmap_ctx; - -+ ret = ad_set_search_bases(ad_options->id, sdom); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to set LDAP search bases for " -+ "domain '%s'. Will try to use automatically detected search " -+ "bases.", subdom->name); -+ } -+ - *_subdom_id_ctx = ad_id_ctx; - return EOK; - } -@@ -621,6 +631,13 @@ ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx, - return ret; - } - -+ ret = ad_set_search_bases(ctx->ad_id_ctx->ad_options->id, ctx->sdom); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "failed to set ldap search bases for " -+ "domain '%s'. will try to use automatically detected search " -+ "bases.", ctx->sdom->dom->name); -+ } -+ - DLIST_FOR_EACH(sditer, ctx->sdom) { - if (IS_SUBDOMAIN(sditer->dom) && sditer->pvt == NULL) { - ret = ad_subdom_ad_ctx_new(ctx->be_ctx, ctx->ad_id_ctx, -diff --git a/src/providers/ldap/sdap_domain.c b/src/providers/ldap/sdap_domain.c -index 5cba9df0fd5fb320a57adc39093283aed865f57f..d384b2e4a0ec3a7c8d0b05e0ce735feb2189085f 100644 ---- a/src/providers/ldap/sdap_domain.c -+++ b/src/providers/ldap/sdap_domain.c -@@ -154,6 +154,11 @@ sdap_domain_subdom_add(struct sdap_id_ctx *sdap_id_ctx, - parent->name, ret, strerror(ret)); - return ret; - } -+ } else if (sditer->search_bases != NULL) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "subdomain %s has already initialized search bases\n", -+ dom->name); -+ continue; - } else { - sdom = sditer; - } --- -2.9.3 - diff --git a/SOURCES/0132-KRB5-Advise-the-user-to-inspect-the-krb5_child.log-i.patch b/SOURCES/0132-KRB5-Advise-the-user-to-inspect-the-krb5_child.log-i.patch deleted file mode 100644 index 7eecef9..0000000 --- a/SOURCES/0132-KRB5-Advise-the-user-to-inspect-the-krb5_child.log-i.patch +++ /dev/null @@ -1,39 +0,0 @@ -From cf1bb5464609f5873685406f9e09e43de8738e42 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 22 May 2017 09:55:12 +0200 -Subject: [PATCH 132/135] KRB5: Advise the user to inspect the krb5_child.log - if the child doesn't return a valid response -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If the child returns a runtime error, it is often not clear from the -domain debug logs what to do next. This patch adds a DEBUG message that -tells the admin to look into the krb5_child.log - -Resolves: -https://pagure.io/SSSD/sssd/issue/2955 - -Reviewed-by: Pavel Březina -(cherry picked from commit 7410f735b64937e0c2401c09b5cffc9c78b11849) ---- - src/providers/krb5/krb5_auth.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c -index 2faf18d17a735476c20f9cc27b15be4a39cadc5c..894bd41bde031ac33187bfa3b14202e9429a9198 100644 ---- a/src/providers/krb5/krb5_auth.c -+++ b/src/providers/krb5/krb5_auth.c -@@ -890,6 +890,9 @@ static void krb5_auth_done(struct tevent_req *subreq) - state->be_ctx->domain->pwd_expiration_warning, - &res); - if (ret) { -+ DEBUG(SSSDBG_IMPORTANT_INFO, -+ "The krb5_child process returned an error. Please inspect the " -+ "krb5_child.log file or the journal for more information\n"); - DEBUG(SSSDBG_OP_FAILURE, "Could not parse child response [%d]: %s\n", - ret, strerror(ret)); - goto done; --- -2.9.3 - diff --git a/SOURCES/0133-cache_req-use-the-right-negative-cache-for-initgroup.patch b/SOURCES/0133-cache_req-use-the-right-negative-cache-for-initgroup.patch deleted file mode 100644 index 52aa5dc..0000000 --- a/SOURCES/0133-cache_req-use-the-right-negative-cache-for-initgroup.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 04ef28b7cc49a71209551646b3a82518506f40a6 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 22 May 2017 14:58:01 +0200 -Subject: [PATCH 133/135] cache_req: use the right negative cache for - initgroups by upn -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 870b58a6cc6b5cf92a6503c1578e5c21617c8d40) ---- - src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c -index b6fb43ee02d2f041fb3d992b375ae65a02db8b03..dfb21ac1a0090a3ef9029b38f5b1e8bdda3440c6 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c -+++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c -@@ -66,7 +66,7 @@ cache_req_initgroups_by_upn_ncache_check(struct sss_nc_ctx *ncache, - struct sss_domain_info *domain, - struct cache_req_data *data) - { -- return sss_ncache_check_user(ncache, domain, data->name.lookup); -+ return sss_ncache_check_upn(ncache, domain, data->name.lookup); - } - - static errno_t -@@ -74,7 +74,7 @@ cache_req_initgroups_by_upn_ncache_add(struct sss_nc_ctx *ncache, - struct sss_domain_info *domain, - struct cache_req_data *data) - { -- return sss_ncache_set_user(ncache, false, domain, data->name.lookup); -+ return sss_ncache_set_upn(ncache, false, domain, data->name.lookup); - } - - static errno_t --- -2.9.3 - diff --git a/SOURCES/0134-test-make-sure-p11_child-is-build-for-pam-srv-tests.patch b/SOURCES/0134-test-make-sure-p11_child-is-build-for-pam-srv-tests.patch deleted file mode 100644 index 5fa1c16..0000000 --- a/SOURCES/0134-test-make-sure-p11_child-is-build-for-pam-srv-tests.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 9e7bb71e02af7cf8fe8b593ddc762a09183ff32c Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 22 May 2017 15:04:17 +0200 -Subject: [PATCH 134/135] test: make sure p11_child is build for pam-srv-tests -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit ec9ac22d699a17d590b1d4ba9ba3750eb719f340) ---- - Makefile.am | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/Makefile.am b/Makefile.am -index 370d6442ec58a14946ad288a23c696f25ca98f47..a6279133b56dcd5bcbd1306ae8f2ce18d90c2c12 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -2356,6 +2356,9 @@ nss_srv_tests_LDADD = \ - EXTRA_pam_srv_tests_DEPENDENCIES = \ - $(ldblib_LTLIBRARIES) \ - $(NULL) -+if HAVE_NSS -+EXTRA_pam_srv_tests_DEPENDENCIES += p11_child -+endif - pam_srv_tests_SOURCES = \ - $(TEST_MOCK_RESP_OBJ) \ - src/tests/cmocka/test_pam_srv.c \ --- -2.9.3 - diff --git a/SOURCES/0135-pam-properly-support-UPN-logon-names.patch b/SOURCES/0135-pam-properly-support-UPN-logon-names.patch deleted file mode 100644 index 54d6529..0000000 --- a/SOURCES/0135-pam-properly-support-UPN-logon-names.patch +++ /dev/null @@ -1,163 +0,0 @@ -From b6ba8bc43a0b5a448e4cd30bc406bd08c389e365 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 12 May 2017 10:40:21 +0200 -Subject: [PATCH 135/135] pam: properly support UPN logon names -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Many logon applications like /bin/login or sshd canonicalize the user -name before they call pam_start() and hence the UPN is not seen by -SSSD's pam responder. But some like e.g. gdm don't and authentication -might fail if a UPN is used. - -The reason is that currently the already parsed short name of the user -was used in the cache_req and hence the cache_req was not able to fall -back to the UPN lookup code. This patch uses the name originally -provided by the user as input to allow the fallback to the UPN lookup. - -Resolves https://pagure.io/SSSD/sssd/issue/3240 - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 29d063505c07127f7747405b1a61d8f782673645) ---- - src/responder/pam/pamsrv_cmd.c | 4 +-- - src/tests/cmocka/test_pam_srv.c | 79 ++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 80 insertions(+), 3 deletions(-) - -diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c -index 10a178f839ec011c09a6da4575efbb026f3f7700..36dba37964b71153435b4df5d5328de4361926e6 100644 ---- a/src/responder/pam/pamsrv_cmd.c -+++ b/src/responder/pam/pamsrv_cmd.c -@@ -1560,7 +1560,7 @@ static int pam_check_user_search(struct pam_auth_req *preq) - - data = cache_req_data_name(preq, - CACHE_REQ_INITGROUPS, -- preq->pd->user); -+ preq->pd->logon_name); - if (data == NULL) { - return ENOMEM; - } -@@ -1589,7 +1589,7 @@ static int pam_check_user_search(struct pam_auth_req *preq) - preq->cctx->rctx->ncache, - 0, - preq->req_dom_type, -- preq->pd->domain, -+ NULL, - data); - if (!dpreq) { - DEBUG(SSSDBG_CRIT_FAILURE, -diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c -index d249b8f1ea48f1c17b461c3add9e8c63774e5f88..4d351a3707d2a49604595b728fff7705560c871a 100644 ---- a/src/tests/cmocka/test_pam_srv.c -+++ b/src/tests/cmocka/test_pam_srv.c -@@ -518,6 +518,8 @@ static void mock_input_pam_ex(TALLOC_CTX *mem_ctx, - int ret; - size_t needed_size; - uint8_t *authtok; -+ char *s_name; -+ char *dom; - - if (name != NULL) { - pi.pam_user = name; -@@ -574,7 +576,13 @@ static void mock_input_pam_ex(TALLOC_CTX *mem_ctx, - will_return(__wrap_sss_packet_get_body, buf); - will_return(__wrap_sss_packet_get_body, buf_size); - -- mock_parse_inp(name, NULL, EOK); -+ if (strrchr(name, '@') == NULL) { -+ mock_parse_inp(name, NULL, EOK); -+ } else { -+ ret = sss_parse_internal_fqname(mem_ctx, name, &s_name, &dom); -+ mock_parse_inp(s_name, dom, EOK); -+ } -+ - if (contact_dp) { - mock_account_recv_simple(); - } -@@ -1582,6 +1590,71 @@ void test_pam_preauth_no_logon_name(void **state) - assert_int_equal(ret, EOK); - } - -+void test_pam_auth_no_upn_logon_name(void **state) -+{ -+ int ret; -+ -+ ret = sysdb_cache_password(pam_test_ctx->tctx->dom, -+ pam_test_ctx->pam_user_fqdn, -+ "12345"); -+ assert_int_equal(ret, EOK); -+ -+ mock_input_pam_ex(pam_test_ctx, "upn@"TEST_DOM_NAME, "12345", NULL, NULL, -+ true); -+ mock_account_recv_simple(); -+ -+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); -+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ pam_test_ctx->exp_pam_status = PAM_USER_UNKNOWN; -+ set_cmd_cb(test_pam_simple_check); -+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, -+ pam_test_ctx->pam_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(pam_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ -+void test_pam_auth_upn_logon_name(void **state) -+{ -+ int ret; -+ struct sysdb_attrs *attrs; -+ -+ ret = sysdb_cache_password(pam_test_ctx->tctx->dom, -+ pam_test_ctx->pam_user_fqdn, -+ "12345"); -+ assert_int_equal(ret, EOK); -+ attrs = sysdb_new_attrs(pam_test_ctx); -+ assert_non_null(attrs); -+ ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, "upn@"TEST_DOM_NAME); -+ assert_int_equal(ret, EOK); -+ -+ ret = sysdb_set_user_attr(pam_test_ctx->tctx->dom, -+ pam_test_ctx->pam_user_fqdn, -+ attrs, -+ LDB_FLAG_MOD_ADD); -+ assert_int_equal(ret, EOK); -+ -+ mock_input_pam_ex(pam_test_ctx, "upn@"TEST_DOM_NAME, "12345", NULL, NULL, -+ true); -+ mock_account_recv_simple(); -+ -+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); -+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ set_cmd_cb(test_pam_successful_offline_auth_check); -+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, -+ pam_test_ctx->pam_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(pam_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ -+ - static void set_cert_auth_param(struct pam_ctx *pctx, const char *dbpath) - { - pam_test_ctx->pctx->cert_auth = true; -@@ -2312,6 +2385,10 @@ int main(int argc, const char *argv[]) - pam_test_setup, pam_test_teardown), - cmocka_unit_test_setup_teardown(test_pam_preauth_no_logon_name, - pam_test_setup, pam_test_teardown), -+ cmocka_unit_test_setup_teardown(test_pam_auth_no_upn_logon_name, -+ pam_test_setup, pam_test_teardown), -+ cmocka_unit_test_setup_teardown(test_pam_auth_upn_logon_name, -+ pam_test_setup, pam_test_teardown), - cmocka_unit_test_setup_teardown(test_pam_cached_auth_success, - pam_cached_test_setup, - pam_test_teardown), --- -2.9.3 - diff --git a/SOURCES/0136-KCM-Fix-the-per-client-serialization-queue.patch b/SOURCES/0136-KCM-Fix-the-per-client-serialization-queue.patch deleted file mode 100644 index 3cf4420..0000000 --- a/SOURCES/0136-KCM-Fix-the-per-client-serialization-queue.patch +++ /dev/null @@ -1,334 +0,0 @@ -From b31f75f44a9e1dc0521ec73176f89e05db4973ba Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Thu, 11 May 2017 16:24:24 +0200 -Subject: [PATCH 136/138] KCM: Fix the per-client serialization queue -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: - https://pagure.io/SSSD/sssd/issue/3372 - -Fixes a race condition between one client request adding an operation to -the hash table value, which was previously a linked list of operations, -while another concurrent operation would remove the last remaining -linked list element through its callback. - -Instead, the hash table value is now a separate 'queue head' structure -which is only changed in a tevent request to make sure is is not -processes concurrently with adding to the queue (which is also a tevent -request). - -Reviewed-by: Pavel Březina -(cherry picked from commit fb51bb68e62de7bb8542f5d224994eb7143040a6) ---- - src/responder/kcm/kcmsrv_op_queue.c | 182 ++++++++++++++++++++++++------------ - 1 file changed, 122 insertions(+), 60 deletions(-) - -diff --git a/src/responder/kcm/kcmsrv_op_queue.c b/src/responder/kcm/kcmsrv_op_queue.c -index f6c425dd5b64877c8b7401e488dd6565157fc9b5..55c8b65d94f70979fe56fcc4d8747547a9cc9d33 100644 ---- a/src/responder/kcm/kcmsrv_op_queue.c -+++ b/src/responder/kcm/kcmsrv_op_queue.c -@@ -27,17 +27,23 @@ - - struct kcm_ops_queue_entry { - struct tevent_req *req; -- uid_t uid; - -- hash_table_t *wait_queue_hash; -+ struct kcm_ops_queue *queue; - -- struct kcm_ops_queue_entry *head; - struct kcm_ops_queue_entry *next; - struct kcm_ops_queue_entry *prev; - }; - -+struct kcm_ops_queue { -+ uid_t uid; -+ struct tevent_context *ev; -+ struct kcm_ops_queue_ctx *qctx; -+ -+ struct kcm_ops_queue_entry *head; -+}; -+ - struct kcm_ops_queue_ctx { -- /* UID: dlist of kcm_ops_queue_entry */ -+ /* UID:kcm_ops_queue */ - hash_table_t *wait_queue_hash; - }; - -@@ -45,8 +51,9 @@ struct kcm_ops_queue_ctx { - * Per-UID wait queue - * - * They key in the hash table is the UID of the peer. The value of each -- * hash table entry is a linked list of kcm_ops_queue_entry structures -- * which primarily hold the tevent request being queued. -+ * hash table entry is kcm_ops_queue structure which in turn contains a -+ * linked list of kcm_ops_queue_entry structures * which primarily hold the -+ * tevent request being queued. - */ - struct kcm_ops_queue_ctx *kcm_ops_queue_create(TALLOC_CTX *mem_ctx) - { -@@ -71,11 +78,45 @@ struct kcm_ops_queue_ctx *kcm_ops_queue_create(TALLOC_CTX *mem_ctx) - return queue_ctx; - } - --static int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry) -+void queue_removal_cb(struct tevent_context *ctx, -+ struct tevent_immediate *imm, -+ void *private_data) - { -+ struct kcm_ops_queue *kq = talloc_get_type(private_data, -+ struct kcm_ops_queue); - int ret; -+ hash_key_t key; -+ -+ talloc_free(imm); -+ -+ if (kq->head != NULL) { -+ DEBUG(SSSDBG_TRACE_LIBS, "The queue is no longer empty\n"); -+ return; -+ } -+ -+ key.type = HASH_KEY_ULONG; -+ key.ul = kq->uid; -+ -+ /* If this was the last entry, remove the key (the UID) from the -+ * hash table to signal the queue is empty -+ */ -+ ret = hash_delete(kq->qctx->wait_queue_hash, &key); -+ if (ret != HASH_SUCCESS) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to remove wait queue for user %"SPRIuid"\n", -+ kq->uid); -+ return; -+ } -+ -+ DEBUG(SSSDBG_FUNC_DATA, -+ "Removed queue for %"SPRIuid" \n", kq->uid); -+ talloc_free(kq); -+} -+ -+static int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry) -+{ - struct kcm_ops_queue_entry *next_entry; -- hash_key_t key; -+ struct tevent_immediate *imm; - - if (entry == NULL) { - return 1; -@@ -85,22 +126,19 @@ static int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry) - next_entry = entry->next; - - /* Remove the current entry from the queue */ -- DLIST_REMOVE(entry->head, entry); -+ DLIST_REMOVE(entry->queue->head, entry); - - if (next_entry == NULL) { -- key.type = HASH_KEY_ULONG; -- key.ul = entry->uid; -- -- /* If this was the last entry, remove the key (the UID) from the -- * hash table to signal the queue is empty -+ /* If there was no other entry, schedule removal of the queue. Do it -+ * in another tevent tick to avoid issues with callbacks invoking -+ * the descructor while another request is touching the queue - */ -- ret = hash_delete(entry->wait_queue_hash, &key); -- if (ret != HASH_SUCCESS) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Failed to remove wait queue for user %"SPRIuid"\n", -- entry->uid); -+ imm = tevent_create_immediate(entry->queue); -+ if (imm == NULL) { - return 1; - } -+ -+ tevent_schedule_immediate(imm, entry->queue->ev, queue_removal_cb, entry->queue); - return 0; - } - -@@ -109,41 +147,33 @@ static int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry) - return 0; - } - --static errno_t kcm_op_queue_add(hash_table_t *wait_queue_hash, -- struct kcm_ops_queue_entry *entry, -- uid_t uid) -+static struct kcm_ops_queue *kcm_op_queue_get(struct kcm_ops_queue_ctx *qctx, -+ struct tevent_context *ev, -+ uid_t uid) - { - errno_t ret; - hash_key_t key; - hash_value_t value; -- struct kcm_ops_queue_entry *head = NULL; -+ struct kcm_ops_queue *kq; - - key.type = HASH_KEY_ULONG; - key.ul = uid; - -- ret = hash_lookup(wait_queue_hash, &key, &value); -+ ret = hash_lookup(qctx->wait_queue_hash, &key, &value); - switch (ret) { - case HASH_SUCCESS: -- /* The key with this UID already exists. Its value is request queue -- * for the UID, so let's just add the current request to the end -- * of the queue and wait for the previous requests to finish -- */ - if (value.type != HASH_VALUE_PTR) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected hash value type.\n"); -- return EINVAL; -+ return NULL; - } - -- head = talloc_get_type(value.ptr, struct kcm_ops_queue_entry); -- if (head == NULL) { -+ kq = talloc_get_type(value.ptr, struct kcm_ops_queue); -+ if (kq == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Invalid queue pointer\n"); -- return EINVAL; -+ return NULL; - } - -- entry->head = head; -- DLIST_ADD_END(head, entry, struct kcm_ops_queue_entry *); -- -- DEBUG(SSSDBG_TRACE_LIBS, "Waiting in queue\n"); -- ret = EAGAIN; -+ DEBUG(SSSDBG_TRACE_LIBS, "Found existing queue for this ID\n"); - break; - - case HASH_ERROR_KEY_NOT_FOUND: -@@ -151,36 +181,41 @@ static errno_t kcm_op_queue_add(hash_table_t *wait_queue_hash, - * another one comes in and return EOK to run the current request - * immediatelly - */ -- entry->head = entry; -+ DEBUG(SSSDBG_TRACE_LIBS, "No existing queue for this ID\n"); -+ -+ kq = talloc_zero(qctx->wait_queue_hash, struct kcm_ops_queue); -+ if (kq == NULL) { -+ return NULL; -+ } -+ kq->uid = uid; -+ kq->qctx = qctx; -+ kq->ev = ev; - - value.type = HASH_VALUE_PTR; -- value.ptr = entry; -+ value.ptr = kq; - -- ret = hash_enter(wait_queue_hash, &key, &value); -+ ret = hash_enter(qctx->wait_queue_hash, &key, &value); - if (ret != HASH_SUCCESS) { - DEBUG(SSSDBG_CRIT_FAILURE, "hash_enter failed.\n"); -- return EIO; -+ return NULL; - } -- -- DEBUG(SSSDBG_TRACE_LIBS, -- "Added a first request to the queue, running immediately\n"); -- ret = EOK; - break; - - default: - DEBUG(SSSDBG_CRIT_FAILURE, "hash_lookup failed.\n"); -- return EIO; -+ return NULL; - } - -- talloc_steal(wait_queue_hash, entry); -- talloc_set_destructor(entry, kcm_op_queue_entry_destructor); -- return ret; -+ return kq; - } - - struct kcm_op_queue_state { - struct kcm_ops_queue_entry *entry; - }; - -+static errno_t kcm_op_queue_add_req(struct kcm_ops_queue *kq, -+ struct tevent_req *req); -+ - /* - * Enqueue a request. - * -@@ -198,6 +233,7 @@ struct tevent_req *kcm_op_queue_send(TALLOC_CTX *mem_ctx, - { - errno_t ret; - struct tevent_req *req; -+ struct kcm_ops_queue *kq; - struct kcm_op_queue_state *state; - uid_t uid; - -@@ -208,22 +244,21 @@ struct tevent_req *kcm_op_queue_send(TALLOC_CTX *mem_ctx, - return NULL; - } - -- state->entry = talloc_zero(state, struct kcm_ops_queue_entry); -- if (state->entry == NULL) { -- ret = ENOMEM; -- goto immediate; -- } -- state->entry->req = req; -- state->entry->uid = uid; -- state->entry->wait_queue_hash = qctx->wait_queue_hash; -- - DEBUG(SSSDBG_FUNC_DATA, - "Adding request by %"SPRIuid" to the wait queue\n", uid); - -- ret = kcm_op_queue_add(qctx->wait_queue_hash, state->entry, uid); -+ kq = kcm_op_queue_get(qctx, ev, uid); -+ if (kq == NULL) { -+ ret = EIO; -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Cannot get queue [%d]: %s\n", ret, sss_strerror(ret)); -+ goto immediate; -+ } -+ -+ ret = kcm_op_queue_add_req(kq, req); - if (ret == EOK) { - DEBUG(SSSDBG_TRACE_LIBS, -- "Wait queue was empty, running immediately\n"); -+ "Queue was empty, running the request immediately\n"); - goto immediate; - } else if (ret != EAGAIN) { - DEBUG(SSSDBG_OP_FAILURE, -@@ -244,6 +279,33 @@ immediate: - return req; - } - -+static errno_t kcm_op_queue_add_req(struct kcm_ops_queue *kq, -+ struct tevent_req *req) -+{ -+ errno_t ret; -+ struct kcm_op_queue_state *state = tevent_req_data(req, -+ struct kcm_op_queue_state); -+ -+ state->entry = talloc_zero(kq->qctx->wait_queue_hash, struct kcm_ops_queue_entry); -+ if (state->entry == NULL) { -+ return ENOMEM; -+ } -+ state->entry->req = req; -+ state->entry->queue = kq; -+ talloc_set_destructor(state->entry, kcm_op_queue_entry_destructor); -+ -+ if (kq->head == NULL) { -+ /* First entry, will run callback at once */ -+ ret = EOK; -+ } else { -+ /* Will wait for the previous callbacks to finish */ -+ ret = EAGAIN; -+ } -+ -+ DLIST_ADD_END(kq->head, state->entry, struct kcm_ops_queue_entry *); -+ return ret; -+} -+ - /* - * The queue recv function is called when this request is 'activated'. The queue - * entry should be allocated on the same memory context as the enqueued request --- -2.9.4 - diff --git a/SOURCES/0137-TESTS-Add-a-test-for-parallel-execution-of-klist.patch b/SOURCES/0137-TESTS-Add-a-test-for-parallel-execution-of-klist.patch deleted file mode 100644 index 25a3528..0000000 --- a/SOURCES/0137-TESTS-Add-a-test-for-parallel-execution-of-klist.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 7930ee12093eae1e1ab9422c4f4f9f8c5661fcb9 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 23 May 2017 13:55:01 +0200 -Subject: [PATCH 137/138] TESTS: Add a test for parallel execution of klist -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Integration test for: - https://pagure.io/SSSD/sssd/issue/3372 - -With https://pagure.io/SSSD/sssd/issue/3372 still broken, the unit test -wold fail because one of the concurrent klist commands would trigger a -race condition in the KCM queue code, crashing the KCM responder. - -Reviewed-by: Pavel Březina -(cherry picked from commit 274489b092bba5fc81cb0f803843d56b267c5aaf) ---- - src/tests/intg/krb5utils.py | 6 +++++- - src/tests/intg/test_kcm.py | 22 ++++++++++++++++++++++ - 2 files changed, 27 insertions(+), 1 deletion(-) - -diff --git a/src/tests/intg/krb5utils.py b/src/tests/intg/krb5utils.py -index 775cffd0bbfa011f2d8ffc1169dccfef96d78fab..0349ff3829533088fb2263f84b19574127d6e809 100644 ---- a/src/tests/intg/krb5utils.py -+++ b/src/tests/intg/krb5utils.py -@@ -36,7 +36,7 @@ class Krb5Utils(object): - def __init__(self, krb5_conf_path): - self.krb5_conf_path = krb5_conf_path - -- def _run_in_env(self, args, stdin=None, extra_env=None): -+ def spawn_in_env(self, args, stdin=None, extra_env=None): - my_env = os.environ - my_env['KRB5_CONFIG'] = self.krb5_conf_path - -@@ -50,6 +50,10 @@ class Krb5Utils(object): - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) -+ return cmd -+ -+ def _run_in_env(self, args, stdin=None, extra_env=None): -+ cmd = self.spawn_in_env(args, stdin, extra_env) - out, err = cmd.communicate(stdin) - return cmd.returncode, out.decode('utf-8'), err.decode('utf-8') - -diff --git a/src/tests/intg/test_kcm.py b/src/tests/intg/test_kcm.py -index 11f80a1803b4ad9b8e8857bf9a8a244d4816f0a2..1ab2a1837687a6c2cf8676124b42538833550c91 100644 ---- a/src/tests/intg/test_kcm.py -+++ b/src/tests/intg/test_kcm.py -@@ -445,3 +445,25 @@ def test_kcm_sec_kdestroy_nocache(setup_for_kcm_sec, - setup_secrets): - testenv = setup_for_kcm_sec - exercise_subsidiaries(testenv) -+ -+def test_kcm_sec_parallel_klist(setup_for_kcm_sec, -+ setup_secrets): -+ """ -+ Test that parallel operations from a single UID are handled well. -+ Regression test for https://pagure.io/SSSD/sssd/issue/3372 -+ """ -+ testenv = setup_for_kcm_sec -+ -+ testenv.k5kdc.add_principal("alice", "alicepw") -+ out, _, _ = testenv.k5util.kinit("alice", "alicepw") -+ assert out == 0 -+ -+ -+ processes = [] -+ for i in range(0,10): -+ p = testenv.k5util.spawn_in_env(['klist', '-A']) -+ processes.append(p) -+ -+ for p in processes: -+ rc = p.wait() -+ assert rc == 0 --- -2.9.4 - diff --git a/SOURCES/0138-ipa-filter-IPA-users-from-extdom-lookups-by-certific.patch b/SOURCES/0138-ipa-filter-IPA-users-from-extdom-lookups-by-certific.patch deleted file mode 100644 index f9689ea..0000000 --- a/SOURCES/0138-ipa-filter-IPA-users-from-extdom-lookups-by-certific.patch +++ /dev/null @@ -1,115 +0,0 @@ -From e3b29c9f95d5a5ff007000b254143c337ef0b0dc Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 19 May 2017 12:52:47 +0200 -Subject: [PATCH 138/138] ipa: filter IPA users from extdom lookups by - certificate -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The extdom lookup by certificate will return the names of all matching -users, both from the IPA and trusted domains. The IPA users from the -list should not be looked up via the extdom plugin because they are -already lookup up directly. Additionally the lookup might fail and cause -an error which might prevent that the remaining users from the list are -looked up. - -Resolves https://pagure.io/SSSD/sssd/issue/3407 - -Reviewed-by: Pavel Březina -(cherry picked from commit eb7095099b2dd0afb1d028dbc15d8c5a897d90f8) ---- - src/providers/ipa/ipa_s2n_exop.c | 35 ++++++++++++++++++++++++++++++----- - 1 file changed, 30 insertions(+), 5 deletions(-) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index f5f4401f86615dc7f81f844e1096ad43e965c384..15904e0197919c34b1bce58b4bd2c070f99b67a7 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -792,6 +792,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, - char **name_list = NULL; - ber_len_t ber_len; - char *fq_name = NULL; -+ struct sss_domain_info *root_domain = NULL; - - if (retoid == NULL || retdata == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "Missing OID or data.\n"); -@@ -965,6 +966,8 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, - goto done; - } - -+ root_domain = get_domains_head(dom); -+ - while (ber_peek_tag(ber, &ber_len) == LBER_SEQUENCE) { - tag = ber_scanf(ber, "{aa}", &domain_name, &name); - if (tag == LBER_ERROR) { -@@ -983,7 +986,12 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, - DEBUG(SSSDBG_TRACE_ALL, "[%s][%s][%s].\n", domain_name, name, - fq_name); - -- ret = add_string_to_list(attrs, fq_name, &name_list); -+ if (strcasecmp(root_domain->name, domain_name) != 0) { -+ ret = add_string_to_list(attrs, fq_name, &name_list); -+ } else { -+ DEBUG(SSSDBG_TRACE_ALL, -+ "[%s] from root domain, skipping.\n", fq_name); -+ } - ber_memfree(domain_name); - ber_memfree(name); - talloc_free(fq_name); -@@ -1228,7 +1236,7 @@ static errno_t ipa_s2n_get_list_step(struct tevent_req *req) - - break; - default: -- DEBUG(SSSDBG_OP_FAILURE, "Unexpected inoput type [%d].\n", -+ DEBUG(SSSDBG_OP_FAILURE, "Unexpected input type [%d].\n", - state->req_input.type); - return EINVAL; - } -@@ -1247,9 +1255,10 @@ static errno_t ipa_s2n_get_list_step(struct tevent_req *req) - - if (state->req_input.type == REQ_INP_NAME - && state->req_input.inp.name != NULL) { -- DEBUG(SSSDBG_TRACE_FUNC, "Sending request_type: [%s] for group [%s].\n", -- ipa_s2n_reqtype2str(state->request_type), -- state->list[state->list_idx]); -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Sending request_type: [%s] for object [%s].\n", -+ ipa_s2n_reqtype2str(state->request_type), -+ state->list[state->list_idx]); - } - - subreq = ipa_s2n_exop_send(state, state->ev, state->sh, need_v1, -@@ -1886,6 +1895,13 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) - - if (state->simple_attrs->response_type == RESP_NAME_LIST - && state->req_input->type == REQ_INP_CERT) { -+ -+ if (state->simple_attrs->name_list == NULL) { -+ /* No results from sub-domains, nothing to do */ -+ ret = EOK; -+ goto done; -+ } -+ - state->mapped_attrs = sysdb_new_attrs(state); - if (state->mapped_attrs == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); -@@ -2640,6 +2656,15 @@ static void ipa_s2n_get_list_done(struct tevent_req *subreq) - return; - } - -+ if (state->attrs == NULL) { -+ /* If this is a request by certificate we are done */ -+ if (state->req_input->type == REQ_INP_CERT) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, EINVAL); -+ } -+ } -+ - ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR, - &sid_str); - if (ret == ENOENT) { --- -2.9.4 - diff --git a/SOURCES/0139-krb5-accept-changed-principal-if-krb5_canonicalize-T.patch b/SOURCES/0139-krb5-accept-changed-principal-if-krb5_canonicalize-T.patch deleted file mode 100644 index 259a343..0000000 --- a/SOURCES/0139-krb5-accept-changed-principal-if-krb5_canonicalize-T.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 04a1802749b6ebf72730357b06bf8cabe09ebb01 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 24 May 2017 16:10:26 +0200 -Subject: [PATCH 139/141] krb5: accept changed principal if - krb5_canonicalize=True - -Currently SSSD accepts significant changes in the principal only if -krb5_use_enterprise_principal=True. But canonicalization can lead to -similar changes so they should be accepted in this case as well. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3408 - -Reviewed-by: Robbie Harwood -(cherry picked from commit ca95807a9060e454ee68f6f30558d6f7ee968c39) ---- - src/providers/krb5/krb5_auth.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c -index 894bd41bde031ac33187bfa3b14202e9429a9198..03ea9d88cac67919d4b9ba3a1cf2efa208662195 100644 ---- a/src/providers/krb5/krb5_auth.c -+++ b/src/providers/krb5/krb5_auth.c -@@ -829,6 +829,7 @@ static void krb5_auth_done(struct tevent_req *subreq) - char *renew_interval_str; - time_t renew_interval_time = 0; - bool use_enterprise_principal; -+ bool canonicalize; - - ret = handle_child_recv(subreq, pd, &buf, &len); - talloc_zfree(subreq); -@@ -908,6 +909,7 @@ static void krb5_auth_done(struct tevent_req *subreq) - - use_enterprise_principal = dp_opt_get_bool(kr->krb5_ctx->opts, - KRB5_USE_ENTERPRISE_PRINCIPAL); -+ canonicalize = dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_CANONICALIZE); - - /* Check if the cases of our upn are correct and update it if needed. - * Fail if the upn differs by more than just the case for non-enterprise -@@ -915,6 +917,7 @@ static void krb5_auth_done(struct tevent_req *subreq) - if (res->correct_upn != NULL && - strcmp(kr->upn, res->correct_upn) != 0) { - if (strcasecmp(kr->upn, res->correct_upn) == 0 || -+ canonicalize == true || - use_enterprise_principal == true) { - talloc_free(kr->upn); - kr->upn = talloc_strdup(kr, res->correct_upn); --- -2.9.4 - diff --git a/SOURCES/0140-IPA-Avoid-using-uninitialized-ret-value-when-skippin.patch b/SOURCES/0140-IPA-Avoid-using-uninitialized-ret-value-when-skippin.patch deleted file mode 100644 index e6a08b1..0000000 --- a/SOURCES/0140-IPA-Avoid-using-uninitialized-ret-value-when-skippin.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 4986fe8b68a3e14a30e8091353bf0679eb3c5e55 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 24 May 2017 21:24:20 +0200 -Subject: [PATCH 140/141] IPA: Avoid using uninitialized ret value when - skipping entries from the joined domain -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 3e3034199b44e01899ec7ba8152fef3738a0e093) ---- - src/providers/ipa/ipa_s2n_exop.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index 15904e0197919c34b1bce58b4bd2c070f99b67a7..3f5f9859554f0b98ecd3fdad31fd66274c5707b0 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -991,6 +991,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, - } else { - DEBUG(SSSDBG_TRACE_ALL, - "[%s] from root domain, skipping.\n", fq_name); -+ ret = EOK; /* Free resources and continue in the loop */ - } - ber_memfree(domain_name); - ber_memfree(name); --- -2.9.4 - diff --git a/SOURCES/0141-IPA-Return-from-function-after-marking-a-request-as-.patch b/SOURCES/0141-IPA-Return-from-function-after-marking-a-request-as-.patch deleted file mode 100644 index 1da145d..0000000 --- a/SOURCES/0141-IPA-Return-from-function-after-marking-a-request-as-.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 2ae1485566cbd2b095935aaf7e851d12d2de4513 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 24 May 2017 21:26:22 +0200 -Subject: [PATCH 141/141] IPA: Return from function after marking a request as - finished -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit eb404bcdbbff7e080a93d816e17b8cec04f79fc4) ---- - src/providers/ipa/ipa_s2n_exop.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index 3f5f9859554f0b98ecd3fdad31fd66274c5707b0..39ed17cbf0e8c523212084197e9f2963fed88dc8 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -2664,6 +2664,7 @@ static void ipa_s2n_get_list_done(struct tevent_req *subreq) - } else { - tevent_req_error(req, EINVAL); - } -+ return; - } - - ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR, --- -2.9.4 - diff --git a/SOURCES/0142-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch b/SOURCES/0142-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch deleted file mode 100644 index 4669a77..0000000 --- a/SOURCES/0142-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch +++ /dev/null @@ -1,175 +0,0 @@ -From c7c087b5485d50e8689d31fd9d52af935ae398be Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Sun, 9 Apr 2017 20:50:47 +0200 -Subject: [PATCH 142/142] HBAC: Do not rely on originalMemberOf, use the sysdb - memberof links instead - -The IPA HBAC code used to read the group members from the -originalMemberOf attribute value for performance reasons. However, -especially on IPA clients trusting an AD domain, the originalMemberOf -attribute value is often not synchronized correctly. - -Instead of going through the work of maintaining both member/memberOf -and originalMemberOf, let's just do an ASQ search for the group names of -the groups the user is a member of in the cache and read their -SYSBD_NAME attribute. - -To avoid clashing between similarly-named groups in IPA and in AD, we -look at the container of the group. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3382 - -Reviewed-by: Sumit Bose -(cherry picked from commit c92e49144978ad3b6c9fffa8803ebdad8f6f5b18) ---- - src/providers/ipa/ipa_hbac_common.c | 97 +++++++++++++++++++++++++------------ - 1 file changed, 67 insertions(+), 30 deletions(-) - -diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c -index b99b75d322930f16412f6abd4cdf0d7e0b59c32c..ba677965a3eb68a54baf99b1875bca2acbb76c99 100644 ---- a/src/providers/ipa/ipa_hbac_common.c -+++ b/src/providers/ipa/ipa_hbac_common.c -@@ -507,15 +507,15 @@ hbac_eval_user_element(TALLOC_CTX *mem_ctx, - struct hbac_request_element **user_element) - { - errno_t ret; -- unsigned int i; - unsigned int num_groups = 0; - TALLOC_CTX *tmp_ctx; -- const char *member_dn; - struct hbac_request_element *users; -- struct ldb_message *msg; -- struct ldb_message_element *el; -- const char *attrs[] = { SYSDB_ORIG_MEMBEROF, NULL }; - char *shortname; -+ const char *fqgroupname = NULL; -+ struct sss_domain_info *ipa_domain; -+ struct ldb_dn *ipa_groups_basedn; -+ struct ldb_result *res; -+ int exp_comp; - - tmp_ctx = talloc_new(mem_ctx); - if (tmp_ctx == NULL) return ENOMEM; -@@ -533,56 +533,93 @@ hbac_eval_user_element(TALLOC_CTX *mem_ctx, - } - users->name = talloc_steal(users, shortname); - -- /* Read the originalMemberOf attribute -- * This will give us the list of both POSIX and -- * non-POSIX groups that this user belongs to. -+ ipa_domain = get_domains_head(domain); -+ if (ipa_domain == NULL) { -+ ret = EINVAL; -+ goto done; -+ } -+ -+ ipa_groups_basedn = ldb_dn_new_fmt(tmp_ctx, sysdb_ctx_get_ldb(domain->sysdb), -+ SYSDB_TMPL_GROUP_BASE, ipa_domain->name); -+ if (ipa_groups_basedn == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ /* +1 because there will be a RDN preceding the base DN */ -+ exp_comp = ldb_dn_get_comp_num(ipa_groups_basedn) + 1; -+ -+ /* -+ * Get all the groups the user is a member of. -+ * This includes both POSIX and non-POSIX groups. - */ -- ret = sysdb_search_user_by_name(tmp_ctx, domain, username, -- attrs, &msg); -+ ret = sysdb_initgroups(tmp_ctx, domain, username, &res); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, -- "Could not determine user memberships for [%s]\n", -- users->name); -+ "sysdb_asq_search failed [%d]: %s\n", ret, sss_strerror(ret)); - goto done; - } - -- el = ldb_msg_find_element(msg, SYSDB_ORIG_MEMBEROF); -- if (el == NULL || el->num_values == 0) { -+ if (res->count == 0) { -+ /* This should not happen at this point */ -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "User [%s] not found in cache.\n", username); -+ ret = ENOENT; -+ goto done; -+ } else if (res->count == 1) { -+ /* The first item is the user entry */ - DEBUG(SSSDBG_TRACE_LIBS, "No groups for [%s]\n", users->name); - ret = create_empty_grouplist(users); - goto done; - } - DEBUG(SSSDBG_TRACE_LIBS, -- "[%d] groups for [%s]\n", el->num_values, users->name); -+ "[%u] groups for [%s]\n", res->count - 1, username); - -- users->groups = talloc_array(users, const char *, el->num_values + 1); -+ /* This also includes the sentinel, b/c we'll skip the user entry below */ -+ users->groups = talloc_array(users, const char *, res->count); - if (users->groups == NULL) { - ret = ENOMEM; - goto done; - } - -- for (i = 0; i < el->num_values; i++) { -- member_dn = (const char *)el->values[i].data; -+ /* Start counting from 1 to exclude the user entry */ -+ for (size_t i = 1; i < res->count; i++) { -+ /* Only groups from the IPA domain can be referenced from HBAC rules. To -+ * avoid evaluating groups which might even have the same name, but come -+ * from a trusted domain, we first copy the DN to a temporary one.. -+ */ -+ if (ldb_dn_get_comp_num(res->msgs[i]->dn) != exp_comp -+ || ldb_dn_compare_base(ipa_groups_basedn, -+ res->msgs[i]->dn) != 0) { -+ DEBUG(SSSDBG_FUNC_DATA, -+ "Skipping non-IPA group %s\n", -+ ldb_dn_get_linearized(res->msgs[i]->dn)); -+ continue; -+ } - -- ret = get_ipa_groupname(users->groups, domain->sysdb, member_dn, -- &users->groups[num_groups]); -- if (ret != EOK && ret != ERR_UNEXPECTED_ENTRY_TYPE) { -+ fqgroupname = ldb_msg_find_attr_as_string(res->msgs[i], SYSDB_NAME, NULL); -+ if (fqgroupname == NULL) { - DEBUG(SSSDBG_MINOR_FAILURE, -- "Skipping malformed entry [%s]\n", member_dn); -+ "Skipping malformed entry [%s]\n", -+ ldb_dn_get_linearized(res->msgs[i]->dn)); - continue; -- } else if (ret == EOK) { -- DEBUG(SSSDBG_TRACE_LIBS, "Added group [%s] for user [%s]\n", -- users->groups[num_groups], users->name); -- num_groups++; -+ } -+ -+ ret = sss_parse_internal_fqname(tmp_ctx, fqgroupname, -+ &shortname, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "Malformed name %s, skipping!\n", fqgroupname); - continue; - } -- /* Skip entries that are not groups */ -- DEBUG(SSSDBG_TRACE_INTERNAL, -- "Skipping non-group memberOf [%s]\n", member_dn); -+ -+ users->groups[num_groups] = talloc_steal(users->groups, shortname); -+ DEBUG(SSSDBG_TRACE_LIBS, "Added group [%s] for user [%s]\n", -+ users->groups[num_groups], users->name); -+ num_groups++; - } - users->groups[num_groups] = NULL; - -- if (num_groups < el->num_values) { -+ if (num_groups < (res->count - 1)) { - /* Shrink the array memory */ - users->groups = talloc_realloc(users, users->groups, const char *, - num_groups+1); --- -2.9.4 - diff --git a/SOURCES/0143-VALIDATORS-Add-subdomain-section.patch b/SOURCES/0143-VALIDATORS-Add-subdomain-section.patch deleted file mode 100644 index 8b1c3c5..0000000 --- a/SOURCES/0143-VALIDATORS-Add-subdomain-section.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 270121098caff2496da73795fe586ff734ae1e56 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 4 Apr 2017 18:01:02 +0200 -Subject: [PATCH 143/152] VALIDATORS: Add subdomain section -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add separate rule for subdomain sections. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3356 - -Reviewed-by: Lukáš Slebodník ---- - src/config/cfg_rules.ini | 17 ++++++++++++++++- - 1 file changed, 16 insertions(+), 1 deletion(-) - -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index e47ff33242d6a9e5979fe0eb8eea14c2af28685a..4b30e8fc43b50844023e7fffa607a59530a302f0 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -11,7 +11,8 @@ section = ifp - section = secrets - section = kcm - section_re = ^secrets/users/[0-9]\+$ --section_re = ^domain/.*$ -+section_re = ^domain/[^/\@]\+$ -+section_re = ^domain/[^/\@]\+/[^/\@]\+$ - section_re = ^application/.*$ - - [rule/allowed_sssd_options] -@@ -698,3 +699,17 @@ validator = ini_allowed_options - section_re = ^application/.*$ - - option = inherit_from -+ -+[rule/allowed_subdomain_options] -+validator = ini_allowed_options -+section_re = ^domain/[^/\@]\+/[^/\@]\+$ -+ -+option = ldap_search_base -+option = ldap_user_search_base -+option = ldap_group_search_base -+option = ldap_netgroup_search_base -+option = ldap_service_search_base -+option = ad_server -+option = ad_backup_server -+option = ad_site -+option = use_fully_qualified_names --- -2.9.4 - diff --git a/SOURCES/0144-VALIDATORS-Remove-application-section-domain.patch b/SOURCES/0144-VALIDATORS-Remove-application-section-domain.patch deleted file mode 100644 index d644b35..0000000 --- a/SOURCES/0144-VALIDATORS-Remove-application-section-domain.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 39864f9ce41ce892fe3cafb769584173299f49f7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 4 Apr 2017 19:07:12 +0200 -Subject: [PATCH 144/152] VALIDATORS: Remove application section domain -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Application domains can use the same options as normal domains section -with one more additional option. - -We could either duplicate all options from the domain section also in -the application domain section + add the one additional option or -add this one option to the domain section even though it is not meant -to be used there to avoid duplication of all domain options in the -rule for application section. - -It would be could to enhance the validators in libini to allow -something like 'include' section in order to avoid this issue -in the future. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3356 - -Reviewed-by: Lukáš Slebodník ---- - src/config/cfg_rules.ini | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 4b30e8fc43b50844023e7fffa607a59530a302f0..a30fe57e262716abeb2d2af9c3add326122ee4ca 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -694,10 +694,7 @@ option = ldap_user_uid_number - option = ldap_user_uuid - option = ldap_use_tokengroups - --[rule/allowed_application_options] --validator = ini_allowed_options --section_re = ^application/.*$ -- -+# For application domains - option = inherit_from - - [rule/allowed_subdomain_options] --- -2.9.4 - diff --git a/SOURCES/0145-VALIDATORS-Escape-special-regex-chars.patch b/SOURCES/0145-VALIDATORS-Escape-special-regex-chars.patch deleted file mode 100644 index d80f3cf..0000000 --- a/SOURCES/0145-VALIDATORS-Escape-special-regex-chars.patch +++ /dev/null @@ -1,35 +0,0 @@ -From fc6bffc8523e6decf4656182f8caf72236e45c3d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 4 Apr 2017 20:06:40 +0200 -Subject: [PATCH 145/152] VALIDATORS: Escape special regex chars -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The rule allowed_domain_options did not work because -of bad regex. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3356 - -Reviewed-by: Lukáš Slebodník ---- - src/config/cfg_rules.ini | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index a30fe57e262716abeb2d2af9c3add326122ee4ca..628f2e0e0a040bad5128d00d9348aa91170ed704 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -295,7 +295,7 @@ option = responder_idle_timeout - - [rule/allowed_domain_options] - validator = ini_allowed_options --section_re = ^(domain|application)/.*$ -+section_re = ^\(domain\|application\)/.*$ - - option = debug - option = debug_level --- -2.9.4 - diff --git a/SOURCES/0146-TESTS-Add-unit-tests-for-cfg-validation.patch b/SOURCES/0146-TESTS-Add-unit-tests-for-cfg-validation.patch deleted file mode 100644 index dae5f6c..0000000 --- a/SOURCES/0146-TESTS-Add-unit-tests-for-cfg-validation.patch +++ /dev/null @@ -1,328 +0,0 @@ -From 897216b87352e9f80181be6f1a036163c599ba46 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Fri, 26 May 2017 19:58:48 +0200 -Subject: [PATCH 146/152] TESTS: Add unit tests for cfg validation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add infrastructure for unit tests for validators. - -Reviewed-by: Lukáš Slebodník ---- - Makefile.am | 16 +++ - src/tests/cmocka/test_config_check.c | 268 +++++++++++++++++++++++++++++++++++ - 2 files changed, 284 insertions(+) - create mode 100644 src/tests/cmocka/test_config_check.c - -diff --git a/Makefile.am b/Makefile.am -index a6279133b56dcd5bcbd1306ae8f2ce18d90c2c12..503c8cfd795b503f566431c08a56a56147180322 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -252,6 +252,7 @@ if HAVE_CMOCKA - dp_opt_tests \ - responder-get-domains-tests \ - sbus-internal-tests \ -+ config_check-tests \ - sss_sifp-tests \ - test_search_bases \ - test_ldap_auth \ -@@ -2429,6 +2430,21 @@ sbus_internal_tests_LDADD = \ - libsss_debug.la \ - libsss_test_common.la - -+config_check_tests_SOURCES = \ -+ src/tests/cmocka/test_config_check.c \ -+ $(NULL) -+config_check_tests_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(NULL) -+config_check_tests_LDADD = \ -+ $(CMOCKA_LIBS) \ -+ $(POPT_LIBS) \ -+ $(INI_CONFIG_LIBS) \ -+ $(TALLOC_LIBS) \ -+ $(SSSD_INTERNAL_LTLIBS) \ -+ libsss_test_common.la \ -+ $(NULL) -+ - test_find_uid_SOURCES = \ - src/tests/cmocka/test_find_uid.c \ - src/util/find_uid.c \ -diff --git a/src/tests/cmocka/test_config_check.c b/src/tests/cmocka/test_config_check.c -new file mode 100644 -index 0000000000000000000000000000000000000000..8fc0b01f3ef3fe03152efd979a3e96c21ba567cc ---- /dev/null -+++ b/src/tests/cmocka/test_config_check.c -@@ -0,0 +1,268 @@ -+/* -+ Authors: -+ Michal Zidek -+ -+ Copyright (C) 2017 Red Hat -+ -+ Config file validators test -+ -+ 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 -+#include -+ -+#include "util/sss_ini.h" -+#include "tests/cmocka/common_mock.h" -+ -+#ifdef HAVE_LIBINI_CONFIG_V1_3 -+ -+#define RULES_PATH ABS_SRC_DIR"/src/config/cfg_rules.ini" -+ -+struct sss_ini_initdata { -+ char **error_list; -+ struct ref_array *ra_success_list; -+ struct ref_array *ra_error_list; -+ struct ini_cfgobj *sssd_config; -+ struct value_obj *obj; -+ const struct stat *cstat; -+ struct ini_cfgfile *file; -+}; -+ -+void config_check_test_common(const char *cfg_string, -+ size_t num_errors_expected, -+ const char **errors_expected) -+{ -+ struct sss_ini_initdata *init_data; -+ size_t num_errors; -+ char **strs; -+ int ret; -+ TALLOC_CTX *tmp_ctx; -+ -+ tmp_ctx = talloc_new(NULL); -+ assert_non_null(tmp_ctx); -+ -+ init_data = sss_ini_initdata_init(tmp_ctx); -+ -+ ret = ini_config_file_from_mem(discard_const(cfg_string), -+ strlen(cfg_string), -+ &init_data->file); -+ assert_int_equal(ret, EOK); -+ -+ ret = ini_config_create(&(init_data->sssd_config)); -+ assert_int_equal(ret, EOK); -+ -+ ret = ini_config_parse(init_data->file, -+ INI_STOP_ON_ANY, -+ INI_MV1S_OVERWRITE, -+ INI_PARSE_NOWRAP, -+ init_data->sssd_config); -+ assert_int_equal(ret, EOK); -+ -+ ret = sss_ini_call_validators_strs(tmp_ctx, init_data, -+ RULES_PATH, -+ &strs, &num_errors); -+ assert_int_equal(ret, EOK); -+ -+ /* Output from validators */ -+ for (int i = 0; i < num_errors; i++) { -+ /* Keep this printf loop for faster debugging */ -+ printf("%s\n", strs[i]); -+ } -+ -+ for (int i = 0; i < num_errors && i <= num_errors_expected; i++) { -+ assert_string_equal(strs[i], errors_expected[i]); -+ } -+ -+ /* Check if the number of errors is the same */ -+ assert_int_equal(num_errors_expected, num_errors); -+ -+ sss_ini_close_file(init_data); -+ sss_ini_config_destroy(init_data); -+ talloc_free(tmp_ctx); -+} -+ -+void config_check_test_bad_section_name(void **state) -+{ -+ char cfg_str[] = "[sssssssssssssd]"; -+ const char *expected_errors[] = { -+ "[rule/allowed_sections]: Section [sssssssssssssd] is not allowed. " -+ "Check for typos.", -+ }; -+ -+ config_check_test_common(cfg_str, 1, expected_errors); -+} -+ -+void config_check_test_bad_sssd_option_name(void **state) -+{ -+ char cfg_str[] = "[sssd]\n" -+ "debug_leTYPOvel = 10\n"; -+ const char *expected_errors[] = { -+ "[rule/allowed_sssd_options]: Attribute 'debug_leTYPOvel' is not " -+ "allowed in section 'sssd'. Check for typos.", -+ }; -+ -+ config_check_test_common(cfg_str, 1, expected_errors); -+} -+ -+void config_check_test_bad_pam_option_name(void **state) -+{ -+ char cfg_str[] = "[pam]\n" -+ "debug_leTYPOvel = 10\n"; -+ const char *expected_errors[] = { -+ "[rule/allowed_pam_options]: Attribute 'debug_leTYPOvel' is not " -+ "allowed in section 'pam'. Check for typos.", -+ }; -+ -+ config_check_test_common(cfg_str, 1, expected_errors); -+} -+ -+void config_check_test_bad_nss_option_name(void **state) -+{ -+ char cfg_str[] = "[nss]\n" -+ "debug_leTYPOvel = 10\n"; -+ const char *expected_errors[] = { -+ "[rule/allowed_nss_options]: Attribute 'debug_leTYPOvel' is not " -+ "allowed in section 'nss'. Check for typos.", -+ }; -+ -+ config_check_test_common(cfg_str, 1, expected_errors); -+} -+ -+void config_check_test_bad_pac_option_name(void **state) -+{ -+ char cfg_str[] = "[pac]\n" -+ "debug_leTYPOvel = 10\n"; -+ const char *expected_errors[] = { -+ "[rule/allowed_pac_options]: Attribute 'debug_leTYPOvel' is not " -+ "allowed in section 'pac'. Check for typos.", -+ }; -+ -+ config_check_test_common(cfg_str, 1, expected_errors); -+} -+ -+void config_check_test_bad_ifp_option_name(void **state) -+{ -+ char cfg_str[] = "[ifp]\n" -+ "debug_leTYPOvel = 10\n"; -+ const char *expected_errors[] = { -+ "[rule/allowed_ifp_options]: Attribute 'debug_leTYPOvel' is not " -+ "allowed in section 'ifp'. Check for typos.", -+ }; -+ -+ config_check_test_common(cfg_str, 1, expected_errors); -+} -+ -+void config_check_test_bad_domain_option_name(void **state) -+{ -+ char cfg_str[] = "[domain/A.test\n" -+ "debug_leTYPOvel = 10\n"; -+ const char *expected_errors[] = { -+ "[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not " -+ "allowed in section 'domain/A.test'. Check for typos.", -+ }; -+ -+ config_check_test_common(cfg_str, 1, expected_errors); -+} -+ -+void config_check_test_bad_appdomain_option_name(void **state) -+{ -+ char cfg_str[] = "[application/myapp\n" -+ "debug_leTYPOvel = 10\n"; -+ const char *expected_errors[] = { -+ "[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not " -+ "allowed in section 'application/myapp'. Check for typos.", -+ }; -+ -+ config_check_test_common(cfg_str, 1, expected_errors); -+} -+ -+void config_check_test_bad_subdom_option_name(void **state) -+{ -+ char cfg_str[] = "[domain/A.test/B.A.test]\n" -+ "debug_leTYPOvel = 10\n"; -+ const char *expected_errors[] = { -+ "[rule/allowed_sssd_options]: Attribute 'debug_leTYPOvel' is not " -+ "allowed in section 'domain/A.test/B.A.test'. 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" -+ "[pam]\n" -+ "[nss]\n" -+ "[domain/testdom.test]\n" -+ "[domain/testdom.test/testsubdom.testdom.test]\n" -+ "[application/myapp]\n" -+ "[secrets]\n" -+ "[ifp]\n" -+ "[pac]\n"; -+ const char *expected_errors[] = { NULL }; -+ -+ config_check_test_common(cfg_str, 0, expected_errors); -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ poptContext pc; -+ int opt; -+ struct poptOption long_options[] = { -+ POPT_AUTOHELP -+ SSSD_DEBUG_OPTS -+ POPT_TABLEEND -+ }; -+ -+ const struct CMUnitTest tests[] = { -+ cmocka_unit_test(config_check_test_bad_section_name), -+ cmocka_unit_test(config_check_test_bad_sssd_option_name), -+ cmocka_unit_test(config_check_test_bad_pam_option_name), -+ cmocka_unit_test(config_check_test_bad_nss_option_name), -+ cmocka_unit_test(config_check_test_bad_pac_option_name), -+ cmocka_unit_test(config_check_test_bad_ifp_option_name), -+ cmocka_unit_test(config_check_test_good_sections), -+ }; -+ -+ /* Set debug level to invalid value so we can decide if -d 0 was used. */ -+ debug_level = SSSDBG_INVALID; -+ -+ pc = poptGetContext(argv[0], argc, argv, long_options, 0); -+ while ((opt = poptGetNextOpt(pc)) != -1) { -+ switch (opt) { -+ default: -+ fprintf(stderr, "\nInvalid option %s: %s\n\n", -+ poptBadOption(pc, 0), poptStrerror(opt)); -+ poptPrintUsage(pc, stderr, 0); -+ return 1; -+ } -+ } -+ poptFreeContext(pc); -+ -+ DEBUG_CLI_INIT(debug_level); -+ tests_set_cwd(); -+ return cmocka_run_group_tests(tests, NULL, NULL); -+} -+ -+#else /* !HAVE_LIBINI_CONFIG_V1_3 */ -+ -+int main(int argc, const char *argv[]) -+{ -+ fprintf(stderr, "%s requires newer version of libini\n", argv[0]); -+ return 0; -+} -+ -+#endif /* HAVE_LIBINI_CONFIG_V1_3 */ --- -2.9.4 - diff --git a/SOURCES/0147-MAN-Fix-typo-in-trusted-domain-section.patch b/SOURCES/0147-MAN-Fix-typo-in-trusted-domain-section.patch deleted file mode 100644 index 3d015fc..0000000 --- a/SOURCES/0147-MAN-Fix-typo-in-trusted-domain-section.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 8a6087c3b53bbe26cb212e60af74da981529f57d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 30 May 2017 12:05:39 +0200 -Subject: [PATCH 147/152] MAN: Fix typo in trusted domain section -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Lukáš Slebodník ---- - src/man/sssd.conf.5.xml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml -index c4e30396f16c40db37af2f56ac218b6e37201ef7..a35f2807eac8bb89d6cb1dd0a48f738d71a7578f 100644 ---- a/src/man/sssd.conf.5.xml -+++ b/src/man/sssd.conf.5.xml -@@ -2912,7 +2912,7 @@ ldap_user_extra_attrs = phone:telephoneNumber - - Some options used in the domain section can also be used in the - trusted domain section, that is, in a section called -- [domain/DOMAIN_NAME]/TRUSTED_DOMAIN_NAME]. -+ [domain/DOMAIN_NAME/TRUSTED_DOMAIN_NAME]. - Currently supported options in the trusted domain section are: - - ldap_search_base, --- -2.9.4 - diff --git a/SOURCES/0148-VALIDATORS-Change-regex-for-app-domains.patch b/SOURCES/0148-VALIDATORS-Change-regex-for-app-domains.patch deleted file mode 100644 index 3ca41ad..0000000 --- a/SOURCES/0148-VALIDATORS-Change-regex-for-app-domains.patch +++ /dev/null @@ -1,36 +0,0 @@ -From b32bb7226b89777063e4cd49373ce86353abd74c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 30 May 2017 13:17:45 +0200 -Subject: [PATCH 148/152] VALIDATORS: Change regex for app domains -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use the same restrictions for application domains that we use for -normal domain. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3356 - -Reviewed-by: Lukáš Slebodník ---- - src/config/cfg_rules.ini | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 628f2e0e0a040bad5128d00d9348aa91170ed704..2c8c0cb98ed039c374c827775798f61369c1521e 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -13,7 +13,8 @@ section = kcm - section_re = ^secrets/users/[0-9]\+$ - section_re = ^domain/[^/\@]\+$ - section_re = ^domain/[^/\@]\+/[^/\@]\+$ --section_re = ^application/.*$ -+section_re = ^application/[^/\@]\+$ -+ - - [rule/allowed_sssd_options] - validator = ini_allowed_options --- -2.9.4 - diff --git a/SOURCES/0149-VALIDATORS-Detect-inherit_from-in-normal-domain.patch b/SOURCES/0149-VALIDATORS-Detect-inherit_from-in-normal-domain.patch deleted file mode 100644 index b99885a..0000000 --- a/SOURCES/0149-VALIDATORS-Detect-inherit_from-in-normal-domain.patch +++ /dev/null @@ -1,154 +0,0 @@ -From b94b578fac8f94d42fd6fb691438d2dbe5248309 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 31 May 2017 14:21:02 +0200 -Subject: [PATCH 149/152] VALIDATORS: Detect inherit_from in normal domain -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch adds new sssd specific validator. In the future we -can add more checks in it, but currently it only checks if -the option inherit_from is used on normal domain and reports -error if it is. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3356 - -Reviewed-by: Lukáš Slebodník ---- - src/config/cfg_rules.ini | 3 ++ - src/tests/cmocka/test_config_check.c | 22 +++++++++++++++ - src/util/sss_ini.c | 53 +++++++++++++++++++++++++++++++++++- - 3 files changed, 77 insertions(+), 1 deletion(-) - -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 2c8c0cb98ed039c374c827775798f61369c1521e..744446478e5d5489cd86d8e15ce8e178cf5e3a91 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -711,3 +711,6 @@ option = ad_server - option = ad_backup_server - option = ad_site - option = use_fully_qualified_names -+ -+[rule/sssd_checks] -+validator = sssd_checks -diff --git a/src/tests/cmocka/test_config_check.c b/src/tests/cmocka/test_config_check.c -index 8fc0b01f3ef3fe03152efd979a3e96c21ba567cc..bab3226c004fb9495471af7c7d3f6861552d8a86 100644 ---- a/src/tests/cmocka/test_config_check.c -+++ b/src/tests/cmocka/test_config_check.c -@@ -217,6 +217,27 @@ void config_check_test_good_sections(void **state) - config_check_test_common(cfg_str, 0, expected_errors); - } - -+void config_check_test_inherit_from_in_normal_dom(void **state) -+{ -+ char cfg_str[] = "[domain/A.test]\n" -+ "inherit_from = domain\n"; -+ const char *expected_errors[] = { -+ "[rule/sssd_checks]: Attribute 'inherit_from' is not allowed in " -+ "section 'domain/A.test'. Check for typos.", -+ }; -+ -+ config_check_test_common(cfg_str, 1, expected_errors); -+} -+ -+void config_check_test_inherit_from_in_app_dom(void **state) -+{ -+ char cfg_str[] = "[application/A.test]\n" -+ "inherit_from = domain\n"; -+ const char *expected_errors[] = { NULL }; -+ -+ config_check_test_common(cfg_str, 0, expected_errors); -+} -+ - int main(int argc, const char *argv[]) - { - poptContext pc; -@@ -235,6 +256,7 @@ int main(int argc, const char *argv[]) - cmocka_unit_test(config_check_test_bad_pac_option_name), - cmocka_unit_test(config_check_test_bad_ifp_option_name), - cmocka_unit_test(config_check_test_good_sections), -+ cmocka_unit_test(config_check_test_inherit_from_in_normal_dom), - }; - - /* Set debug level to invalid value so we can decide if -d 0 was used. */ -diff --git a/src/util/sss_ini.c b/src/util/sss_ini.c -index e56006c05555d6e0c5e726e83771abce5a72b139..175a4cfaba7ea964aee174e928d5e3c1e81de638 100644 ---- a/src/util/sss_ini.c -+++ b/src/util/sss_ini.c -@@ -561,12 +561,63 @@ error: - } - - #ifdef HAVE_LIBINI_CONFIG_V1_3 -+/* Here we can put custom SSSD specific checks that can not be implemented -+ * using libini validators */ -+static int custom_sssd_checks(const char *rule_name, -+ struct ini_cfgobj *rules_obj, -+ struct ini_cfgobj *config_obj, -+ struct ini_errobj *errobj, -+ void **data) -+{ -+ char **cfg_sections = NULL; -+ int num_cfg_sections; -+ struct value_obj *vo = NULL; -+ char dom_prefix[] = "domain/"; -+ int ret; -+ -+ /* Get all sections in configuration */ -+ cfg_sections = ini_get_section_list(config_obj, &num_cfg_sections, &ret); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ /* Check if a normal domain section (not application domains) has option -+ * inherit_from and report error if it does */ -+ for (int i = 0; i < num_cfg_sections; i++) { -+ if (strncmp(dom_prefix, cfg_sections[i], strlen(dom_prefix)) == 0) { -+ ret = ini_get_config_valueobj(cfg_sections[i], -+ "inherit_from", -+ config_obj, -+ INI_GET_NEXT_VALUE, -+ &vo); -+ if (vo != NULL) { -+ ret = ini_errobj_add_msg(errobj, -+ "Attribute 'inherit_from' is not " -+ "allowed in section '%s'. Check for " -+ "typos.", -+ cfg_sections[i]); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ } -+ } -+ -+ ret = EOK; -+done: -+ ini_free_section_list(cfg_sections); -+ return EOK; -+} -+ - static int sss_ini_call_validators_errobj(struct sss_ini_initdata *data, - const char *rules_path, - struct ini_errobj *errobj) - { - int ret; - struct ini_cfgobj *rules_cfgobj = NULL; -+ struct ini_validator custom_sssd = { "sssd_checks", custom_sssd_checks, -+ NULL }; -+ struct ini_validator *sss_validators[] = { &custom_sssd, NULL }; - - ret = ini_rules_read_from_file(rules_path, &rules_cfgobj); - if (ret != EOK) { -@@ -575,7 +626,7 @@ static int sss_ini_call_validators_errobj(struct sss_ini_initdata *data, - goto done; - } - -- ret = ini_rules_check(rules_cfgobj, data->sssd_config, NULL, errobj); -+ ret = ini_rules_check(rules_cfgobj, data->sssd_config, sss_validators, errobj); - if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, - "ini_rules_check failed %d [%s]\n", ret, strerror(ret)); --- -2.9.4 - diff --git a/SOURCES/0150-VALIDATOR-prevent-duplicite-report-from-subdomain-se.patch b/SOURCES/0150-VALIDATOR-prevent-duplicite-report-from-subdomain-se.patch deleted file mode 100644 index 8ce1bb0..0000000 --- a/SOURCES/0150-VALIDATOR-prevent-duplicite-report-from-subdomain-se.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 03bfcf1746b163fa3fbce9f2741db77064ac84e7 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Wed, 31 May 2017 17:35:27 +0200 -Subject: [PATCH 150/152] VALIDATOR: prevent duplicite report from subdomain - sections -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Issues is subdomain sections e.g. "[domain/A.test/B.A.test]" were -reported twice. - -[rule/allowed_domain_options]: Attribute 'debug_leTYPOvel' is not allowed in section 'domain/A.test/B.A.test'. Check for typos. -[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not allowed in section 'domain/A.test/B.A.test'. Check for typos. - -Reviewed-by: Michal Židek ---- - src/config/cfg_rules.ini | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 744446478e5d5489cd86d8e15ce8e178cf5e3a91..d6506b7c3cee13f7c5400a546deb787e755abc8b 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -296,7 +296,7 @@ option = responder_idle_timeout - - [rule/allowed_domain_options] - validator = ini_allowed_options --section_re = ^\(domain\|application\)/.*$ -+section_re = ^\(domain\|application\)/[^/]\+$ - - option = debug - option = debug_level --- -2.9.4 - diff --git a/SOURCES/0151-test_config_check-Fix-few-issues.patch b/SOURCES/0151-test_config_check-Fix-few-issues.patch deleted file mode 100644 index 9e48ed1..0000000 --- a/SOURCES/0151-test_config_check-Fix-few-issues.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 15f997c22228f4b87a841148bf05c6911107879c Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Wed, 31 May 2017 17:16:47 +0200 -Subject: [PATCH 151/152] test_config_check: Fix few issues -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -* enable few tests -* malformed configuration file due to missing closing ']' -* fix few expected failures -* add few sections into whitelist test -* crash in test if count of expected failures is different then real - value - -[ RUN ] config_check_test_bad_subdom_option_name -[rule/allowed_domain_options]: Attribute 'debug_leTYPOvel' is not allowed in section 'domain/A.test/B.A.test'. Check for typos. -[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not allowed in section 'domain/A.test/B.A.test'. Check for typos. -[ ERROR ] --- Test failed with exception: Segmentation fault(11) - -Reviewed-by: Michal Židek ---- - src/tests/cmocka/test_config_check.c | 14 ++++++++++---- - 1 file changed, 10 insertions(+), 4 deletions(-) - -diff --git a/src/tests/cmocka/test_config_check.c b/src/tests/cmocka/test_config_check.c -index bab3226c004fb9495471af7c7d3f6861552d8a86..0066ebe77e9f174449461caebdb3359380bc19b5 100644 ---- a/src/tests/cmocka/test_config_check.c -+++ b/src/tests/cmocka/test_config_check.c -@@ -81,6 +81,7 @@ void config_check_test_common(const char *cfg_string, - /* Keep this printf loop for faster debugging */ - printf("%s\n", strs[i]); - } -+ assert_int_equal(num_errors, num_errors_expected); - - for (int i = 0; i < num_errors && i <= num_errors_expected; i++) { - assert_string_equal(strs[i], errors_expected[i]); -@@ -167,7 +168,7 @@ void config_check_test_bad_ifp_option_name(void **state) - - void config_check_test_bad_domain_option_name(void **state) - { -- char cfg_str[] = "[domain/A.test\n" -+ char cfg_str[] = "[domain/A.test]\n" - "debug_leTYPOvel = 10\n"; - const char *expected_errors[] = { - "[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not " -@@ -179,10 +180,10 @@ void config_check_test_bad_domain_option_name(void **state) - - void config_check_test_bad_appdomain_option_name(void **state) - { -- char cfg_str[] = "[application/myapp\n" -+ char cfg_str[] = "[application/myapp]\n" - "debug_leTYPOvel = 10\n"; - const char *expected_errors[] = { -- "[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not " -+ "[rule/allowed_domain_options]: Attribute 'debug_leTYPOvel' is not " - "allowed in section 'application/myapp'. Check for typos.", - }; - -@@ -194,7 +195,7 @@ void config_check_test_bad_subdom_option_name(void **state) - char cfg_str[] = "[domain/A.test/B.A.test]\n" - "debug_leTYPOvel = 10\n"; - const char *expected_errors[] = { -- "[rule/allowed_sssd_options]: Attribute 'debug_leTYPOvel' is not " -+ "[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not " - "allowed in section 'domain/A.test/B.A.test'. Check for typos.", - }; - -@@ -210,6 +211,8 @@ void config_check_test_good_sections(void **state) - "[domain/testdom.test/testsubdom.testdom.test]\n" - "[application/myapp]\n" - "[secrets]\n" -+ "[secrets/users/1000]\n" -+ "[ssh]\n" - "[ifp]\n" - "[pac]\n"; - const char *expected_errors[] = { NULL }; -@@ -255,8 +258,11 @@ int main(int argc, const char *argv[]) - cmocka_unit_test(config_check_test_bad_nss_option_name), - cmocka_unit_test(config_check_test_bad_pac_option_name), - 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_good_sections), - cmocka_unit_test(config_check_test_inherit_from_in_normal_dom), -+ cmocka_unit_test(config_check_test_inherit_from_in_app_dom), - }; - - /* Set debug level to invalid value so we can decide if -d 0 was used. */ --- -2.9.4 - diff --git a/SOURCES/0152-KRB5-Fix-access_provider-krb5.patch b/SOURCES/0152-KRB5-Fix-access_provider-krb5.patch deleted file mode 100644 index 89845c7..0000000 --- a/SOURCES/0152-KRB5-Fix-access_provider-krb5.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 3ee575c2852adb9d5a5c0a4616c082afc6779a8e Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Thu, 1 Jun 2017 09:51:31 +0200 -Subject: [PATCH 152/152] KRB5: Fix access_provider=krb5 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The domain type (posix or not) was being sent to the krb5_child always, -but the buffer only had enough space in case of authentication, not -authorization. Bug was introduced in the commit - 861ab44e8148208425b67c4711bc8fade10fd3ed - -This patch makes the buffer one uint32_t unit larger. - -To reproduce, just set up sssd.conf with: - access_provider = krb5 - -Without the patch, you would see messages like: - ==14111== Invalid write of size 2 - ==14111== at 0x4C3041B: memcpy@@GLIBC_2.14 (vg_replace_strmem.c:1018) - ==14111== by 0xE0EE275: safealign_memcpy (util_safealign.h:51) - ==14111== by 0xE0EECB3: create_send_buffer (krb5_child_handler.c:239) - ==14111== by 0xE0EFDDE: handle_child_send (krb5_child_handler.c:529) - ==14111== by 0xE0EDEDD: krb5_access_send (krb5_access.c:149) - ==14111== by 0xE0ED32F: krb5_pam_handler_send (krb5_auth.c:1250) - ==14111== by 0x418868: file_dp_request (dp_request.c:254) - ==14111== by 0x418976: dp_req_send (dp_request.c:300) - ==14111== by 0x41C25F: dp_pam_handler (dp_target_auth.c:219) - ==14111== by 0x52B3456: sbus_request_invoke_or_finish (sssd_dbus_request.c:71) - ==14111== by 0x52B0F37: sbus_message_handler_got_caller_id (sssd_dbus_interface.c:1048) - ==14111== by 0x923C923: tevent_common_loop_immediate (tevent_immediate.c:135) - ==14111== Address 0x126ab506 is 150 bytes inside a block of size 151 alloc'd - ==14111== at 0x4C2BBAD: malloc (vg_replace_malloc.c:299) - ==14111== by 0x944D7F4: __talloc_with_prefix (talloc.c:698) - ==14111== by 0x944D7F4: __talloc (talloc.c:739) - ==14111== by 0x944D7F4: _talloc_named_const (talloc.c:896) - ==14111== by 0x944D7F4: talloc_named_const (talloc.c:1675) - ==14111== by 0xE0EE7B6: create_send_buffer (krb5_child_handler.c:185) - ==14111== by 0xE0EFDDE: handle_child_send (krb5_child_handler.c:529) - ==14111== by 0xE0EDEDD: krb5_access_send (krb5_access.c:149) - ==14111== by 0xE0ED32F: krb5_pam_handler_send (krb5_auth.c:1250) - ==14111== by 0x418868: file_dp_request (dp_request.c:254) - ==14111== by 0x418976: dp_req_send (dp_request.c:300) - ==14111== by 0x41C25F: dp_pam_handler (dp_target_auth.c:219) - ==14111== by 0x52B3456: sbus_request_invoke_or_finish (sssd_dbus_request.c:71) - ==14111== by 0x52B0F37: sbus_message_handler_got_caller_id (sssd_dbus_interface.c:1048) - ==14111== by 0x923C923: tevent_common_loop_immediate (tevent_immediate.c:135) - -Resolves: -https://pagure.io/SSSD/sssd/issue/3418 - -Reviewed-by: Lukáš Slebodník ---- - src/providers/krb5/krb5_child_handler.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c -index 87e79a06e917aadb622455bccfc2e9c6769f70c2..11ac867e62d2ff96b827cf6d4ff341fc8ff0a286 100644 ---- a/src/providers/krb5/krb5_child_handler.c -+++ b/src/providers/krb5/krb5_child_handler.c -@@ -156,14 +156,14 @@ static errno_t create_send_buffer(struct krb5child_req *kr, - return ENOMEM; - } - -- buf->size = 8*sizeof(uint32_t) + strlen(kr->upn); -+ buf->size = 9*sizeof(uint32_t) + strlen(kr->upn); - - if (kr->pd->cmd == SSS_PAM_AUTHENTICATE || - kr->pd->cmd == SSS_PAM_PREAUTH || - kr->pd->cmd == SSS_CMD_RENEW || - kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || - kr->pd->cmd == SSS_PAM_CHAUTHTOK) { -- buf->size += 5*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + -+ buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + - sss_authtok_get_size(kr->pd->authtok); - - buf->size += sizeof(uint32_t); --- -2.9.4 - diff --git a/SOURCES/0153-BUILD-Improve-error-messages-for-optional-dependenci.patch b/SOURCES/0153-BUILD-Improve-error-messages-for-optional-dependenci.patch deleted file mode 100644 index e06105d..0000000 --- a/SOURCES/0153-BUILD-Improve-error-messages-for-optional-dependenci.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 9581287c1b5e13a38182af12328ace781957a118 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Tue, 30 May 2017 14:40:07 +0200 -Subject: [PATCH 153/160] BUILD: Improve error messages for optional - dependencies - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 8ccc9b7c317cf5ee8f295b38bfc4c2b7d551f8f1) ---- - configure.ac | 2 +- - contrib/sssd.spec.in | 6 +++++- - src/external/libcurl.m4 | 6 +++++- - src/external/libjansson.m4 | 5 +++-- - 4 files changed, 14 insertions(+), 5 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 80d8ea9ff5785b0d76edbb04f454d0dd8c8a1e6d..e8fe1d47e1803cc570295cf6512a3363e63c51c5 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -197,7 +197,6 @@ m4_include([src/external/service.m4]) - - if test x$with_secrets = xyes; then - m4_include([src/external/libhttp_parser.m4]) -- m4_include([src/external/libjansson.m4]) - fi - - if test x$with_kcm = xyes; then -@@ -206,6 +205,7 @@ fi - - if test x$with_kcm = xyes -o x$with_secrets = xyes; then - m4_include([src/external/libcurl.m4]) -+ m4_include([src/external/libjansson.m4]) - fi - - # This variable is defined by external/libcurl.m4, but conditionals -diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in -index 39a974edebba3dbcd7625d1729b4a7330eaa8a27..b19702d091862e25bea352901b85406ccda1db65 100644 ---- a/contrib/sssd.spec.in -+++ b/contrib/sssd.spec.in -@@ -228,10 +228,14 @@ BuildRequires: systemtap-sdt-devel - %endif - %if (0%{?with_secrets} == 1) - BuildRequires: http-parser-devel --BuildRequires: jansson-devel - %endif -+%if (0%{?with_kcm} == 1) - BuildRequires: libuuid-devel -+%endif -+%if (0%{?with_secrets} == 1 || 0%{?with_kcm} == 1) -+BuildRequires: jansson-devel - BuildRequires: libcurl-devel -+%endif - - %description - Provides a set of daemons to manage access to remote directories and -diff --git a/src/external/libcurl.m4 b/src/external/libcurl.m4 -index 42be308cd1e4b04e736daf887be9b75ea92db80e..94cea9ebe40f07c18452b8c2faf82e81e1dc766b 100644 ---- a/src/external/libcurl.m4 -+++ b/src/external/libcurl.m4 -@@ -1,5 +1,9 @@ - PKG_CHECK_MODULES([CURL], [libcurl], [found_libcurl=yes], -- [AC_MSG_ERROR([The libcurl development library was not found.])]) -+ [AC_MSG_ERROR([The libcurl development library was not found. -+You must have the header file curl/curl.h installed to build sssd -+with secrets and KCM responder. If you want to build sssd without these -+responders then specify --without-secrets --without-kcm when running configure. -+])]) - - AS_IF([test x"$found_libcurl" = xyes], - CFLAGS="$CFLAGS $CURL_CFLAGS" -diff --git a/src/external/libjansson.m4 b/src/external/libjansson.m4 -index 48a4a5fd8df4ac41312a596b5ebd5de7474e75f1..d87769848558efdd32325e01d8d222bb517b4c45 100644 ---- a/src/external/libjansson.m4 -+++ b/src/external/libjansson.m4 -@@ -13,5 +13,6 @@ AS_IF([test x"$found_jansson" != xyes], - [-L$sss_extra_libdir -ljanson])], - [AC_MSG_ERROR([ - You must have the header file jansson.h installed to build sssd --with secrets responder. If you want to build sssd without secret responder --then specify --without-secrets when running configure.])])]) -+with secrets and KCM responder. If you want to build sssd without these -+responders then specify --without-secrets --without-kcm when running configure. -+])])]) --- -2.9.4 - diff --git a/SOURCES/0154-RESPONDER_COMMON-update-certmaps-in-responders.patch b/SOURCES/0154-RESPONDER_COMMON-update-certmaps-in-responders.patch deleted file mode 100644 index 0b1ddaa..0000000 --- a/SOURCES/0154-RESPONDER_COMMON-update-certmaps-in-responders.patch +++ /dev/null @@ -1,77 +0,0 @@ -From d363bd0f829fa7af5f96c2b07b975b7b2c5fdcfa Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 2 May 2017 15:25:10 +0200 -Subject: [PATCH 154/160] RESPONDER_COMMON: update certmaps in responders -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Make certificate mapping data available to the responders. - -Related to https://pagure.io/SSSD/sssd/issue/3395 - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 749963195393efa3a4f9b168dd02fbcc68976ba3) ---- - src/confdb/confdb.h | 3 +++ - src/responder/common/responder_get_domains.c | 23 +++++++++++++++++++++++ - 2 files changed, 26 insertions(+) - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index 8719c239362b371fcdb1b78956bcddde871f141b..797353141edcccbf3341d161ca598c99492e54fe 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -351,6 +351,9 @@ struct sss_domain_info { - char *forest; - struct sss_domain_info *forest_root; - const char **upn_suffixes; -+ -+ struct certmap_info **certmaps; -+ bool user_name_hint; - }; - - /** -diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c -index 8c90b7773e248e1dd6d846c5050e1931fc50c786..155631676d9449f69865919e1b74ee9399607c27 100644 ---- a/src/responder/common/responder_get_domains.c -+++ b/src/responder/common/responder_get_domains.c -@@ -224,6 +224,26 @@ immediately: - return req; - } - -+static void sss_resp_update_certmaps(struct resp_ctx *rctx) -+{ -+ int ret; -+ struct certmap_info **certmaps; -+ bool user_name_hint; -+ struct sss_domain_info *dom; -+ -+ for (dom = rctx->domains; dom != NULL; dom = dom->next) { -+ ret = sysdb_get_certmap(dom, dom->sysdb, &certmaps, &user_name_hint); -+ if (ret == EOK) { -+ dom->user_name_hint = user_name_hint; -+ talloc_free(dom->certmaps); -+ dom->certmaps = certmaps; -+ } else { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_get_certmap failed for domain [%s].\n", dom->name); -+ } -+ } -+} -+ - static void - sss_dp_get_domains_process(struct tevent_req *subreq) - { -@@ -267,6 +287,9 @@ sss_dp_get_domains_process(struct tevent_req *subreq) - ret, sss_strerror(ret)); - goto fail; - } -+ -+ sss_resp_update_certmaps(state->rctx); -+ - tevent_req_done(req); - return; - } --- -2.9.4 - diff --git a/SOURCES/0155-tests-fix-test_pam_preauth_cert_no_logon_name.patch b/SOURCES/0155-tests-fix-test_pam_preauth_cert_no_logon_name.patch deleted file mode 100644 index dc6a41c..0000000 --- a/SOURCES/0155-tests-fix-test_pam_preauth_cert_no_logon_name.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 7487682e505735f2143ccecfc5e7e0fc2dac37f2 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 8 May 2017 15:28:20 +0200 -Subject: [PATCH 155/160] tests: fix test_pam_preauth_cert_no_logon_name() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Currently a name is provided for test_pam_preauth_cert_no_logon_name() -so it is not a no-logon-name test. This patch removes the name and adds -the now missing mocked reply manually. - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 89ff140d7ab92fce52d6730a7d27c8d73c7d9e4a) ---- - src/tests/cmocka/test_pam_srv.c | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c -index 4d351a3707d2a49604595b728fff7705560c871a..35afbdd81d004236885ee80914771ccb4b8acff4 100644 ---- a/src/tests/cmocka/test_pam_srv.c -+++ b/src/tests/cmocka/test_pam_srv.c -@@ -1873,10 +1873,14 @@ void test_pam_preauth_cert_no_logon_name(void **state) - * Since there is a matching user the upcoming lookup by name will find - * the user entry. But since we force the lookup by name to go to the - * backend to make sure the group-membership data is up to date the -- * backend response has to be mocked twice and the second argument of -- * mock_input_pam_cert cannot be NULL but must match the user name. */ -- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, -+ * backend response has to be mocked twice. -+ * Additionally sss_parse_inp_recv() must be mocked because the cache -+ * request will be done with the username found by the certificate -+ * lookup. */ -+ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, - test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); -+ mock_account_recv_simple(); -+ mock_parse_inp("pamuser", NULL, EOK); - - will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); - will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); --- -2.9.4 - diff --git a/SOURCES/0156-pam_sss-add-support-for-SSS_PAM_CERT_INFO_WITH_HINT.patch b/SOURCES/0156-pam_sss-add-support-for-SSS_PAM_CERT_INFO_WITH_HINT.patch deleted file mode 100644 index 94c6f8e..0000000 --- a/SOURCES/0156-pam_sss-add-support-for-SSS_PAM_CERT_INFO_WITH_HINT.patch +++ /dev/null @@ -1,258 +0,0 @@ -From 19cb2e2d826dc4e3c938c5a6b51a03338e80fa9e Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 8 May 2017 16:01:26 +0200 -Subject: [PATCH 156/160] pam_sss: add support for SSS_PAM_CERT_INFO_WITH_HINT -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The new response type SSS_PAM_CERT_INFO_WITH_HINT is equivalent to -SSS_PAM_CERT_INFO but tells pam_sss to prompt for an option user name as -well. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3395 - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit a192a1d72e92dae3e71e062b333e51a5095a0395) ---- - src/sss_client/pam_message.h | 1 + - src/sss_client/pam_sss.c | 129 ++++++++++++++++++++++++++++++++++++++----- - src/sss_client/sss_cli.h | 11 +++- - 3 files changed, 127 insertions(+), 14 deletions(-) - -diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h -index 3f4a770ac08ee416ead2f215ab873e8eb277c9eb..f215392f6879f01a0ca12abc8807bac5fc1f1cbb 100644 ---- a/src/sss_client/pam_message.h -+++ b/src/sss_client/pam_message.h -@@ -63,6 +63,7 @@ struct pam_items { - char *token_name; - char *module_name; - char *key_id; -+ bool user_name_hint; - }; - - int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer); -diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c -index db0dcb9de7b893850bcea96a9cdf76dc0b36dcee..1c06079967e3d9076d537c3de8aba93e13f76d09 100644 ---- a/src/sss_client/pam_sss.c -+++ b/src/sss_client/pam_sss.c -@@ -982,6 +982,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, - - break; - case SSS_PAM_CERT_INFO: -+ case SSS_PAM_CERT_INFO_WITH_HINT: - if (buf[p + (len - 1)] != '\0') { - D(("cert info does not end with \\0.")); - break; -@@ -994,7 +995,19 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, - break; - } - -- if (pi->pam_user == NULL || *(pi->pam_user) == '\0') { -+ if (type == SSS_PAM_CERT_INFO && pi->cert_user == '\0') { -+ D(("Invalid CERT message")); -+ break; -+ } -+ -+ if (type == SSS_PAM_CERT_INFO_WITH_HINT) { -+ pi->user_name_hint = true; -+ } else { -+ pi->user_name_hint = false; -+ } -+ -+ if ((pi->pam_user == NULL || *(pi->pam_user) == '\0') -+ && pi->cert_user != '\0') { - ret = pam_set_item(pamh, PAM_USER, pi->cert_user); - if (ret != PAM_SUCCESS) { - D(("Failed to set PAM_USER during " -@@ -1469,7 +1482,7 @@ done: - return ret; - } - --#define SC_PROMPT_FMT "PIN for %s for user %s" -+#define SC_PROMPT_FMT "PIN for %s" - - static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) - { -@@ -1478,32 +1491,108 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) - char *prompt; - size_t size; - size_t needed_size; -+ const struct pam_conv *conv; -+ const struct pam_message *mesg[2] = { NULL, NULL }; -+ struct pam_message m[2] = { { 0 }, { 0 } }; -+ struct pam_response *resp = NULL; - -- if (pi->token_name == NULL || *pi->token_name == '\0' -- || pi->cert_user == NULL || *pi->cert_user == '\0') { -+ if (pi->token_name == NULL || *pi->token_name == '\0') { - return EINVAL; - } - -- size = sizeof(SC_PROMPT_FMT) + strlen(pi->token_name) + -- strlen(pi->cert_user); -+ size = sizeof(SC_PROMPT_FMT) + strlen(pi->token_name); - prompt = malloc(size); - if (prompt == NULL) { - D(("malloc failed.")); - return ENOMEM; - } - -- ret = snprintf(prompt, size, SC_PROMPT_FMT, pi->token_name, pi->cert_user); -+ ret = snprintf(prompt, size, SC_PROMPT_FMT, pi->token_name); - if (ret < 0 || ret >= size) { - D(("snprintf failed.")); - free(prompt); - return EFAULT; - } - -- ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, &answer); -- free(prompt); -- if (ret != PAM_SUCCESS) { -- D(("do_pam_conversation failed.")); -- return ret; -+ if (pi->user_name_hint) { -+ ret = pam_get_item(pamh, PAM_CONV, (const void **)&conv); -+ if (ret != PAM_SUCCESS) { -+ return ret; -+ } -+ if (conv == NULL || conv->conv == NULL) { -+ logger(pamh, LOG_ERR, "No conversation function"); -+ return PAM_SYSTEM_ERR; -+ } -+ -+ m[0].msg_style = PAM_PROMPT_ECHO_OFF; -+ m[0].msg = prompt; -+ m[1].msg_style = PAM_PROMPT_ECHO_ON; -+ m[1].msg = "User name hint: "; -+ -+ mesg[0] = (const struct pam_message *)m; -+ /* The following assignment might look a bit odd but is recommended in the -+ * pam_conv man page to make sure that the second argument of the PAM -+ * conversation function can be interpreted in two different ways. -+ * Basically it is important that both the actual struct pam_message and -+ * the pointers to the struct pam_message are arrays. Since the assignment -+ * makes clear that mesg[] and (*mesg)[] are arrays it should be kept this -+ * way and not be replaced by other equivalent assignments. */ -+ mesg[1] = &((*mesg)[1]); -+ -+ ret = conv->conv(2, mesg, &resp, conv->appdata_ptr); -+ if (ret != PAM_SUCCESS) { -+ D(("Conversation failure: %s.", pam_strerror(pamh, ret))); -+ return ret; -+ } -+ -+ if (resp == NULL) { -+ D(("response expected, but resp==NULL")); -+ return PAM_SYSTEM_ERR; -+ } -+ -+ if (resp[0].resp == NULL || *(resp[0].resp) == '\0') { -+ D(("Missing PIN.")); -+ ret = PAM_CRED_INSUFFICIENT; -+ goto done; -+ } -+ -+ answer = strndup(resp[0].resp, MAX_AUTHTOK_SIZE); -+ _pam_overwrite((void *)resp[0].resp); -+ free(resp[0].resp); -+ resp[0].resp = NULL; -+ if (answer == NULL) { -+ D(("strndup failed")); -+ ret = PAM_BUF_ERR; -+ goto done; -+ } -+ -+ if (resp[1].resp != NULL && *(resp[1].resp) != '\0') { -+ ret = pam_set_item(pamh, PAM_USER, resp[1].resp); -+ free(resp[1].resp); -+ resp[1].resp = NULL; -+ if (ret != PAM_SUCCESS) { -+ D(("Failed to set PAM_USER with user name hint [%s]", -+ pam_strerror(pamh, ret))); -+ goto done; -+ } -+ -+ ret = pam_get_item(pamh, PAM_USER, (const void **)&(pi->pam_user)); -+ if (ret != PAM_SUCCESS) { -+ D(("Failed to get PAM_USER with user name hint [%s]", -+ pam_strerror(pamh, ret))); -+ goto done; -+ } -+ -+ pi->pam_user_size = strlen(pi->pam_user) + 1; -+ } -+ } else { -+ ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, -+ &answer); -+ free(prompt); -+ if (ret != PAM_SUCCESS) { -+ D(("do_pam_conversation failed.")); -+ return ret; -+ } - } - - if (answer == NULL) { -@@ -1552,6 +1641,20 @@ done: - free(answer); - answer=NULL; - -+ if (resp != NULL) { -+ if (resp[0].resp != NULL) { -+ _pam_overwrite((void *)resp[0].resp); -+ free(resp[0].resp); -+ } -+ if (resp[1].resp != NULL) { -+ _pam_overwrite((void *)resp[1].resp); -+ free(resp[1].resp); -+ } -+ -+ free(resp); -+ resp = NULL; -+ } -+ - return ret; - } - -@@ -1680,7 +1783,7 @@ static int get_authtok_for_authentication(pam_handle_t *pamh, - ret = prompt_2fa(pamh, pi, _("First Factor: "), - _("Second Factor: ")); - } -- } else if (pi->cert_user != NULL) { -+ } else if (pi->token_name != NULL && *(pi->token_name) != '\0') { - ret = prompt_sc_pin(pamh, pi); - } else { - ret = prompt_password(pamh, pi, _("Password: ")); -diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h -index 59fee7a4eceb2c185e156e812af7f2f4c6b2a0dd..d4198407f2f86c6594aee6a2a43775e429692df0 100644 ---- a/src/sss_client/sss_cli.h -+++ b/src/sss_client/sss_cli.h -@@ -427,7 +427,13 @@ enum response_type { - * @param Three zero terminated strings, if one of the - * strings is missing the message will contain only - * an empty string (\0) for that component. */ -- SSS_PAM_CERT_INFO, -+ SSS_PAM_CERT_INFO, /**< A message indicating that Smartcard/certificate -+ * based authentication is available and contains -+ * details about the found Smartcard. -+ * @param user name, zero terminated -+ * @param token name, zero terminated -+ * @param PKCS#11 module name, zero terminated -+ * @param key id, zero terminated */ - SSS_OTP, /**< Indicates that the autotok was a OTP, so don't - * cache it. There is no message. - * @param None. */ -@@ -442,6 +448,9 @@ enum response_type { - * be used together with other prompting options - * to determine the type of prompting. - * @param None. */ -+ SSS_PAM_CERT_INFO_WITH_HINT, /**< Same as SSS_PAM_CERT_INFO but user name -+ * might be missing and should be prompted -+ * for. */ - }; - - /** --- -2.9.4 - diff --git a/SOURCES/0157-add_pam_cert_response-add-support-for-SSS_PAM_CERT_I.patch b/SOURCES/0157-add_pam_cert_response-add-support-for-SSS_PAM_CERT_I.patch deleted file mode 100644 index a9a73fd..0000000 --- a/SOURCES/0157-add_pam_cert_response-add-support-for-SSS_PAM_CERT_I.patch +++ /dev/null @@ -1,104 +0,0 @@ -From c5c6ba2546d350a7a01a9f44bb5df9c6652a1e06 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 8 May 2017 16:02:36 +0200 -Subject: [PATCH 157/160] add_pam_cert_response: add support for - SSS_PAM_CERT_INFO_WITH_HINT -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Related to https://pagure.io/SSSD/sssd/issue/3395 - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 6073cfc40747cd6d3142f0f98b880fc390dd7aad) ---- - src/responder/pam/pamsrv.h | 2 +- - src/responder/pam/pamsrv_cmd.c | 3 ++- - src/responder/pam/pamsrv_p11.c | 21 +++++++++++++++------ - 3 files changed, 18 insertions(+), 8 deletions(-) - -diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h -index b569748fe2a2005cee5df34bef55e803175492a9..57a37b72594f030995f5e22255eb7a8fcd63d10e 100644 ---- a/src/responder/pam/pamsrv.h -+++ b/src/responder/pam/pamsrv.h -@@ -101,7 +101,7 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - - errno_t add_pam_cert_response(struct pam_data *pd, const char *user, - const char *token_name, const char *module_name, -- const char *key_id); -+ const char *key_id, enum response_type type); - - bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd); - -diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c -index 36dba37964b71153435b4df5d5328de4361926e6..080cfafa709d63542fbf57d26fab11f0a367dea7 100644 ---- a/src/responder/pam/pamsrv_cmd.c -+++ b/src/responder/pam/pamsrv_cmd.c -@@ -1846,7 +1846,8 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) - ret = add_pam_cert_response(preq->pd, cert_user, - preq->token_name, - preq->module_name, -- preq->key_id); -+ preq->key_id, -+ SSS_PAM_CERT_INFO); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); - preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; -diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c -index 365300b9075983b603a6f9e91ba6f8f21706388f..4dce43800c3c6b026c545df35c846269cbb49610 100644 ---- a/src/responder/pam/pamsrv_p11.c -+++ b/src/responder/pam/pamsrv_p11.c -@@ -580,7 +580,7 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - - errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, - const char *token_name, const char *module_name, -- const char *key_id) -+ const char *key_id, enum response_type type) - { - uint8_t *msg = NULL; - char *env = NULL; -@@ -590,14 +590,23 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, - size_t module_len; - size_t key_id_len; - int ret; -+ const char *username = ""; - -- if (sysdb_username == NULL || token_name == NULL || module_name == NULL -- || key_id == NULL) { -+ if (type != SSS_PAM_CERT_INFO && type != SSS_PAM_CERT_INFO_WITH_HINT) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid response type [%d].\n", type); -+ return EINVAL; -+ } -+ -+ if ((type == SSS_PAM_CERT_INFO && sysdb_username == NULL) -+ || token_name == NULL || module_name == NULL || key_id == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n"); - return EINVAL; - } - -- user_len = strlen(sysdb_username) + 1; -+ if (sysdb_username != NULL) { -+ username = sysdb_username; -+ } -+ user_len = strlen(username) + 1; - slot_len = strlen(token_name) + 1; - module_len = strlen(module_name) + 1; - key_id_len = strlen(key_id) + 1; -@@ -616,12 +625,12 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, - * re_expression config option was set in a way that user@domain cannot be - * handled anymore some more logic has to be added here. But for the time - * being I think using sysdb_username is fine. */ -- memcpy(msg, sysdb_username, user_len); -+ memcpy(msg, username, user_len); - memcpy(msg + user_len, token_name, slot_len); - memcpy(msg + user_len + slot_len, module_name, module_len); - memcpy(msg + user_len + slot_len + module_len, key_id, key_id_len); - -- ret = pam_add_response(pd, SSS_PAM_CERT_INFO, msg_len, msg); -+ ret = pam_add_response(pd, type, msg_len, msg); - talloc_free(msg); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, --- -2.9.4 - diff --git a/SOURCES/0158-PAM-send-user-name-hint-response-when-needed.patch b/SOURCES/0158-PAM-send-user-name-hint-response-when-needed.patch deleted file mode 100644 index a444dcf..0000000 --- a/SOURCES/0158-PAM-send-user-name-hint-response-when-needed.patch +++ /dev/null @@ -1,335 +0,0 @@ -From a531a785f57be7ae228ca04a7af606debd66eeb1 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 3 May 2017 16:30:12 +0200 -Subject: [PATCH 158/160] PAM: send user name hint response when needed -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If the PAM client didn't send a user name and promtusername is enable -the PAM responder will tell pam_sss to ask for an optional user name as -well. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3395 - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 32474fa2f0a6dc09386bab405fc3461cb3dd12ac) ---- - src/responder/pam/pamsrv_cmd.c | 72 ++++++++++------ - src/tests/cmocka/test_pam_srv.c | 180 +++++++++++++++++++++++++++++----------- - 2 files changed, 177 insertions(+), 75 deletions(-) - -diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c -index 080cfafa709d63542fbf57d26fab11f0a367dea7..49a05657e03feef564d6196029da4cacc2ab8eaf 100644 ---- a/src/responder/pam/pamsrv_cmd.c -+++ b/src/responder/pam/pamsrv_cmd.c -@@ -1414,7 +1414,7 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) - struct cache_req_result **results; - struct pam_auth_req *preq = tevent_req_callback_data(req, - struct pam_auth_req); -- const char *cert_user; -+ const char *cert_user = NULL; - - ret = cache_req_recv(preq, req, &results); - talloc_zfree(req); -@@ -1439,35 +1439,55 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) - goto done; - } - -- if (preq->cert_user_objs->count != 1) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "More than one user mapped to certificate.\n"); -- /* TODO: send pam response to ask for a user name */ -- ret = ERR_NO_CREDS; -- goto done; -- } -- cert_user = ldb_msg_find_attr_as_string( -+ if (preq->cert_user_objs->count == 1) { -+ cert_user = ldb_msg_find_attr_as_string( - preq->cert_user_objs->msgs[0], - SYSDB_NAME, NULL); -+ if (cert_user == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Certificate user object has not name.\n"); -+ ret = ENOENT; -+ goto done; -+ } -+ -+ DEBUG(SSSDBG_FUNC_DATA, -+ "Found certificate user [%s].\n", cert_user); -+ -+ ret = sss_parse_name_for_domains(preq->pd, -+ preq->cctx->rctx->domains, -+ preq->cctx->rctx->default_domain, -+ cert_user, -+ &preq->pd->domain, -+ &preq->pd->user); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sss_parse_name_for_domains failed.\n"); -+ goto done; -+ } -+ } -+ -+ if (preq->cctx->rctx->domains->user_name_hint) { -+ ret = add_pam_cert_response(preq->pd, cert_user, -+ preq->token_name, -+ preq->module_name, -+ preq->key_id, -+ SSS_PAM_CERT_INFO_WITH_HINT); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); -+ preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; -+ } -+ ret = EOK; -+ preq->pd->pam_status = PAM_SUCCESS; -+ pam_reply(preq); -+ goto done; -+ } -+ -+ /* Without user name hints the certificate must map to single user -+ * if no login name was given */ - if (cert_user == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, -- "Certificate user object has not name.\n"); -- ret = ENOENT; -- goto done; -- } -- -- DEBUG(SSSDBG_FUNC_DATA, "Found certificate user [%s].\n", -- cert_user); -- -- ret = sss_parse_name_for_domains(preq->pd, -- preq->cctx->rctx->domains, -- preq->cctx->rctx->default_domain, -- cert_user, -- &preq->pd->domain, -- &preq->pd->user); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "sss_parse_name_for_domains failed.\n"); -+ "More than one user mapped to certificate.\n"); -+ ret = ERR_NO_CREDS; - goto done; - } - -diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c -index 35afbdd81d004236885ee80914771ccb4b8acff4..0f92f05417025e41a702127099d1d01e269412dc 100644 ---- a/src/tests/cmocka/test_pam_srv.c -+++ b/src/tests/cmocka/test_pam_srv.c -@@ -747,57 +747,83 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, - return EOK; - } - -+static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, -+ enum response_type type, const char *name) -+{ -+ size_t rp = 0; -+ uint32_t val; -+ -+ assert_int_equal(status, 0); -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ assert_int_equal(val, pam_test_ctx->exp_pam_status); -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ if (name == NULL || *name == '\0') { -+ assert_int_equal(val, 1); -+ } else { -+ assert_int_equal(val, 2); -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ assert_int_equal(val, SSS_PAM_DOMAIN_NAME); -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ assert_int_equal(val, 9); -+ -+ assert_int_equal(*(body + rp + val - 1), 0); -+ assert_string_equal(body + rp, TEST_DOM_NAME); -+ rp += val; -+ } -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ assert_int_equal(val, type); -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ assert_int_equal(val, (strlen(name) + 1 -+ + sizeof(TEST_TOKEN_NAME) -+ + sizeof(TEST_MODULE_NAME) -+ + sizeof(TEST_KEY_ID))); -+ -+ assert_int_equal(*(body + rp + strlen(name)), 0); -+ assert_string_equal(body + rp, name); -+ rp += strlen(name) + 1; -+ -+ assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0); -+ assert_string_equal(body + rp, TEST_TOKEN_NAME); -+ rp += sizeof(TEST_TOKEN_NAME); -+ -+ assert_int_equal(*(body + rp + sizeof(TEST_MODULE_NAME) - 1), 0); -+ assert_string_equal(body + rp, TEST_MODULE_NAME); -+ rp += sizeof(TEST_MODULE_NAME); -+ -+ assert_int_equal(*(body + rp + sizeof(TEST_KEY_ID) - 1), 0); -+ assert_string_equal(body + rp, TEST_KEY_ID); -+ rp += sizeof(TEST_KEY_ID); -+ -+ assert_int_equal(rp, blen); -+ -+ return EOK; -+} -+ - static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) - { -- size_t rp = 0; -- uint32_t val; -- -- assert_int_equal(status, 0); -- -- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -- assert_int_equal(val, pam_test_ctx->exp_pam_status); -- -- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -- assert_int_equal(val, 2); -- -- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -- assert_int_equal(val, SSS_PAM_DOMAIN_NAME); -- -- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -- assert_int_equal(val, 9); -- -- assert_int_equal(*(body + rp + val - 1), 0); -- assert_string_equal(body + rp, TEST_DOM_NAME); -- rp += val; -- -- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -- assert_int_equal(val, SSS_PAM_CERT_INFO); -- -- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -- assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) -- + sizeof(TEST_TOKEN_NAME) -- + sizeof(TEST_MODULE_NAME) -- + sizeof(TEST_KEY_ID))); -- -- assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); -- assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); -- rp += sizeof("pamuser@"TEST_DOM_NAME); -- -- assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0); -- assert_string_equal(body + rp, TEST_TOKEN_NAME); -- rp += sizeof(TEST_TOKEN_NAME); -- -- assert_int_equal(*(body + rp + sizeof(TEST_MODULE_NAME) - 1), 0); -- assert_string_equal(body + rp, TEST_MODULE_NAME); -- rp += sizeof(TEST_MODULE_NAME); -- -- assert_int_equal(*(body + rp + sizeof(TEST_KEY_ID) - 1), 0); -- assert_string_equal(body + rp, TEST_KEY_ID); -- rp += sizeof(TEST_KEY_ID); -- -- assert_int_equal(rp, blen); -- -- return EOK; -+ return test_pam_cert_check_ex(status, body, blen, -+ SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME); -+} -+ -+static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body, -+ size_t blen) -+{ -+ return test_pam_cert_check_ex(status, body, blen, -+ SSS_PAM_CERT_INFO_WITH_HINT, -+ "pamuser@"TEST_DOM_NAME); -+} -+ -+static int test_pam_cert_check_with_hint_no_user(uint32_t status, uint8_t *body, -+ size_t blen) -+{ -+ return test_pam_cert_check_ex(status, body, blen, -+ SSS_PAM_CERT_INFO_WITH_HINT, ""); - } - - static int test_pam_offline_chauthtok_check(uint32_t status, -@@ -1895,6 +1921,33 @@ void test_pam_preauth_cert_no_logon_name(void **state) - assert_int_equal(ret, EOK); - } - -+void test_pam_preauth_cert_no_logon_name_with_hint(void **state) -+{ -+ int ret; -+ -+ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); -+ pam_test_ctx->rctx->domains->user_name_hint = true; -+ -+ /* If no logon name is given the user is looked by certificate first. -+ * Since user name hint is enabled we do not have to search the user -+ * during pre-auth and there is no need for an extra mocked response as in -+ * test_pam_preauth_cert_no_logon_name. */ -+ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, -+ test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); -+ -+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); -+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ set_cmd_cb(test_pam_cert_check_with_hint); -+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH, -+ pam_test_ctx->pam_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(pam_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ - void test_pam_preauth_cert_no_logon_name_double_cert(void **state) - { - int ret; -@@ -1917,6 +1970,29 @@ void test_pam_preauth_cert_no_logon_name_double_cert(void **state) - assert_int_equal(ret, EOK); - } - -+void test_pam_preauth_cert_no_logon_name_double_cert_with_hint(void **state) -+{ -+ int ret; -+ -+ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); -+ pam_test_ctx->rctx->domains->user_name_hint = true; -+ -+ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, -+ test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, false); -+ -+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); -+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ -+ set_cmd_cb(test_pam_cert_check_with_hint_no_user); -+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH, -+ pam_test_ctx->pam_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(pam_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ - void test_pam_preauth_no_cert_no_logon_name(void **state) - { - int ret; -@@ -2426,8 +2502,14 @@ int main(int argc, const char *argv[]) - cmocka_unit_test_setup_teardown(test_pam_preauth_cert_no_logon_name, - pam_test_setup, pam_test_teardown), - cmocka_unit_test_setup_teardown( -+ test_pam_preauth_cert_no_logon_name_with_hint, -+ pam_test_setup, pam_test_teardown), -+ cmocka_unit_test_setup_teardown( - test_pam_preauth_cert_no_logon_name_double_cert, - pam_test_setup, pam_test_teardown), -+ cmocka_unit_test_setup_teardown( -+ test_pam_preauth_cert_no_logon_name_double_cert_with_hint, -+ pam_test_setup, pam_test_teardown), - cmocka_unit_test_setup_teardown(test_pam_preauth_no_cert_no_logon_name, - pam_test_setup, pam_test_teardown), - cmocka_unit_test_setup_teardown( --- -2.9.4 - diff --git a/SOURCES/0159-sysdb-sysdb_get_certmap-allow-empty-certmap.patch b/SOURCES/0159-sysdb-sysdb_get_certmap-allow-empty-certmap.patch deleted file mode 100644 index 290bab5..0000000 --- a/SOURCES/0159-sysdb-sysdb_get_certmap-allow-empty-certmap.patch +++ /dev/null @@ -1,105 +0,0 @@ -From b435e510fb06af4e8f3cffd3730f43a6aff165fa Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 8 May 2017 17:30:06 +0200 -Subject: [PATCH 159/160] sysdb: sysdb_get_certmap() allow empty certmap -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Since sysdb_get_certmap() returns the user name hint information as well -it should return a result even if there are no certmaps. - -Related to https://pagure.io/SSSD/sssd/issue/3395 - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit ee7e72a65d323636600ffda271d5b5c4ddbc78b1) ---- - src/db/sysdb_certmap.c | 13 ++++++++----- - src/tests/cmocka/test_sysdb_certmap.c | 9 +++++---- - 2 files changed, 13 insertions(+), 9 deletions(-) - -diff --git a/src/db/sysdb_certmap.c b/src/db/sysdb_certmap.c -index 4917796b11c3967b4d147ebee7c7e83f09b872ce..2d89c08a07be6e8eaf853d6c50b206c5c53d5a37 100644 ---- a/src/db/sysdb_certmap.c -+++ b/src/db/sysdb_certmap.c -@@ -269,7 +269,7 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, - size_t d; - struct ldb_dn *container_dn = NULL; - int ret; -- struct certmap_info **maps; -+ struct certmap_info **maps = NULL; - TALLOC_CTX *tmp_ctx = NULL; - struct ldb_result *res; - const char *tmp_str; -@@ -320,7 +320,7 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, - - if (res->count == 0) { - DEBUG(SSSDBG_TRACE_FUNC, "No certificate maps found.\n"); -- ret = ENOENT; -+ ret = EOK; - goto done; - } - -@@ -377,7 +377,7 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, - SYSDB_CERTMAP_PRIORITY, - (uint64_t) -1); - if (tmp_uint != (uint64_t) -1) { -- if (tmp_uint >= UINT32_MAX) { -+ if (tmp_uint > UINT32_MAX) { - DEBUG(SSSDBG_OP_FAILURE, "Priority value [%lu] too large.\n", - (unsigned long) tmp_uint); - ret = EINVAL; -@@ -414,11 +414,14 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, - } - } - -- *certmaps = talloc_steal(mem_ctx, maps); -- *user_name_hint = hint; - ret = EOK; - - done: -+ if (ret == EOK) { -+ *certmaps = talloc_steal(mem_ctx, maps); -+ *user_name_hint = hint; -+ } -+ - talloc_free(tmp_ctx); - - return ret; -diff --git a/src/tests/cmocka/test_sysdb_certmap.c b/src/tests/cmocka/test_sysdb_certmap.c -index fb07165561779226935f436c308c85abfc305635..72edf5f53fd6d23d7279eaa496b3e798c06cb903 100644 ---- a/src/tests/cmocka/test_sysdb_certmap.c -+++ b/src/tests/cmocka/test_sysdb_certmap.c -@@ -88,8 +88,8 @@ static void test_sysdb_get_certmap_not_exists(void **state) - - ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, - &user_name_hint); -- assert_int_equal(ret, ENOENT); -- -+ assert_int_equal(ret, EOK); -+ assert_null(certmap); - } - - static void check_certmap(struct certmap_info *m, struct certmap_info *r, -@@ -134,7 +134,7 @@ static void test_sysdb_update_certmap(void **state) - int ret; - const char *domains[] = { "dom1.test", "dom2.test", "dom3.test", NULL }; - struct certmap_info map_a = { discard_const("map_a"), 11, discard_const("abc"), discard_const("def"), NULL }; -- struct certmap_info map_b = { discard_const("map_b"), 22, discard_const("abc"), NULL, domains }; -+ struct certmap_info map_b = { discard_const("map_b"), UINT_MAX, discard_const("abc"), NULL, domains }; - struct certmap_info *certmap_empty[] = { NULL }; - struct certmap_info *certmap_a[] = { &map_a, NULL }; - struct certmap_info *certmap_b[] = { &map_b, NULL }; -@@ -152,7 +152,8 @@ static void test_sysdb_update_certmap(void **state) - - ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, - &user_name_hint); -- assert_int_equal(ret, ENOENT); -+ assert_int_equal(ret, EOK); -+ assert_null(certmap); - - ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_a, false); - assert_int_equal(ret, EOK); --- -2.9.4 - diff --git a/SOURCES/0160-sssctl-show-user-name-used-for-authentication-in-use.patch b/SOURCES/0160-sssctl-show-user-name-used-for-authentication-in-use.patch deleted file mode 100644 index 6680a3b..0000000 --- a/SOURCES/0160-sssctl-show-user-name-used-for-authentication-in-use.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 6edf41eba3cec8aa40dffaf639cd5c7756db310e Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 10 May 2017 17:13:48 +0200 -Subject: [PATCH 160/160] sssctl: show user name used for authentication in - user-checks -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Since there are cases where the user name is not entered directly but -determined by other means the user-checks should show the name of the -user used for authentication. - -Related to https://pagure.io/SSSD/sssd/issue/3395 - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit b130adaa3934d0531aca0f32961ab8b4cc720820) ---- - src/tools/sssctl/sssctl_user_checks.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/src/tools/sssctl/sssctl_user_checks.c b/src/tools/sssctl/sssctl_user_checks.c -index 7c7b564bd29100382c9bbef7a3131c379e9aa97e..d5cd8a1b42e84aa96df95ed39905c864a38212b7 100644 ---- a/src/tools/sssctl/sssctl_user_checks.c -+++ b/src/tools/sssctl/sssctl_user_checks.c -@@ -200,6 +200,8 @@ errno_t sssctl_user_checks(struct sss_cmdline *cmdline, - const char *action = DEFAULT_ACTION; - const char *service = DEFAULT_SERVICE; - int ret; -+ int pret; -+ const char *pam_user = NULL; - size_t c; - char **pam_env; - -@@ -246,7 +248,14 @@ errno_t sssctl_user_checks(struct sss_cmdline *cmdline, - if ( strncmp(action, "auth", 4)== 0 ) { - fprintf(stdout, _("testing pam_authenticate\n\n")); - ret = pam_authenticate(pamh, 0); -- fprintf(stderr, _("pam_authenticate: %s\n\n"), pam_strerror(pamh, ret)); -+ pret = pam_get_item(pamh, PAM_USER, (const void **) &pam_user); -+ if (pret != PAM_SUCCESS) { -+ fprintf(stderr, _("pam_get_item failed: %s\n"), pam_strerror(pamh, -+ pret)); -+ pam_user = "- not available -"; -+ } -+ fprintf(stderr, _("pam_authenticate for user [%s]: %s\n\n"), pam_user, -+ pam_strerror(pamh, ret)); - } else if ( strncmp(action, "chau", 4)== 0 ) { - fprintf(stdout, _("testing pam_chauthtok\n\n")); - ret = pam_chauthtok(pamh, 0); --- -2.9.4 - diff --git a/SOURCES/0161-RESP-Provide-a-reusable-request-to-fully-resolve-inc.patch b/SOURCES/0161-RESP-Provide-a-reusable-request-to-fully-resolve-inc.patch deleted file mode 100644 index cc83129..0000000 --- a/SOURCES/0161-RESP-Provide-a-reusable-request-to-fully-resolve-inc.patch +++ /dev/null @@ -1,267 +0,0 @@ -From be1f9a082eb28b3346135cbe399f7f909c8a50ce Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 24 May 2017 17:34:55 +0200 -Subject: [PATCH 161/166] RESP: Provide a reusable request to fully resolve - incomplete groups -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -After initgroups, the group objects might not be complete, but just -stubs that contain the SID and the GID. If the caller needs to know the -group names as well, this request allows them to iterate over the list -of the groups and resolve them one-by-one. - -Reviewed-by: Pavel Březina ---- - src/responder/common/responder.h | 14 +++ - src/responder/common/responder_utils.c | 206 +++++++++++++++++++++++++++++++++ - 2 files changed, 220 insertions(+) - -diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h -index dfe1ec455e355de263c3550306e53fea3ada85df..c09ecd4931c9e197fbdfb7835eb72f49cc6f6d3f 100644 ---- a/src/responder/common/responder.h -+++ b/src/responder/common/responder.h -@@ -414,4 +414,18 @@ int sized_domain_name(TALLOC_CTX *mem_ctx, - const char *member_name, - struct sized_string **_name); - -+/* Given a ldb_result structure that contains a result of sysdb_initgroups -+ * where some groups might be just 'stubs' that don't have a name, but only -+ * a SID and a GID, resolve those incomplete groups into full group objects -+ */ -+struct tevent_req *resp_resolve_group_names_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct resp_ctx *rctx, -+ struct sss_domain_info *dom, -+ struct ldb_result *initgr_res); -+ -+int resp_resolve_group_names_recv(TALLOC_CTX *mem_ctx, -+ struct tevent_req *req, -+ struct ldb_result **_initgr_named_res); -+ - #endif /* __SSS_RESPONDER_H__ */ -diff --git a/src/responder/common/responder_utils.c b/src/responder/common/responder_utils.c -index b02212dfd87c2b7c2ca6108d46f939447f0eaa25..7f5c0573087e9c6c885ae158d0677994fd538e2a 100644 ---- a/src/responder/common/responder_utils.c -+++ b/src/responder/common/responder_utils.c -@@ -23,6 +23,7 @@ - #include - - #include "responder/common/responder.h" -+#include "responder/common/cache_req/cache_req.h" - #include "util/util.h" - - static inline bool -@@ -193,3 +194,208 @@ char *sss_resp_create_fqname(TALLOC_CTX *mem_ctx, - talloc_free(tmp_ctx); - return name; - } -+ -+struct resp_resolve_group_names_state { -+ struct tevent_context *ev; -+ struct resp_ctx *rctx; -+ struct sss_domain_info *dom; -+ struct ldb_result *initgr_res; -+ -+ bool needs_refresh; -+ unsigned int group_iter; -+ -+ struct ldb_result *initgr_named_res; -+}; -+ -+static void resp_resolve_group_done(struct tevent_req *subreq); -+static errno_t resp_resolve_group_next(struct tevent_req *req); -+static errno_t resp_resolve_group_reread_names(struct resp_resolve_group_names_state *state); -+ -+struct tevent_req *resp_resolve_group_names_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct resp_ctx *rctx, -+ struct sss_domain_info *dom, -+ struct ldb_result *initgr_res) -+{ -+ struct resp_resolve_group_names_state *state; -+ struct tevent_req *req; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, struct resp_resolve_group_names_state); -+ if (req == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); -+ return NULL; -+ } -+ state->ev = ev; -+ state->rctx = rctx; -+ state->dom = dom; -+ state->initgr_res = initgr_res; -+ -+ ret = resp_resolve_group_next(req); -+ if (ret == EOK) { -+ goto immediate; -+ } else if (ret != EAGAIN) { -+ goto immediate; -+ } -+ -+ return req; -+ -+immediate: -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static bool -+resp_resolve_group_needs_refresh(struct resp_resolve_group_names_state *state) -+{ -+ /* Refresh groups that have a non-zero GID, -+ * but are marked as non-POSIX -+ */ -+ bool is_posix; -+ uint64_t gid; -+ struct ldb_message *group_msg; -+ -+ group_msg = state->initgr_res->msgs[state->group_iter]; -+ -+ is_posix = ldb_msg_find_attr_as_bool(group_msg, SYSDB_POSIX, false); -+ gid = ldb_msg_find_attr_as_uint64(group_msg, SYSDB_GIDNUM, 0); -+ -+ if (is_posix == false && gid != 0) { -+ return true; -+ } -+ -+ return false; -+} -+ -+static errno_t resp_resolve_group_next(struct tevent_req *req) -+{ -+ struct cache_req_data *data; -+ uint64_t gid; -+ struct tevent_req *subreq; -+ struct resp_resolve_group_names_state *state; -+ -+ state = tevent_req_data(req, struct resp_resolve_group_names_state); -+ -+ while (state->group_iter < state->initgr_res->count -+ && !resp_resolve_group_needs_refresh(state)) { -+ state->group_iter++; -+ } -+ -+ if (state->group_iter >= state->initgr_res->count) { -+ /* All groups were refreshed */ -+ return EOK; -+ } -+ -+ /* Fire a request */ -+ gid = ldb_msg_find_attr_as_uint64(state->initgr_res->msgs[state->group_iter], -+ SYSDB_GIDNUM, 0); -+ if (gid == 0) { -+ return EINVAL; -+ } -+ -+ data = cache_req_data_id_attrs(state, CACHE_REQ_GROUP_BY_ID, gid, NULL); -+ if (data == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set cache request data!\n"); -+ return ENOMEM; -+ } -+ -+ subreq = cache_req_send(state, -+ state->ev, -+ state->rctx, -+ state->rctx->ncache, -+ 0, -+ CACHE_REQ_ANY_DOM, -+ NULL, -+ data); -+ if (subreq == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send cache request!\n"); -+ return ENOMEM; -+ } -+ -+ tevent_req_set_callback(subreq, resp_resolve_group_done, req); -+ return EAGAIN; -+} -+ -+static void resp_resolve_group_done(struct tevent_req *subreq) -+{ -+ struct resp_resolve_group_names_state *state; -+ struct tevent_req *req; -+ errno_t ret; -+ -+ req = tevent_req_callback_data(subreq, struct tevent_req); -+ state = tevent_req_data(req, struct resp_resolve_group_names_state); -+ -+ ret = cache_req_single_domain_recv(state, subreq, NULL); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh group\n"); -+ /* Try to refresh the others on error */ -+ } -+ -+ state->group_iter++; -+ state->needs_refresh = true; -+ -+ ret = resp_resolve_group_next(req); -+ if (ret == EOK) { -+ ret = resp_resolve_group_reread_names(state); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ DEBUG(SSSDBG_TRACE_FUNC, "All groups are refreshed, done\n"); -+ tevent_req_done(req); -+ return; -+ } else if (ret != EAGAIN) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ /* Continue refreshing.. */ -+} -+ -+static errno_t -+resp_resolve_group_reread_names(struct resp_resolve_group_names_state *state) -+{ -+ errno_t ret; -+ const char *username; -+ -+ /* re-read reply in case any groups were renamed */ -+ /* msgs[0] is the user entry */ -+ username = sss_view_ldb_msg_find_attr_as_string(state->dom, -+ state->initgr_res->msgs[0], -+ SYSDB_NAME, -+ NULL); -+ if (username == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "A user with no name?\n"); -+ return EINVAL; -+ } -+ -+ ret = sysdb_initgroups_with_views(state, -+ state->dom, -+ username, -+ &state->initgr_named_res); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "Cannot re-read the group names\n"); -+ return ret; -+ } -+ -+ return EOK; -+} -+ -+int resp_resolve_group_names_recv(TALLOC_CTX *mem_ctx, -+ struct tevent_req *req, -+ struct ldb_result **_initgr_named_res) -+{ -+ struct resp_resolve_group_names_state *state = NULL; -+ state = tevent_req_data(req, struct resp_resolve_group_names_state); -+ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ -+ *_initgr_named_res = talloc_steal(mem_ctx, state->initgr_named_res); -+ return EOK; -+} --- -2.9.4 - diff --git a/SOURCES/0162-IFP-Only-format-the-output-name-to-the-short-version.patch b/SOURCES/0162-IFP-Only-format-the-output-name-to-the-short-version.patch deleted file mode 100644 index b6c6eaa..0000000 --- a/SOURCES/0162-IFP-Only-format-the-output-name-to-the-short-version.patch +++ /dev/null @@ -1,121 +0,0 @@ -From f5bee70057370c72ed111b50937e3252e36ccefb Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 9 May 2017 12:21:32 +0200 -Subject: [PATCH 162/166] IFP: Only format the output name to the short version - before output -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The ifp_user_get_attr_done() request handler was reused for both -GetUserGroups and GetUserAttrs requests. Yet, it performed output -formatting of name and nameAlias. - -This is bad, because the output formatting should really be done only -during output. Also, it broke any post-processing of the returned -message which the request might do later. - -Reviewed-by: Pavel Březina ---- - src/responder/ifp/ifpsrv_cmd.c | 64 ++++++++++++------------------------------ - 1 file changed, 18 insertions(+), 46 deletions(-) - -diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c -index e4d6c42ef35ef372472803d3d26b17d4181021a8..915f77e38e94c703f6c67e8d5fdcc59d189943be 100644 ---- a/src/responder/ifp/ifpsrv_cmd.c -+++ b/src/responder/ifp/ifpsrv_cmd.c -@@ -181,26 +181,6 @@ static void ifp_user_get_attr_process(struct tevent_req *req) - } - - static errno_t --ifp_user_get_attr_replace_space(TALLOC_CTX *mem_ctx, -- struct ldb_message_element *el, -- const char sub) --{ -- int i; -- -- for (i = 0; i < el->num_values; i++) { -- el->values[i].data = (uint8_t *) sss_replace_space(mem_ctx, -- (const char *) el->values[i].data, -- sub); -- if (el->values[i].data == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "sss_replace_space failed, skipping\n"); -- return ENOMEM; -- } -- } -- -- return EOK; --} -- --static errno_t - ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, - struct ifp_req *ireq, - const char **attrs, -@@ -234,6 +214,24 @@ ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, - } - - if (res->count > 0) { -+ ret = ifp_ldb_el_output_name(ireq->ifp_ctx->rctx, res->msgs[0], -+ SYSDB_NAME, domain); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert SYSDB_NAME to output format [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return sbus_request_finish(ireq->dbus_req, NULL); -+ } -+ -+ ret = ifp_ldb_el_output_name(ireq->ifp_ctx->rctx, res->msgs[0], -+ SYSDB_NAME_ALIAS, domain); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot convert SYSDB_NAME_ALIAS to output format [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ return sbus_request_finish(ireq->dbus_req, NULL); -+ } -+ - for (ai = 0; attrs[ai]; ai++) { - el = sss_view_ldb_msg_find_element(domain, res->msgs[0], attrs[ai]); - if (el == NULL || el->num_values == 0) { -@@ -243,18 +241,6 @@ ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, - continue; - } - -- /* Normalize white space in user names */ -- if (ireq->ifp_ctx->rctx->override_space != '\0' && -- strcmp(attrs[ai], SYSDB_NAME) == 0) { -- ret = ifp_user_get_attr_replace_space(ireq, el, -- ireq->ifp_ctx->rctx->override_space); -- if (ret != EOK) { -- DEBUG(SSSDBG_MINOR_FAILURE, "Cannot normalize %s\n", -- attrs[ai]); -- continue; -- } -- } -- - ret = ifp_add_ldb_el_to_dict(&iter_dict, el); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, -@@ -575,20 +561,6 @@ static void ifp_user_get_attr_done(struct tevent_req *subreq) - } - } - -- ret = ifp_ldb_el_output_name(state->rctx, state->res->msgs[0], -- SYSDB_NAME, state->dom); -- if (ret != EOK) { -- tevent_req_error(req, ret); -- return; -- } -- -- ret = ifp_ldb_el_output_name(state->rctx, state->res->msgs[0], -- SYSDB_NAME_ALIAS, state->dom); -- if (ret != EOK) { -- tevent_req_error(req, ret); -- return; -- } -- - tevent_req_done(req); - } - --- -2.9.4 - diff --git a/SOURCES/0163-IFP-Resolve-group-names-from-GIDs-if-required.patch b/SOURCES/0163-IFP-Resolve-group-names-from-GIDs-if-required.patch deleted file mode 100644 index b33cbba..0000000 --- a/SOURCES/0163-IFP-Resolve-group-names-from-GIDs-if-required.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 3891e94330a5df632a8db1a6f1d642cf2fa96579 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 24 May 2017 21:32:28 +0200 -Subject: [PATCH 163/166] IFP: Resolve group names from GIDs if required -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The AD provider only converts SIDs to GIDs during initgroups -to improve performance. But this is not sufficient for the -org.freedesktop.sssd.infopipe.GetUserGroups method, which needs to return -names. - -We need to resolve the GIDs to names ourselves in that method. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3392 - -Reviewed-by: Pavel Březina ---- - src/responder/ifp/ifpsrv_cmd.c | 115 +++++++++++++++++++++++++++++++---------- - 1 file changed, 89 insertions(+), 26 deletions(-) - -diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c -index 915f77e38e94c703f6c67e8d5fdcc59d189943be..70728e1bb656fd032b7f1c240683e8aa3b91a726 100644 ---- a/src/responder/ifp/ifpsrv_cmd.c -+++ b/src/responder/ifp/ifpsrv_cmd.c -@@ -259,7 +259,18 @@ ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, - return sbus_request_finish(ireq->dbus_req, reply); - } - -+struct ifp_user_get_groups_state { -+ struct resp_ctx *rctx; -+ -+ struct ifp_attr_req *group_attr_req; -+ -+ struct ldb_result *res; -+ struct ldb_result *res_names; -+ struct sss_domain_info *dom; -+}; -+ - static void ifp_user_get_groups_process(struct tevent_req *req); -+static void ifp_user_get_groups_names_resolved(struct tevent_req *req); - static errno_t ifp_user_get_groups_reply(struct sss_domain_info *domain, - struct ifp_req *ireq, - struct ldb_result *res); -@@ -269,7 +280,7 @@ int ifp_user_get_groups(struct sbus_request *dbus_req, - { - struct ifp_req *ireq; - struct ifp_ctx *ifp_ctx; -- struct ifp_attr_req *group_req; -+ struct ifp_user_get_groups_state *state; - struct tevent_req *req; - errno_t ret; - -@@ -284,68 +295,120 @@ int ifp_user_get_groups(struct sbus_request *dbus_req, - return ifp_req_create_handle_failure(dbus_req, ret); - } - -- group_req = talloc_zero(ireq, struct ifp_attr_req); -- if (group_req == NULL) { -+ state = talloc_zero(ireq, struct ifp_user_get_groups_state); -+ if (state == NULL) { - return sbus_request_finish(dbus_req, NULL); - } -- group_req->ireq = ireq; -- group_req->name = arg_user; -+ state->rctx = ifp_ctx->rctx; - -- group_req->attrs = talloc_zero_array(group_req, const char *, 2); -- if (group_req->attrs == NULL) { -+ state->group_attr_req = talloc_zero(state, struct ifp_attr_req); -+ if (state->group_attr_req == NULL) { - return sbus_request_finish(dbus_req, NULL); - } -+ state->group_attr_req->ireq = ireq; -+ state->group_attr_req->name = arg_user; - -- group_req->attrs[0] = talloc_strdup(group_req->attrs, SYSDB_MEMBEROF); -- if (group_req->attrs[0] == NULL) { -+ state->group_attr_req->attrs = talloc_zero_array(state->group_attr_req, -+ const char *, 2); -+ if (state->group_attr_req->attrs == NULL) { -+ return sbus_request_finish(dbus_req, NULL); -+ } -+ -+ state->group_attr_req->attrs[0] = talloc_strdup(state->group_attr_req->attrs, -+ SYSDB_MEMBEROF); -+ if (state->group_attr_req->attrs[0] == NULL) { - return sbus_request_finish(dbus_req, NULL); - } - - DEBUG(SSSDBG_FUNC_DATA, - "Looking up groups of user [%s] on behalf of %"PRIi64"\n", -- group_req->name, group_req->ireq->dbus_req->client); -+ state->group_attr_req->name, -+ state->group_attr_req->ireq->dbus_req->client); - - req = ifp_user_get_attr_send(ireq, ifp_ctx->rctx, - ifp_ctx->rctx->ncache, SSS_DP_INITGROUPS, -- group_req->name, group_req->attrs); -+ state->group_attr_req->name, -+ state->group_attr_req->attrs); - if (req == NULL) { - return sbus_request_finish(dbus_req, NULL); - } -- tevent_req_set_callback(req, ifp_user_get_groups_process, group_req); -+ tevent_req_set_callback(req, -+ ifp_user_get_groups_process, -+ state); - return EOK; - } - - static void ifp_user_get_groups_process(struct tevent_req *req) - { -- struct ifp_attr_req *group_req; -+ struct ifp_user_get_groups_state *state; -+ struct ifp_attr_req *group_attr_req; - errno_t ret; -- struct ldb_result *res; -- struct sss_domain_info *dom; - -- group_req = tevent_req_callback_data(req, struct ifp_attr_req); -+ state = tevent_req_callback_data(req, struct ifp_user_get_groups_state); -+ group_attr_req = state->group_attr_req; - -- ret = ifp_user_get_attr_recv(group_req, req, &res, &dom); -+ ret = ifp_user_get_attr_recv(group_attr_req, req, &state->res, &state->dom); - talloc_zfree(req); - if (ret == ENOENT) { -- sbus_request_fail_and_finish(group_req->ireq->dbus_req, -- sbus_error_new(group_req->ireq->dbus_req, -+ sbus_request_fail_and_finish(group_attr_req->ireq->dbus_req, -+ sbus_error_new(group_attr_req->ireq->dbus_req, - DBUS_ERROR_FAILED, - "No such user\n")); - return; - } else if (ret != EOK) { -- sbus_request_fail_and_finish(group_req->ireq->dbus_req, -- sbus_error_new(group_req->ireq->dbus_req, -+ sbus_request_fail_and_finish(group_attr_req->ireq->dbus_req, -+ sbus_error_new(group_attr_req->ireq->dbus_req, - DBUS_ERROR_FAILED, - "Failed to read attribute\n")); - return; - } - -- ret = ifp_user_get_groups_reply(dom, group_req->ireq, res); -+ req = resp_resolve_group_names_send(state, -+ state->rctx->ev, -+ state->rctx, -+ state->dom, -+ state->res); -+ if (req == NULL) { -+ sbus_request_finish(group_attr_req->ireq->dbus_req, NULL); -+ return; -+ } -+ tevent_req_set_callback(req, -+ ifp_user_get_groups_names_resolved, -+ state); -+} -+ -+static void ifp_user_get_groups_names_resolved(struct tevent_req *req) -+{ -+ struct ifp_user_get_groups_state *state; -+ struct ifp_attr_req *group_attr_req; -+ errno_t ret; -+ -+ state = tevent_req_callback_data(req, struct ifp_user_get_groups_state); -+ group_attr_req = state->group_attr_req; -+ -+ ret = resp_resolve_group_names_recv(state, req, &state->res_names); -+ talloc_zfree(req); - if (ret != EOK) { -- sbus_request_fail_and_finish(group_req->ireq->dbus_req, -- sbus_error_new(group_req->ireq->dbus_req, -- DBUS_ERROR_FAILED, -- "Failed to build a reply\n")); -+ sbus_request_fail_and_finish(group_attr_req->ireq->dbus_req, -+ sbus_error_new(group_attr_req->ireq->dbus_req, -+ DBUS_ERROR_FAILED, -+ "Failed to resolve groupnames\n")); -+ return; -+ } -+ -+ if (state->res_names == NULL) { -+ state->res_names = state->res; -+ } -+ -+ ret = ifp_user_get_groups_reply(state->dom, -+ group_attr_req->ireq, -+ state->res_names); -+ if (ret != EOK) { -+ sbus_request_fail_and_finish(group_attr_req->ireq->dbus_req, -+ sbus_error_new( -+ group_attr_req->ireq->dbus_req, -+ DBUS_ERROR_FAILED, -+ "Failed to build a reply\n")); - return; - } - } --- -2.9.4 - diff --git a/SOURCES/0164-ldap-handle-certmap-errors-gracefully.patch b/SOURCES/0164-ldap-handle-certmap-errors-gracefully.patch deleted file mode 100644 index caebbc1..0000000 --- a/SOURCES/0164-ldap-handle-certmap-errors-gracefully.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 85b74b966ec1d417ce76b05cbf3351b20c0981b2 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 17 May 2017 15:43:25 +0200 -Subject: [PATCH 164/166] ldap: handle certmap errors gracefully - -Currently the LDAP user lookup request errors out if e.g. there is no -matching rule for a certificate. This might cause the related domain to -go offline. - -With this patch the request returns that no user was found for the given -certificate but overall result is that the request finishes -successfully. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3405 - -Reviewed-by: Jakub Hrozek ---- - src/providers/ldap/ldap_id.c | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c -index 7400dc1f57e30cc6ae5f939ffa628a1e9dd47e06..557712e8dc2b2bde664b4054fa2f8eb39df84d73 100644 ---- a/src/providers/ldap/ldap_id.c -+++ b/src/providers/ldap/ldap_id.c -@@ -258,6 +258,27 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "sss_cert_derb64_to_ldap_filter failed.\n"); -+ -+ /* Typically sss_cert_derb64_to_ldap_filter() will fail if there -+ * is no mapping rule matching the current certificate. But this -+ * just means that no matching user can be found so we can finish -+ * the request with this result. Even if -+ * sss_cert_derb64_to_ldap_filter() would fail for other reason -+ * there is no need to return an error which might cause the -+ * domain go offline. */ -+ -+ if (noexist_delete) { -+ ret = sysdb_remove_cert(state->domain, filter_value); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Ignoring error while removing user certificate " -+ "[%d]: %s\n", ret, sss_strerror(ret)); -+ } -+ } -+ -+ ret = EOK; -+ state->sdap_ret = ENOENT; -+ state->dp_error = DP_ERR_OK; - goto done; - } - --- -2.9.4 - diff --git a/SOURCES/0165-SECRETS-Fix-warning-Wpointer-bool-conversion.patch b/SOURCES/0165-SECRETS-Fix-warning-Wpointer-bool-conversion.patch deleted file mode 100644 index 0a3ecf7..0000000 --- a/SOURCES/0165-SECRETS-Fix-warning-Wpointer-bool-conversion.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0e1416e65c99aca947e589bfa56d5bc832c023d6 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Sat, 27 May 2017 14:39:45 +0200 -Subject: [PATCH 165/166] SECRETS: Fix warning Wpointer-bool-conversion - -Debug messages would always say that verify_peer and verify_host -are enabled. Even though they would be explicitly disabled. - -src/responder/secrets/proxy.c:143:18: error: - address of 'cfg->verify_peer' will always evaluate to - 'true' [-Werror,-Wpointer-bool-conversion] - (&cfg->verify_peer ? "true" : "false")); - ~~~~~^~~~~~~~~~~ ~ -src/util/debug.h:108:32: note: expanded from macro 'DEBUG' - format, ##__VA_ARGS__); \ - ^~~~~~~~~~~ -src/responder/secrets/proxy.c:149:18: error: - address of 'cfg->verify_host' will always evaluate to - 'true' [-Werror,-Wpointer-bool-conversion] - (&cfg->verify_host ? "true" : "false")); - ~~~~~^~~~~~~~~~~ ~ -src/util/debug.h:108:32: note: expanded from macro 'DEBUG' - format, ##__VA_ARGS__); \ - ^~~~~~~~~~~ - -Reviewed-by: Jakub Hrozek ---- - src/responder/secrets/proxy.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c -index 9c2aa425d414728d10aa830f640632e98def3c1c..a4e97f83ef406e71a1e6509a6b719c47afdfd5b8 100644 ---- a/src/responder/secrets/proxy.c -+++ b/src/responder/secrets/proxy.c -@@ -140,13 +140,13 @@ static int proxy_sec_get_cfg(struct proxy_context *pctx, - true, &cfg->verify_peer); - if (ret) goto done; - DEBUG(SSSDBG_CONF_SETTINGS, "verify_peer: %s\n", -- (&cfg->verify_peer ? "true" : "false")); -+ cfg->verify_peer ? "true" : "false"); - - ret = confdb_get_bool(pctx->cdb, secreq->cfg_section, "verify_host", - true, &cfg->verify_host); - if (ret) goto done; - DEBUG(SSSDBG_CONF_SETTINGS, "verify_host: %s\n", -- (&cfg->verify_host ? "true" : "false")); -+ cfg->verify_host ? "true" : "false"); - - ret = proxy_get_config_string(pctx, cfg, false, secreq, - "capath", &cfg->capath); --- -2.9.4 - diff --git a/SOURCES/0166-IPA-Fix-the-PAM-error-code-that-auth-code-expects-to.patch b/SOURCES/0166-IPA-Fix-the-PAM-error-code-that-auth-code-expects-to.patch deleted file mode 100644 index f9eb273..0000000 --- a/SOURCES/0166-IPA-Fix-the-PAM-error-code-that-auth-code-expects-to.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 62cebc27bd0bdb2c12531203fd79f231e96eab7b Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 2 Jun 2017 11:17:18 +0200 -Subject: [PATCH 166/166] IPA: Fix the PAM error code that auth code expects to - start migration -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Recent patches which adds support for PKINIT in krb5_child changed a -return code which is used to indicate to the IPA provider that password -migration should be tried. - -With this patch krb5_child properly returns PAM_CRED_ERR as expected by -the IPA provider in this case. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3394 - -Reviewed-by: Simo Sorce -Reviewed-by: Lukáš Slebodník ---- - src/providers/krb5/krb5_child.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c -index cbbc892bee0365892ac66d3654c974d325166b60..3cd8bfba76a35acd2c885ee2aac4765a6c1cc03c 100644 ---- a/src/providers/krb5/krb5_child.c -+++ b/src/providers/krb5/krb5_child.c -@@ -1540,6 +1540,17 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - if (kerr != 0) { - KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); - -+ /* Special case for IPA password migration */ -+ if (kr->pd->cmd == SSS_PAM_AUTHENTICATE -+ && kerr == KRB5_PREAUTH_FAILED -+ && kr->pkinit_prompting == false -+ && kr->password_prompting == false -+ && kr->otp == false -+ && sss_authtok_get_type(kr->pd->authtok) -+ == SSS_AUTHTOK_TYPE_PASSWORD) { -+ return ERR_CREDS_INVALID; -+ } -+ - /* If during authentication either the MIT Kerberos pkinit - * pre-auth module is missing or no Smartcard is inserted and only - * pkinit is available KRB5_PREAUTH_FAILED is returned. --- -2.9.4 - diff --git a/SOURCES/0167-pam_sss-Fix-checking-of-empty-string-cert_user.patch b/SOURCES/0167-pam_sss-Fix-checking-of-empty-string-cert_user.patch deleted file mode 100644 index b8e2d31..0000000 --- a/SOURCES/0167-pam_sss-Fix-checking-of-empty-string-cert_user.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 1ac8b82addfa0a4c94321d5cb72b7991755e61f8 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Fri, 2 Jun 2017 11:56:55 +0200 -Subject: [PATCH 167/169] pam_sss: Fix checking of empty string cert_user -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -src/sss_client/pam_sss.c: In function ‘eval_response’: -src/sss_client/pam_sss.c:998:64: error: comparison between pointer and zero character constant [-Werror=pointer-compare] - if (type == SSS_PAM_CERT_INFO && pi->cert_user == '\0') { - ^~ -src/sss_client/pam_sss.c:998:50: note: did you mean to dereference the pointer? - if (type == SSS_PAM_CERT_INFO && pi->cert_user == '\0') { - ^ -src/sss_client/pam_sss.c:1010:42: error: comparison between pointer and zero character constant [-Werror=pointer-compare] - && pi->cert_user != '\0') { - ^~ -src/sss_client/pam_sss.c:1010:28: note: did you mean to dereference the pointer? - && pi->cert_user != '\0') { - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit c62dc2ac02253e130991db0f6acd60ce1a2753f1) ---- - src/sss_client/pam_sss.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c -index 1c06079967e3d9076d537c3de8aba93e13f76d09..9732459e6fb7ce01c9445c423cf0a583ca36e036 100644 ---- a/src/sss_client/pam_sss.c -+++ b/src/sss_client/pam_sss.c -@@ -995,7 +995,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, - break; - } - -- if (type == SSS_PAM_CERT_INFO && pi->cert_user == '\0') { -+ if (type == SSS_PAM_CERT_INFO && *pi->cert_user == '\0') { - D(("Invalid CERT message")); - break; - } -@@ -1007,7 +1007,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, - } - - if ((pi->pam_user == NULL || *(pi->pam_user) == '\0') -- && pi->cert_user != '\0') { -+ && *pi->cert_user != '\0') { - ret = pam_set_item(pamh, PAM_USER, pi->cert_user); - if (ret != PAM_SUCCESS) { - D(("Failed to set PAM_USER during " --- -2.9.4 - diff --git a/SOURCES/0168-CACHE_REQ-Simplify-_search_ncache_filter.patch b/SOURCES/0168-CACHE_REQ-Simplify-_search_ncache_filter.patch deleted file mode 100644 index 67e6f57..0000000 --- a/SOURCES/0168-CACHE_REQ-Simplify-_search_ncache_filter.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 992a6410a3100cc64f9f2ea674fda9151fa5d474 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Mon, 29 May 2017 14:58:33 +0200 -Subject: [PATCH 168/169] CACHE_REQ: Simplify _search_ncache_filter() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Let's make the result and input/output argument for -_search_ncache_filter() and free it inside the function whenever it's -needed instead of leaving this responsibility for the caller. - -Related: -https://pagure.io/SSSD/sssd/issue/3362 - -Signed-off-by: Fabiano Fidêncio -Reviewed-by: Pavel Březina -(cherry picked from commit c8193b1602cf44740b59f5dfcdc5330508c0c365) ---- - src/responder/common/cache_req/cache_req_search.c | 27 ++++++----------------- - 1 file changed, 7 insertions(+), 20 deletions(-) - -diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c -index 70448a7639bc9f98d380b8edce9d130adfa0ceb2..d3aaa7542ddfd28716fbf9cdcedfeadb649dbaa0 100644 ---- a/src/responder/common/cache_req/cache_req_search.c -+++ b/src/responder/common/cache_req/cache_req_search.c -@@ -86,7 +86,6 @@ static void cache_req_search_ncache_add(struct cache_req *cr) - - static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, - struct cache_req *cr, -- struct ldb_result *result, - struct ldb_result **_result) - { - TALLOC_CTX *tmp_ctx; -@@ -106,8 +105,6 @@ static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, - "This request type does not support filtering " - "result by negative cache\n"); - -- *_result = talloc_steal(mem_ctx, result); -- - ret = EOK; - goto done; - } -@@ -115,11 +112,11 @@ static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, - CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, - "Filtering out results by negative cache\n"); - -- msgs = talloc_zero_array(tmp_ctx, struct ldb_message *, result->count); -+ msgs = talloc_zero_array(tmp_ctx, struct ldb_message *, (*_result)->count); - msg_count = 0; - -- for (size_t i = 0; i < result->count; i++) { -- name = sss_get_name_from_msg(cr->domain, result->msgs[i]); -+ for (size_t i = 0; i < (*_result)->count; i++) { -+ name = sss_get_name_from_msg(cr->domain, (*_result)->msgs[i]); - if (name == NULL) { - CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, - "sss_get_name_from_msg() returned NULL, which should never " -@@ -141,7 +138,7 @@ static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, - goto done; - } - -- msgs[msg_count] = talloc_steal(msgs, result->msgs[i]); -+ msgs[msg_count] = talloc_steal(msgs, (*_result)->msgs[i]); - msg_count++; - } - -@@ -157,6 +154,7 @@ static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, - goto done; - } - -+ talloc_zfree(*_result); - *_result = talloc_steal(mem_ctx, filtered_result); - ret = EOK; - -@@ -419,10 +417,8 @@ static void cache_req_search_oob_done(struct tevent_req *subreq) - - static void cache_req_search_done(struct tevent_req *subreq) - { -- TALLOC_CTX *tmp_ctx; - struct cache_req_search_state *state; - struct tevent_req *req; -- struct ldb_result *result = NULL; - errno_t ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); -@@ -431,14 +427,8 @@ static void cache_req_search_done(struct tevent_req *subreq) - state->dp_success = state->cr->plugin->dp_recv_fn(subreq, state->cr); - talloc_zfree(subreq); - -- tmp_ctx = talloc_new(NULL); -- if (tmp_ctx == NULL) { -- ret = ENOMEM; -- goto done; -- } -- - /* Get result from cache again. */ -- ret = cache_req_search_cache(tmp_ctx, state->cr, &result); -+ ret = cache_req_search_cache(state, state->cr, &state->result); - if (ret != EOK) { - if (ret == ENOENT) { - /* Only store entry in negative cache if DP request succeeded -@@ -451,8 +441,7 @@ static void cache_req_search_done(struct tevent_req *subreq) - } - - /* ret == EOK */ -- ret = cache_req_search_ncache_filter(state, state->cr, result, -- &state->result); -+ ret = cache_req_search_ncache_filter(state, state->cr, &state->result); - if (ret != EOK) { - goto done; - } -@@ -461,8 +450,6 @@ static void cache_req_search_done(struct tevent_req *subreq) - "Returning updated object [%s]\n", state->cr->debugobj); - - done: -- talloc_free(tmp_ctx); -- - if (ret != EOK) { - tevent_req_error(req, ret); - return; --- -2.9.4 - diff --git a/SOURCES/0169-CACHE_REQ_SEARCH-Check-for-filtered-users-groups-als.patch b/SOURCES/0169-CACHE_REQ_SEARCH-Check-for-filtered-users-groups-als.patch deleted file mode 100644 index 6d53d21..0000000 --- a/SOURCES/0169-CACHE_REQ_SEARCH-Check-for-filtered-users-groups-als.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 79f389eb400eddc133824b079f8bd49ced24643b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 17 May 2017 14:43:39 +0200 -Subject: [PATCH 169/169] CACHE_REQ_SEARCH: Check for filtered users/groups - also on cache_req_send() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -cache_req_send() may take some shortcuts in case the object is found in -the cache and it's still valid. - -This behaviour may lead to exposing filtered users and groups when -they're searched by their uid/gid. - -A solution for this issue was proposed on 4ef0b19a but, unfortunately, -didn't take into consideration that this shortcut could be taken. - -There are basically two really easy ways to test this issue: - 1) Using enumeration: - - Set "enumerate = True" in the domain section - - restart SSSD cleaning up the cache; - - getent passwd - - Wait a little bit till the entry_negative_timeout is expired - - getent passwd - - 2) Not using enumeration: - - getent passwd - - Wait a little bit till the entry_negative_timeout is expired - - getent passwd - -A test covering this code path will be added in the follow-up commit. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3362 - -Signed-off-by: Fabiano Fidêncio -Reviewed-by: Pavel Březina -(cherry picked from commit 4c09cd008967c5c0ec358dc658ffc6fc1cef2697) ---- - src/responder/common/cache_req/cache_req_search.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c -index d3aaa7542ddfd28716fbf9cdcedfeadb649dbaa0..56d0345cd8f98de574961d3c9628ae7a4c24f9be 100644 ---- a/src/responder/common/cache_req/cache_req_search.c -+++ b/src/responder/common/cache_req/cache_req_search.c -@@ -334,6 +334,10 @@ cache_req_search_send(TALLOC_CTX *mem_ctx, - - done: - if (ret == EOK) { -+ ret = cache_req_search_ncache_filter(state, cr, &state->result); -+ } -+ -+ if (ret == EOK) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); --- -2.9.4 - diff --git a/SOURCES/0170-cache_req-Do-not-use-default_domain_suffix-with-netg.patch b/SOURCES/0170-cache_req-Do-not-use-default_domain_suffix-with-netg.patch deleted file mode 100644 index 78326bf..0000000 --- a/SOURCES/0170-cache_req-Do-not-use-default_domain_suffix-with-netg.patch +++ /dev/null @@ -1,34 +0,0 @@ -From eb3f60eacc6279a6bd97eff7d7be0cc081a7bf9a Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Thu, 8 Jun 2017 12:32:44 +0200 -Subject: [PATCH 170/171] cache_req: Do not use default_domain_suffix with - netgroups -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: -https://pagure.io/SSSD/sssd/issue/3428 - -Reviewed-by: Pavel Březina -(cherry picked from commit c83e265bbb5b2f2aa4f0067263753c8403c383f9) ---- - src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -index 4d8bb18579a286042b00528190dadd52fdd7c75c..ef0775d0b8eac4d679450f436d8427cff9c04582 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -+++ b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c -@@ -112,7 +112,7 @@ const struct cache_req_plugin cache_req_netgroup_by_name = { - .name = "Netgroup by name", - .attr_expiration = SYSDB_CACHE_EXPIRE, - .parse_name = true, -- .ignore_default_domain = false, -+ .ignore_default_domain = true, - .bypass_cache = false, - .only_one_result = true, - .search_all_domains = false, --- -2.9.4 - diff --git a/SOURCES/0171-krb5-disable-enterprise-principals-during-password-c.patch b/SOURCES/0171-krb5-disable-enterprise-principals-during-password-c.patch deleted file mode 100644 index 22655c1..0000000 --- a/SOURCES/0171-krb5-disable-enterprise-principals-during-password-c.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0956acb31884e87ef48c3be8c59960acfc03a547 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 8 Jun 2017 11:06:02 +0200 -Subject: [PATCH 171/171] krb5: disable enterprise principals during password - changes - -Currently using enterprise principals during password changes does not -work reliable. - -First there is a special behavior if canonicalization, which in general -should be used together with enterprise principals, is enabled with AD, -see https://pagure.io/SSSD/sssd/issue/1405 and -https://pagure.io/SSSD/sssd/issue/1615 for details. As a result of this -SSSD currently disables canonicalization during password changes. - -Additionally it looks like MIT Kerberos does not handle canonicalized -principals well, even if canonicalization is enabled, if not the default -krbtgt/REALM@REALM but kadmin/changepw@REALM is requested. Since it is -currently not clear what is the expected behavior here it make sense to -completely disable enterprise principals during password changes for the -time being. - -Resolves https://pagure.io/SSSD/sssd/issue/3426 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 614057ea85c05d3a6d4b62217a41b8b5db8d5d38) ---- - src/providers/krb5/krb5_child_handler.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c -index 11ac867e62d2ff96b827cf6d4ff341fc8ff0a286..0007f92a61ba711aed6be5ee28664e5f7de0f226 100644 ---- a/src/providers/krb5/krb5_child_handler.c -+++ b/src/providers/krb5/krb5_child_handler.c -@@ -143,7 +143,8 @@ static errno_t create_send_buffer(struct krb5child_req *kr, - return EINVAL; - } - -- if (kr->pd->cmd == SSS_CMD_RENEW || kr->is_offline) { -+ if (kr->pd->cmd == SSS_CMD_RENEW || kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM -+ || kr->pd->cmd == SSS_PAM_CHAUTHTOK || kr->is_offline) { - use_enterprise_principal = false; - } else { - use_enterprise_principal = dp_opt_get_bool(kr->krb5_ctx->opts, --- -2.9.4 - diff --git a/SOURCES/0172-pam_sss-Fix-leaking-of-memory-in-case-of-failures.patch b/SOURCES/0172-pam_sss-Fix-leaking-of-memory-in-case-of-failures.patch deleted file mode 100644 index 7c9d403..0000000 --- a/SOURCES/0172-pam_sss-Fix-leaking-of-memory-in-case-of-failures.patch +++ /dev/null @@ -1,44 +0,0 @@ -From c58aac42664dd1a04edb37b0874109a6a88d0da1 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 5 Jun 2017 09:43:46 +0200 -Subject: [PATCH 172/181] pam_sss: Fix leaking of memory in case of failures -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Found by coverity. - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 818d01b4a0d332fff06db33c0c985b8c0f1417c7) ---- - src/sss_client/pam_sss.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c -index 9732459e6fb7ce01c9445c423cf0a583ca36e036..303809b9ea05b5a8709c05ae230d5f289b57de31 100644 ---- a/src/sss_client/pam_sss.c -+++ b/src/sss_client/pam_sss.c -@@ -1517,10 +1517,12 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) - if (pi->user_name_hint) { - ret = pam_get_item(pamh, PAM_CONV, (const void **)&conv); - if (ret != PAM_SUCCESS) { -+ free(prompt); - return ret; - } - if (conv == NULL || conv->conv == NULL) { - logger(pamh, LOG_ERR, "No conversation function"); -+ free(prompt); - return PAM_SYSTEM_ERR; - } - -@@ -1540,6 +1542,7 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) - mesg[1] = &((*mesg)[1]); - - ret = conv->conv(2, mesg, &resp, conv->appdata_ptr); -+ free(prompt); - if (ret != PAM_SUCCESS) { - D(("Conversation failure: %s.", pam_strerror(pamh, ret))); - return ret; --- -2.9.4 - diff --git a/SOURCES/0173-IFP-Add-domain-and-domainname-attributes-to-the-user.patch b/SOURCES/0173-IFP-Add-domain-and-domainname-attributes-to-the-user.patch deleted file mode 100644 index be61e37..0000000 --- a/SOURCES/0173-IFP-Add-domain-and-domainname-attributes-to-the-user.patch +++ /dev/null @@ -1,372 +0,0 @@ -From a35b5c33a76857ad9223363e15558facec5c269d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Thu, 8 Jun 2017 11:46:25 +0200 -Subject: [PATCH 173/181] IFP: Add domain and domainname attributes to the user -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -org.freedekstop.sssd.infopipe.Users.User gets two new attributes: -- domain: object path of user's domain -- domainname: user's domain name - -org.freedekstop.sssd.infopipe.GetUserAttr can now request new attribute: -- domainname: user's domain name - -Resolves: -https://pagure.io/SSSD/sssd/issue/2714 - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 37d2194cc9ea4d0254c88a3419e2376572562bab) ---- - src/responder/ifp/ifp_iface.c | 2 + - src/responder/ifp/ifp_iface.xml | 2 + - src/responder/ifp/ifp_iface_generated.c | 18 ++++++++ - src/responder/ifp/ifp_iface_generated.h | 4 ++ - src/responder/ifp/ifp_private.h | 4 ++ - src/responder/ifp/ifp_users.c | 46 ++++++++++++++++++++ - src/responder/ifp/ifp_users.h | 8 ++++ - src/responder/ifp/ifpsrv_cmd.c | 8 ++++ - src/responder/ifp/ifpsrv_util.c | 74 ++++++++++++++++++++++++++++++++- - src/tests/cmocka/test_ifp.c | 12 ++++-- - 10 files changed, 173 insertions(+), 5 deletions(-) - -diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c -index e413e74f955c067a0efbe385a08b4b2cc6f2bba1..3293b92d750d33b2ecf77a03098c5169d052c924 100644 ---- a/src/responder/ifp/ifp_iface.c -+++ b/src/responder/ifp/ifp_iface.c -@@ -104,6 +104,8 @@ struct iface_ifp_users_user iface_ifp_users_user = { - .get_loginShell = ifp_users_user_get_login_shell, - .get_uniqueID = ifp_users_user_get_unique_id, - .get_groups = ifp_users_user_get_groups, -+ .get_domain = ifp_users_user_get_domain, -+ .get_domainname = ifp_users_user_get_domainname, - .get_extraAttributes = ifp_users_user_get_extra_attributes - }; - -diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml -index 0a23f56907f64c4c24db3ec3c0a312adbdb3edc8..ce071bb999bd207b8cc81f054da80de52a13d3df 100644 ---- a/src/responder/ifp/ifp_iface.xml -+++ b/src/responder/ifp/ifp_iface.xml -@@ -188,6 +188,8 @@ - - - -+ -+ - - - -diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c -index 211646b6760d15e0df55ac20b9611b800b11d16c..51db4a9e5c7d72663f8845bd0da22d3f21526be8 100644 ---- a/src/responder/ifp/ifp_iface_generated.c -+++ b/src/responder/ifp/ifp_iface_generated.c -@@ -982,6 +982,24 @@ const struct sbus_property_meta iface_ifp_users_user__properties[] = { - NULL, /* no invoker */ - }, - { -+ "domain", /* name */ -+ "o", /* type */ -+ SBUS_PROPERTY_READABLE, -+ offsetof(struct iface_ifp_users_user, get_domain), -+ sbus_invoke_get_o, -+ 0, /* not writable */ -+ NULL, /* no invoker */ -+ }, -+ { -+ "domainname", /* name */ -+ "s", /* type */ -+ SBUS_PROPERTY_READABLE, -+ offsetof(struct iface_ifp_users_user, get_domainname), -+ sbus_invoke_get_s, -+ 0, /* not writable */ -+ NULL, /* no invoker */ -+ }, -+ { - "extraAttributes", /* name */ - "a{sas}", /* type */ - SBUS_PROPERTY_READABLE, -diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h -index e69fc3a3efc6bdcef5d6539790908795818cd857..76f729fcb268e9c07668b3a5ee5bbd7d0b44ca16 100644 ---- a/src/responder/ifp/ifp_iface_generated.h -+++ b/src/responder/ifp/ifp_iface_generated.h -@@ -88,6 +88,8 @@ - #define IFACE_IFP_USERS_USER_LOGINSHELL "loginShell" - #define IFACE_IFP_USERS_USER_UNIQUEID "uniqueID" - #define IFACE_IFP_USERS_USER_GROUPS "groups" -+#define IFACE_IFP_USERS_USER_DOMAIN "domain" -+#define IFACE_IFP_USERS_USER_DOMAINNAME "domainname" - #define IFACE_IFP_USERS_USER_EXTRAATTRIBUTES "extraAttributes" - - /* constants for org.freedesktop.sssd.infopipe.Groups */ -@@ -288,6 +290,8 @@ struct iface_ifp_users_user { - void (*get_loginShell)(struct sbus_request *, void *data, const char **); - void (*get_uniqueID)(struct sbus_request *, void *data, const char **); - void (*get_groups)(struct sbus_request *, void *data, const char ***, int *); -+ void (*get_domain)(struct sbus_request *, void *data, const char **); -+ void (*get_domainname)(struct sbus_request *, void *data, const char **); - void (*get_extraAttributes)(struct sbus_request *, void *data, hash_table_t **); - }; - -diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h -index e800070a59f77f8ce58a2fc402e616bb773e996b..a6e5701b8d1ebb27af0c35fa3ebe0c6c00d16bd6 100644 ---- a/src/responder/ifp/ifp_private.h -+++ b/src/responder/ifp/ifp_private.h -@@ -70,6 +70,10 @@ errno_t ifp_req_create(struct sbus_request *dbus_req, - /* Returns an appropriate DBus error for specific ifp_req_create failures */ - int ifp_req_create_handle_failure(struct sbus_request *dbus_req, errno_t err); - -+errno_t ifp_add_value_to_dict(DBusMessageIter *iter_dict, -+ const char *key, -+ const char *value); -+ - errno_t ifp_add_ldb_el_to_dict(DBusMessageIter *iter_dict, - struct ldb_message_element *el); - const char ** -diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c -index 188194f2ab356d0e67b0f26b003f3a9ce48e6acd..90b947ed9ca345fbeba6772c90f898451a0868aa 100644 ---- a/src/responder/ifp/ifp_users.c -+++ b/src/responder/ifp/ifp_users.c -@@ -1328,6 +1328,52 @@ void ifp_users_user_get_groups(struct sbus_request *sbus_req, - *_size = num_groups; - } - -+void ifp_users_user_get_domain(struct sbus_request *sbus_req, -+ void *data, -+ const char **_out) -+{ -+ const char *domainname; -+ -+ *_out = NULL; -+ ifp_users_user_get_domainname(sbus_req, data, &domainname); -+ -+ if (domainname == NULL) { -+ return; -+ } -+ -+ *_out = sbus_opath_compose(sbus_req, IFP_PATH_DOMAINS, -+ domainname); -+} -+ -+void ifp_users_user_get_domainname(struct sbus_request *sbus_req, -+ void *data, -+ const char **_out) -+{ -+ struct ifp_ctx *ifp_ctx; -+ struct sss_domain_info *domain; -+ errno_t ret; -+ -+ *_out = NULL; -+ -+ ifp_ctx = talloc_get_type(data, struct ifp_ctx); -+ if (ifp_ctx == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n"); -+ return; -+ } -+ -+ if (!ifp_is_user_attr_allowed(ifp_ctx, "domainname")) { -+ DEBUG(SSSDBG_TRACE_ALL, "Attribute domainname is not allowed\n"); -+ return; -+ } -+ -+ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, NULL); -+ if (ret != EOK) { -+ return; -+ } -+ -+ *_out = domain->name; -+} -+ - void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, - void *data, - hash_table_t **_out) -diff --git a/src/responder/ifp/ifp_users.h b/src/responder/ifp/ifp_users.h -index f8fefeb7f658b6e0a5f72371da1b025d69e6f412..715a8bc31996bfd93c21dbe263f2567bd0b50b03 100644 ---- a/src/responder/ifp/ifp_users.h -+++ b/src/responder/ifp/ifp_users.h -@@ -103,6 +103,14 @@ void ifp_users_user_get_groups(struct sbus_request *sbus_req, - const char ***_out, - int *_size); - -+void ifp_users_user_get_domain(struct sbus_request *sbus_req, -+ void *data, -+ const char **_out); -+ -+void ifp_users_user_get_domainname(struct sbus_request *sbus_req, -+ void *data, -+ const char **_out); -+ - void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, - void *data, - hash_table_t **_out); -diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c -index 70728e1bb656fd032b7f1c240683e8aa3b91a726..d86aed57206ba8f0a6facbd64051fa7c901513f3 100644 ---- a/src/responder/ifp/ifpsrv_cmd.c -+++ b/src/responder/ifp/ifpsrv_cmd.c -@@ -233,6 +233,14 @@ ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, - } - - for (ai = 0; attrs[ai]; ai++) { -+ if (strcmp(attrs[ai], "domainname") == 0) { -+ ret = ifp_add_value_to_dict(&iter_dict, "domainname", -+ domain->name); -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Cannot add attribute %s to message\n", attrs[ai]); -+ continue; -+ } -+ - el = sss_view_ldb_msg_find_element(domain, res->msgs[0], attrs[ai]); - if (el == NULL || el->num_values == 0) { - DEBUG(SSSDBG_MINOR_FAILURE, -diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c -index 5866d30d8a5845c21f5b05fc5de150162eba747e..643881515fb4805ae93ba56c3bca9d1da7796319 100644 ---- a/src/responder/ifp/ifpsrv_util.c -+++ b/src/responder/ifp/ifpsrv_util.c -@@ -29,7 +29,7 @@ - #define IFP_USER_DEFAULT_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \ - SYSDB_GIDNUM, SYSDB_GECOS, \ - SYSDB_HOMEDIR, SYSDB_SHELL, \ -- "groups", \ -+ "groups", "domain", "domainname", \ - NULL} - - errno_t ifp_req_create(struct sbus_request *dbus_req, -@@ -100,6 +100,78 @@ int ifp_req_create_handle_failure(struct sbus_request *dbus_req, errno_t err) - "Cannot create IFP request\n")); - } - -+errno_t ifp_add_value_to_dict(DBusMessageIter *iter_dict, -+ const char *key, -+ const char *value) -+{ -+ DBusMessageIter iter_dict_entry; -+ DBusMessageIter iter_dict_val; -+ DBusMessageIter iter_array; -+ dbus_bool_t dbret; -+ -+ if (value == NULL || key == NULL) { -+ return EINVAL; -+ } -+ -+ dbret = dbus_message_iter_open_container(iter_dict, -+ DBUS_TYPE_DICT_ENTRY, NULL, -+ &iter_dict_entry); -+ if (!dbret) { -+ return ENOMEM; -+ } -+ -+ /* Start by appending the key */ -+ dbret = dbus_message_iter_append_basic(&iter_dict_entry, -+ DBUS_TYPE_STRING, &key); -+ if (!dbret) { -+ return ENOMEM; -+ } -+ -+ dbret = dbus_message_iter_open_container(&iter_dict_entry, -+ DBUS_TYPE_VARIANT, -+ DBUS_TYPE_ARRAY_AS_STRING -+ DBUS_TYPE_STRING_AS_STRING, -+ &iter_dict_val); -+ if (!dbret) { -+ return ENOMEM; -+ } -+ -+ /* Open container for values */ -+ dbret = dbus_message_iter_open_container(&iter_dict_val, -+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, -+ &iter_array); -+ if (!dbret) { -+ return ENOMEM; -+ } -+ -+ dbret = dbus_message_iter_append_basic(&iter_array, -+ DBUS_TYPE_STRING, -+ &value); -+ if (!dbret) { -+ return ENOMEM; -+ } -+ -+ dbret = dbus_message_iter_close_container(&iter_dict_val, -+ &iter_array); -+ if (!dbret) { -+ return ENOMEM; -+ } -+ -+ dbret = dbus_message_iter_close_container(&iter_dict_entry, -+ &iter_dict_val); -+ if (!dbret) { -+ return ENOMEM; -+ } -+ -+ dbret = dbus_message_iter_close_container(iter_dict, -+ &iter_dict_entry); -+ if (!dbret) { -+ return ENOMEM; -+ } -+ -+ return EOK; -+} -+ - errno_t ifp_add_ldb_el_to_dict(DBusMessageIter *iter_dict, - struct ldb_message_element *el) - { -diff --git a/src/tests/cmocka/test_ifp.c b/src/tests/cmocka/test_ifp.c -index 21c5475d1c74cd8325815653166bef194ea84f7b..45f718341222c6803a65130741590e10e7aded84 100644 ---- a/src/tests/cmocka/test_ifp.c -+++ b/src/tests/cmocka/test_ifp.c -@@ -269,7 +269,7 @@ void test_attr_acl(void **state) - const char *exp_defaults[] = { SYSDB_NAME, SYSDB_UIDNUM, - SYSDB_GIDNUM, SYSDB_GECOS, - SYSDB_HOMEDIR, SYSDB_SHELL, -- "groups", NULL }; -+ "groups", "domain", "domainname", NULL }; - attr_parse_test(exp_defaults, NULL); - - /* Test adding some attributes to the defaults */ -@@ -277,13 +277,14 @@ void test_attr_acl(void **state) - SYSDB_NAME, SYSDB_UIDNUM, - SYSDB_GIDNUM, SYSDB_GECOS, - SYSDB_HOMEDIR, SYSDB_SHELL, -- "groups", NULL }; -+ "groups", "domain", "domainname", NULL }; - attr_parse_test(exp_add, "+telephoneNumber, +streetAddress"); - - /* Test removing some attributes to the defaults */ - const char *exp_rm[] = { SYSDB_NAME, - SYSDB_GIDNUM, SYSDB_GECOS, - SYSDB_HOMEDIR, "groups", -+ "domain", "domainname", - NULL }; - attr_parse_test(exp_rm, "-"SYSDB_SHELL ",-"SYSDB_UIDNUM); - -@@ -292,6 +293,7 @@ void test_attr_acl(void **state) - SYSDB_NAME, SYSDB_UIDNUM, - SYSDB_GIDNUM, SYSDB_GECOS, - SYSDB_HOMEDIR, "groups", -+ "domain", "domainname", - NULL }; - attr_parse_test(exp_add_rm, "+telephoneNumber, -"SYSDB_SHELL); - -@@ -299,7 +301,8 @@ void test_attr_acl(void **state) - const char *exp_add_rm_override[] = { SYSDB_NAME, SYSDB_UIDNUM, - SYSDB_GIDNUM, SYSDB_GECOS, - SYSDB_HOMEDIR, SYSDB_SHELL, -- "groups", NULL }; -+ "groups", "domain", -+ "domainname", NULL }; - attr_parse_test(exp_add_rm_override, - "+telephoneNumber, -telephoneNumber, +telephoneNumber"); - -@@ -307,7 +310,8 @@ void test_attr_acl(void **state) - const char *rm_all[] = { NULL }; - attr_parse_test(rm_all, "-"SYSDB_NAME ", -"SYSDB_UIDNUM - ", -"SYSDB_GIDNUM ", -"SYSDB_GECOS -- ", -"SYSDB_HOMEDIR ", -"SYSDB_SHELL", -groups"); -+ ", -"SYSDB_HOMEDIR ", -"SYSDB_SHELL", -groups, " -+ "-domain, -domainname"); - - /* Malformed list */ - attr_parse_test(NULL, "missing_plus_or_minus"); --- -2.9.4 - diff --git a/SOURCES/0174-IFP-Fix-error-handling-in-ifp_user_get_attr_handle_r.patch b/SOURCES/0174-IFP-Fix-error-handling-in-ifp_user_get_attr_handle_r.patch deleted file mode 100644 index 4d39c22..0000000 --- a/SOURCES/0174-IFP-Fix-error-handling-in-ifp_user_get_attr_handle_r.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 271679e7a7c0c50e39c7a0989dbae77385475c60 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 14 Jun 2017 18:25:21 +0200 -Subject: [PATCH 174/181] IFP: Fix error handling in - ifp_user_get_attr_handle_reply() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This bug was introduced in 37d2194cc9ea4d0254c88a3419e2376572562bab - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 15a76bb7bd9791a3ed1ae416f70753d32c6ff599) ---- - src/responder/ifp/ifpsrv_cmd.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c -index d86aed57206ba8f0a6facbd64051fa7c901513f3..fc9161e82e906ac7dde2712ffc7c0cbb58c519b7 100644 ---- a/src/responder/ifp/ifpsrv_cmd.c -+++ b/src/responder/ifp/ifpsrv_cmd.c -@@ -236,9 +236,11 @@ ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, - if (strcmp(attrs[ai], "domainname") == 0) { - ret = ifp_add_value_to_dict(&iter_dict, "domainname", - domain->name); -- DEBUG(SSSDBG_MINOR_FAILURE, -- "Cannot add attribute %s to message\n", attrs[ai]); -- continue; -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Cannot add attribute domainname to message\n"); -+ continue; -+ } - } - - el = sss_view_ldb_msg_find_element(domain, res->msgs[0], attrs[ai]); --- -2.9.4 - diff --git a/SOURCES/0175-SYSDB-Return-ERR_NO_TS-when-there-s-no-timestamp-cac.patch b/SOURCES/0175-SYSDB-Return-ERR_NO_TS-when-there-s-no-timestamp-cac.patch deleted file mode 100644 index 748f9e8..0000000 --- a/SOURCES/0175-SYSDB-Return-ERR_NO_TS-when-there-s-no-timestamp-cac.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 10b75d84300726e5e311b0488352b891f106d631 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 24 May 2017 00:35:23 +0200 -Subject: [PATCH 175/181] SYSDB: Return ERR_NO_TS when there's no timestamp - cache present -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This change affects sysdb_search_ts_{users,groups} functions and is -mainly needed in order to avoid breaking our current tests due to the -changes planned for fixing https://pagure.io/SSSD/sssd/issue/3369. - -Related: -https://pagure.io/SSSD/sssd/issue/3369 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 01c6bb9b47401f9f14c4cfe5c5f03fce2e63629b) ---- - src/db/sysdb_ops.c | 4 ++-- - src/db/sysdb_search.c | 8 ++++++++ - 2 files changed, 10 insertions(+), 2 deletions(-) - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 4d7b2abd8026c90aaf4e7be687102e459cf3690e..12f8095d2edc60ffab09c92d64f968892c577bbf 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -3520,7 +3520,7 @@ int sysdb_search_ts_users(TALLOC_CTX *mem_ctx, - ZERO_STRUCT(*res); - - if (domain->sysdb->ldb_ts == NULL) { -- return ENOENT; -+ return ERR_NO_TS; - } - - ret = sysdb_cache_search_users(mem_ctx, domain, domain->sysdb->ldb_ts, -@@ -3737,7 +3737,7 @@ int sysdb_search_ts_groups(TALLOC_CTX *mem_ctx, - ZERO_STRUCT(*res); - - if (domain->sysdb->ldb_ts == NULL) { -- return ENOENT; -+ return ERR_NO_TS; - } - - ret = sysdb_cache_search_groups(mem_ctx, domain, domain->sysdb->ldb_ts, -diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c -index 474bc08f0b2fe3b0289cbea96fbf2619ced271e7..6b4b51383d89788052ab7e4b572e86abba5330db 100644 ---- a/src/db/sysdb_search.c -+++ b/src/db/sysdb_search.c -@@ -587,6 +587,10 @@ int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx, - ret = sysdb_search_ts_users(tmp_ctx, domain, ts_filter, - sysdb_ts_cache_attrs, - &ts_res); -+ if (ret == ERR_NO_TS) { -+ ret = ENOENT; -+ } -+ - if (ret != EOK && ret != ENOENT) { - goto done; - } -@@ -1088,6 +1092,10 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx, - ret = sysdb_search_ts_groups(tmp_ctx, domain, ts_filter, - sysdb_ts_cache_attrs, - &ts_res); -+ if (ret == ERR_NO_TS) { -+ ret = ENOENT; -+ } -+ - if (ret != EOK && ret != ENOENT) { - goto done; - } --- -2.9.4 - diff --git a/SOURCES/0176-SYSDB-Internally-expose-sysdb_search_ts_matches.patch b/SOURCES/0176-SYSDB-Internally-expose-sysdb_search_ts_matches.patch deleted file mode 100644 index 38fdfa6..0000000 --- a/SOURCES/0176-SYSDB-Internally-expose-sysdb_search_ts_matches.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 67e592572e655f19326cf821bbbe43411e8c7b06 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Tue, 23 May 2017 22:44:24 +0200 -Subject: [PATCH 176/181] SYSDB: Internally expose sysdb_search_ts_matches() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This function will be used in the follow-up patches. As it's going to be -"exposed", let's also rename it from search_ts_matches() to -sysdb_search_ts_matches(). - -Related: -https://pagure.io/SSSD/sssd/issue/3369 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 347be58e1769ba90b49a7e5ec1678ef66987f6cd) ---- - src/db/sysdb_private.h | 7 +++++++ - src/db/sysdb_search.c | 20 ++++++++++---------- - 2 files changed, 17 insertions(+), 10 deletions(-) - -diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h -index dfddd2dda9e593bd02d52dee7d06f520a11bbdf6..433220dcc0c35366dbbee41525e6c5932eb897f9 100644 ---- a/src/db/sysdb_private.h -+++ b/src/db/sysdb_private.h -@@ -260,6 +260,13 @@ int sysdb_search_ts_groups(TALLOC_CTX *mem_ctx, - const char **attrs, - struct ldb_result *res); - -+errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, -+ const char *attrs[], -+ struct ldb_result *ts_res, -+ const char *filter, -+ struct ldb_result **_res); -+ - /* Compares the modifyTimestamp attribute between old_entry and - * new_entry. Returns true if they differ (or either entry is missing - * the attribute) and false if the attribute is the same -diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c -index 6b4b51383d89788052ab7e4b572e86abba5330db..0c04b84a584e047a0ba8243c9216547ea2791e60 100644 ---- a/src/db/sysdb_search.c -+++ b/src/db/sysdb_search.c -@@ -482,12 +482,12 @@ done: - return ret; - } - --static errno_t search_ts_matches(TALLOC_CTX *mem_ctx, -- struct sysdb_ctx *sysdb, -- const char *attrs[], -- struct ldb_result *ts_res, -- const char *filter, -- struct ldb_result **_res) -+errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, -+ const char *attrs[], -+ struct ldb_result *ts_res, -+ const char *filter, -+ struct ldb_result **_res) - { - char *dn_filter; - TALLOC_CTX *tmp_ctx = NULL; -@@ -595,8 +595,8 @@ int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx, - goto done; - } - -- ret = search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, -- name_filter, &ts_cache_res); -+ ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, -+ name_filter, &ts_cache_res); - if (ret != EOK && ret != ENOENT) { - goto done; - } -@@ -1100,8 +1100,8 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx, - goto done; - } - -- ret = search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, -- name_filter, &ts_cache_res); -+ ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, -+ name_filter, &ts_cache_res); - if (ret != EOK && ret != ENOENT) { - goto done; - } --- -2.9.4 - diff --git a/SOURCES/0177-SYSDB-Make-the-usage-of-the-filter-more-generic-for-.patch b/SOURCES/0177-SYSDB-Make-the-usage-of-the-filter-more-generic-for-.patch deleted file mode 100644 index 89eb87a..0000000 --- a/SOURCES/0177-SYSDB-Make-the-usage-of-the-filter-more-generic-for-.patch +++ /dev/null @@ -1,157 +0,0 @@ -From 7d926fb2e8fe21e3fa51bc341189d33658600daf Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 24 May 2017 11:52:23 +0200 -Subject: [PATCH 177/181] SYSDB: Make the usage of the filter more generic for - search_ts_matches() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In order to make this function re-usable in different parts of our code, -let's start passing an already built filter to it instead of having the -specific code building the name filter there. - -Related: -https://pagure.io/SSSD/sssd/issue/3369 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 8ad57e17779b3ec60246ac58c1691ee15745084c) ---- - src/db/sysdb_search.c | 67 +++++++++++++++++++++++++++++++++++++++++---------- - 1 file changed, 54 insertions(+), 13 deletions(-) - -diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c -index 0c04b84a584e047a0ba8243c9216547ea2791e60..f488442afcc6eef114437a7110722759f86fe19e 100644 ---- a/src/db/sysdb_search.c -+++ b/src/db/sysdb_search.c -@@ -489,7 +489,6 @@ errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, - const char *filter, - struct ldb_result **_res) - { -- char *dn_filter; - TALLOC_CTX *tmp_ctx = NULL; - struct ldb_result *res; - errno_t ret; -@@ -501,7 +500,7 @@ errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, - } - - tmp_ctx = talloc_new(NULL); -- if (!tmp_ctx) { -+ if (tmp_ctx == NULL) { - return ENOMEM; - } - -@@ -511,7 +510,43 @@ errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, - goto done; - } - -- dn_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(|", SYSDB_NAME, filter); -+ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, NULL, -+ LDB_SCOPE_SUBTREE, attrs, "%s", filter); -+ if (ret) { -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ -+ *_res = talloc_steal(mem_ctx, res); -+ ret = EOK; -+ -+done: -+ talloc_zfree(tmp_ctx); -+ return ret; -+} -+ -+static errno_t sysdb_enum_dn_filter(TALLOC_CTX *mem_ctx, -+ struct ldb_result *ts_res, -+ const char *name_filter, -+ char **_dn_filter) -+{ -+ TALLOC_CTX *tmp_ctx = NULL; -+ char *dn_filter; -+ errno_t ret; -+ -+ if (ts_res->count == 0) { -+ *_dn_filter = NULL; -+ ret = EOK; -+ goto done; -+ } -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ dn_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(|", SYSDB_NAME, -+ name_filter); - if (dn_filter == NULL) { - ret = ENOMEM; - goto done; -@@ -535,15 +570,9 @@ errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, - goto done; - } - -- ret = ldb_search(sysdb->ldb, tmp_ctx, &res, NULL, -- LDB_SCOPE_SUBTREE, attrs, "%s", dn_filter); -- if (ret) { -- ret = sysdb_error_to_errno(ret); -- goto done; -- } -- -+ *_dn_filter = talloc_steal(mem_ctx, dn_filter); - ret = EOK; -- *_res = talloc_steal(mem_ctx, res); -+ - done: - talloc_zfree(tmp_ctx); - return ret; -@@ -558,6 +587,7 @@ int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx, - TALLOC_CTX *tmp_ctx; - static const char *attrs[] = SYSDB_PW_ATTRS; - char *filter = NULL; -+ char *dn_filter = NULL; - const char *ts_filter = NULL; - struct ldb_dn *base_dn; - struct ldb_result *res; -@@ -595,8 +625,13 @@ int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx, - goto done; - } - -+ ret = sysdb_enum_dn_filter(tmp_ctx, &ts_res, name_filter, &dn_filter); -+ if (ret != EOK) { -+ goto done; -+ } -+ - ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, -- name_filter, &ts_cache_res); -+ dn_filter, &ts_cache_res); - if (ret != EOK && ret != ENOENT) { - goto done; - } -@@ -1052,6 +1087,7 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx, - const char *filter = NULL; - const char *ts_filter = NULL; - const char *base_filter; -+ char *dn_filter = NULL; - struct ldb_dn *base_dn; - struct ldb_result *res; - struct ldb_result ts_res; -@@ -1100,8 +1136,13 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx, - goto done; - } - -+ ret = sysdb_enum_dn_filter(tmp_ctx, &ts_res, name_filter, &dn_filter); -+ if (ret != EOK) { -+ goto done; -+ } -+ - ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, -- name_filter, &ts_cache_res); -+ dn_filter, &ts_cache_res); - if (ret != EOK && ret != ENOENT) { - goto done; - } --- -2.9.4 - diff --git a/SOURCES/0178-SYSDB_OPS-Mark-an-entry-as-expired-also-in-the-times.patch b/SOURCES/0178-SYSDB_OPS-Mark-an-entry-as-expired-also-in-the-times.patch deleted file mode 100644 index b4cbbf8..0000000 --- a/SOURCES/0178-SYSDB_OPS-Mark-an-entry-as-expired-also-in-the-times.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 891e9c7cb924830334a42864ef2582e545f42723 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Mon, 29 May 2017 13:32:59 +0200 -Subject: [PATCH 178/181] SYSDB_OPS: Mark an entry as expired also in the - timestamp cache -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -As the cleanup task will start using new methods for searching the users -and groups which have to be cleaned up, SSSD starts relying more in a -more consistent state of the timestamp cache on pretty much everything -related to the cleanup task. - -One of the things that would cause SSSD some problems is not having the -ghost user expired in the persistent cache but not in the timestamp -cache. - -With this patch, the entry is also expired in the timestamp cache when -it's present. - -Related: -https://pagure.io/SSSD/sssd/issue/3369 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 9883d1e2913ff0c1db479f1ece8148e03155c7f3) ---- - src/db/sysdb_ops.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 12f8095d2edc60ffab09c92d64f968892c577bbf..ae26470487f859fe1de1dc364b6a05b9793a0545 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -5065,6 +5065,15 @@ errno_t sysdb_mark_entry_as_expired_ldb_dn(struct sss_domain_info *dom, - goto done; - } - -+ if (dom->sysdb->ldb_ts != NULL) { -+ ret = ldb_modify(dom->sysdb->ldb_ts, msg); -+ if (ret != LDB_SUCCESS) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Could not mark an entry as expired in the timestamp cache\n"); -+ /* non-fatal */ -+ } -+ } -+ - ret = EOK; - - done: --- -2.9.4 - diff --git a/SOURCES/0179-SYSDB_OPS-Invalidate-a-cache-entry-also-in-the-ts_ca.patch b/SOURCES/0179-SYSDB_OPS-Invalidate-a-cache-entry-also-in-the-ts_ca.patch deleted file mode 100644 index e6512c2..0000000 --- a/SOURCES/0179-SYSDB_OPS-Invalidate-a-cache-entry-also-in-the-ts_ca.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 256e1b4162832570e10a85579d2b14ed7b54b7f2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Mon, 29 May 2017 13:29:26 +0200 -Subject: [PATCH 179/181] SYSDB_OPS: Invalidate a cache entry also in the - ts_cache -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Similarly to what has been in the previous commit (expiring an entry -also in the timestamp cache), we should do the same when invalidating an -entry. - -Related: -https://pagure.io/SSSD/sssd/issue/3369 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Jakub Hrozek -(cherry picked from commit a71f1a655dcc2ca6dc16bb8eb1c4c9e24cfe2c3e) ---- - src/db/sysdb_ops.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index ae26470487f859fe1de1dc364b6a05b9793a0545..ed936f0cb1a37155aabef96db1d267eb03ec0ed9 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -5160,6 +5160,17 @@ int sysdb_invalidate_cache_entry(struct sss_domain_info *domain, - goto done; - } - -+ if (sysdb->ldb_ts != NULL) { -+ ret = sysdb_set_cache_entry_attr(sysdb->ldb_ts, entry_dn, -+ attrs, SYSDB_MOD_REP); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Cannot set attrs in the timestamp cache for %s, %d [%s]\n", -+ ldb_dn_get_linearized(entry_dn), ret, sss_strerror(ret)); -+ /* non-fatal */ -+ } -+ } -+ - DEBUG(SSSDBG_FUNC_DATA, - "Cache entry [%s] has been invalidated.\n", - ldb_dn_get_linearized(entry_dn)); --- -2.9.4 - diff --git a/SOURCES/0180-SYSDB-Introduce-_search_-users-groups-_by_timestamp.patch b/SOURCES/0180-SYSDB-Introduce-_search_-users-groups-_by_timestamp.patch deleted file mode 100644 index 5bfa491..0000000 --- a/SOURCES/0180-SYSDB-Introduce-_search_-users-groups-_by_timestamp.patch +++ /dev/null @@ -1,278 +0,0 @@ -From 11c34233ac7385c6f2a65c5cc57dfefb1cae48cd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 7 Jun 2017 15:07:10 +0200 -Subject: [PATCH 180/181] SYSDB: Introduce - _search_{users,groups}_by_timestamp() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -These new two sysdb methods are going to be used, at least for now, -uniquely and exclusively in the cleanup task. - -The reason for adding those is that during the cleanup task a timestamp -search is done in the persistent cache, which doesn't have the updated -timestamps, returning then a wrong result that ends up in having all the -users being removed from the cache. - -The persistent cache doesn't have its entries' timestamps updated -because those are kept updated in the timestamp cache, therefore these -new two methods end up doing: -- if the timestamp cache is present: - - search for the entries solely in the timestamp cache; - - get the needed attributes from these entries from the persistent - cache; -- otherwise: - - search for the entries in the persistent cache; - - merge its results with timestamp cache's results; - -Related: -https://pagure.io/SSSD/sssd/issue/3369 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 41708e1e500e7cada3d3e606aa2b8b9869a5c734) ---- - src/db/sysdb.h | 14 +++++ - src/db/sysdb_ops.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 192 insertions(+) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 62c561be9452a284a8ddf8ebb45720265852c8b0..21d6cf4fc90a050e203e1609be5ee267a618dda9 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -1142,6 +1142,13 @@ int sysdb_search_users(TALLOC_CTX *mem_ctx, - size_t *msgs_count, - struct ldb_message ***msgs); - -+int sysdb_search_users_by_timestamp(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domain, -+ const char *sub_filter, -+ const char **attrs, -+ size_t *_msgs_count, -+ struct ldb_message ***_msgs); -+ - int sysdb_delete_user(struct sss_domain_info *domain, - const char *name, uid_t uid); - -@@ -1152,6 +1159,13 @@ int sysdb_search_groups(TALLOC_CTX *mem_ctx, - size_t *msgs_count, - struct ldb_message ***msgs); - -+int sysdb_search_groups_by_timestamp(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domain, -+ const char *sub_filter, -+ const char **attrs, -+ size_t *_msgs_count, -+ struct ldb_message ***_msgs); -+ - int sysdb_delete_group(struct sss_domain_info *domain, - const char *name, gid_t gid); - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index ed936f0cb1a37155aabef96db1d267eb03ec0ed9..7ca6575ce75dab7805236c9f48dbf28a2f3946d2 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -374,6 +374,58 @@ enum sysdb_obj_type { - SYSDB_GROUP - }; - -+static errno_t cleanup_dn_filter(TALLOC_CTX *mem_ctx, -+ struct ldb_result *ts_res, -+ const char *object_class, -+ const char *filter, -+ char **_dn_filter) -+{ -+ TALLOC_CTX *tmp_ctx; -+ char *dn_filter; -+ errno_t ret; -+ -+ if (ts_res->count == 0) { -+ *_dn_filter = NULL; -+ return EOK; -+ } -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ dn_filter = talloc_asprintf(tmp_ctx, "(&(%s)%s(|", object_class, filter); -+ if (dn_filter == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ for (size_t i = 0; i < ts_res->count; i++) { -+ dn_filter = talloc_asprintf_append( -+ dn_filter, -+ "(%s=%s)", -+ SYSDB_DN, -+ ldb_dn_get_linearized(ts_res->msgs[i]->dn)); -+ if (dn_filter == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ dn_filter = talloc_asprintf_append(dn_filter, "))"); -+ if (dn_filter == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ *_dn_filter = talloc_steal(mem_ctx, dn_filter); -+ ret = EOK; -+ -+done: -+ talloc_zfree(tmp_ctx); -+ return ret; -+} -+ - static int sysdb_search_by_name(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - const char *name, -@@ -3503,6 +3555,69 @@ int sysdb_search_users(TALLOC_CTX *mem_ctx, - attrs); - } - -+int sysdb_search_users_by_timestamp(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domain, -+ const char *sub_filter, -+ const char **attrs, -+ size_t *_msgs_count, -+ struct ldb_message ***_msgs) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct ldb_result *res; -+ struct ldb_result ts_res; -+ struct ldb_message **msgs; -+ size_t msgs_count; -+ char *dn_filter = NULL; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = sysdb_search_ts_users(tmp_ctx, domain, sub_filter, NULL, &ts_res); -+ if (ret == ERR_NO_TS) { -+ ret = sysdb_cache_search_users(tmp_ctx, domain, domain->sysdb->ldb, -+ sub_filter, attrs, &msgs_count, &msgs); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ ret = sysdb_merge_msg_list_ts_attrs(domain->sysdb, msgs_count, msgs, attrs); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ goto immediately; -+ } else if (ret != EOK) { -+ goto done; -+ } -+ -+ ret = cleanup_dn_filter(tmp_ctx, &ts_res, SYSDB_UC, sub_filter, &dn_filter); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, -+ &ts_res, dn_filter, &res); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ msgs_count = res->count; -+ msgs = res->msgs; -+ -+immediately: -+ *_msgs_count = msgs_count; -+ *_msgs = talloc_steal(mem_ctx, msgs); -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ - int sysdb_search_ts_users(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - const char *sub_filter, -@@ -3720,6 +3835,69 @@ int sysdb_search_groups(TALLOC_CTX *mem_ctx, - attrs); - } - -+int sysdb_search_groups_by_timestamp(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domain, -+ const char *sub_filter, -+ const char **attrs, -+ size_t *_msgs_count, -+ struct ldb_message ***_msgs) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct ldb_result *res; -+ struct ldb_result ts_res; -+ struct ldb_message **msgs; -+ size_t msgs_count; -+ char *dn_filter = NULL; -+ errno_t ret; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = sysdb_search_ts_groups(tmp_ctx, domain, sub_filter, NULL, &ts_res); -+ if (ret == ERR_NO_TS) { -+ ret = sysdb_cache_search_groups(tmp_ctx, domain, domain->sysdb->ldb, -+ sub_filter, attrs, &msgs_count, &msgs); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ ret = sysdb_merge_msg_list_ts_attrs(domain->sysdb, msgs_count, msgs, attrs); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ goto immediately; -+ } else if (ret != EOK) { -+ goto done; -+ } -+ -+ ret = cleanup_dn_filter(tmp_ctx, &ts_res, SYSDB_GC, sub_filter, &dn_filter); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, -+ &ts_res, dn_filter, &res); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ msgs_count = res->count; -+ msgs = res->msgs; -+ -+immediately: -+ *_msgs_count = msgs_count; -+ *_msgs = talloc_steal(mem_ctx, msgs); -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ - int sysdb_search_ts_groups(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - const char *sub_filter, --- -2.9.4 - diff --git a/SOURCES/0181-LDAP_ID_CLEANUP-Use-sysdb_search_-_by_timestamp.patch b/SOURCES/0181-LDAP_ID_CLEANUP-Use-sysdb_search_-_by_timestamp.patch deleted file mode 100644 index 7bba059..0000000 --- a/SOURCES/0181-LDAP_ID_CLEANUP-Use-sysdb_search_-_by_timestamp.patch +++ /dev/null @@ -1,48 +0,0 @@ -From b96c69f0ab0ecd55b734c167763c3bfe2357c448 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 7 Jun 2017 15:17:15 +0200 -Subject: [PATCH 181/181] LDAP_ID_CLEANUP: Use sysdb_search_*_by_timestamp() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use the appropriate methods for searching users and groups bv timestamp. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3369 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 05e579691b51ac2f81ab0c828ff6fe57bd86a8b6) ---- - src/providers/ldap/ldap_id_cleanup.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c -index cde2ad81873d46edd5e05c4a701ea1742a012bd0..c85ce45918cf938a95ff85c31bfe0541f9ddd052 100644 ---- a/src/providers/ldap/ldap_id_cleanup.c -+++ b/src/providers/ldap/ldap_id_cleanup.c -@@ -219,7 +219,8 @@ static int cleanup_users(struct sdap_options *opts, - goto done; - } - -- ret = sysdb_search_users(tmpctx, dom, subfilter, attrs, &count, &msgs); -+ ret = sysdb_search_users_by_timestamp(tmpctx, dom, subfilter, attrs, -+ &count, &msgs); - if (ret == ENOENT) { - count = 0; - } else if (ret != EOK) { -@@ -394,7 +395,8 @@ static int cleanup_groups(TALLOC_CTX *memctx, - goto done; - } - -- ret = sysdb_search_groups(tmpctx, domain, subfilter, attrs, &count, &msgs); -+ ret = sysdb_search_groups_by_timestamp(tmpctx, domain, subfilter, attrs, -+ &count, &msgs); - if (ret == ENOENT) { - count = 0; - } else if (ret != EOK) { --- -2.9.4 - diff --git a/SOURCES/0182-krb5-use-plain-principal-if-password-is-expired.patch b/SOURCES/0182-krb5-use-plain-principal-if-password-is-expired.patch deleted file mode 100644 index 4802ef1..0000000 --- a/SOURCES/0182-krb5-use-plain-principal-if-password-is-expired.patch +++ /dev/null @@ -1,66 +0,0 @@ -From b7aa85ea053aa78fa23de98d6c48e155f0cc06bc Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 12 Jun 2017 14:42:47 +0200 -Subject: [PATCH 182/182] krb5: use plain principal if password is expired -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Similar as in https://pagure.io/SSSD/sssd/issue/3426 enterprise -principals should be avoided while requesting a kadmin/changepw@REALM -principal for a password change. - -Resolves https://pagure.io/SSSD/sssd/issue/3419 - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 7e2ec7caa2d1c17e475fff78c5025496b8695509) ---- - src/providers/krb5/krb5_child.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c -index 3cd8bfba76a35acd2c885ee2aac4765a6c1cc03c..3a76b900444dea50ec0b783496e22d25aad797ab 100644 ---- a/src/providers/krb5/krb5_child.c -+++ b/src/providers/krb5/krb5_child.c -@@ -64,6 +64,7 @@ struct cli_opts { - struct krb5_req { - krb5_context ctx; - krb5_principal princ; -+ krb5_principal princ_orig; - char* name; - krb5_creds *creds; - bool otp; -@@ -1975,7 +1976,7 @@ static errno_t tgt_req_child(struct krb5_req *kr) - } - - set_changepw_options(kr->options); -- kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, -+ kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ_orig, - password_or_responder(password), - sss_krb5_prompter, kr, 0, - SSSD_KRB5_CHANGEPW_PRINCIPAL, -@@ -2303,6 +2304,8 @@ static int krb5_cleanup(struct krb5_req *kr) - sss_krb5_free_unparsed_name(kr->ctx, kr->name); - if (kr->princ != NULL) - krb5_free_principal(kr->ctx, kr->princ); -+ if (kr->princ_orig != NULL) -+ krb5_free_principal(kr->ctx, kr->princ_orig); - if (kr->ctx != NULL) - krb5_free_context(kr->ctx); - -@@ -2847,6 +2850,12 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline) - return kerr; - } - -+ kerr = krb5_parse_name(kr->ctx, kr->upn, &kr->princ_orig); -+ if (kerr != 0) { -+ KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); -+ return kerr; -+ } -+ - kerr = krb5_unparse_name(kr->ctx, kr->princ, &kr->name); - if (kerr != 0) { - KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); --- -2.9.4 - diff --git a/SOURCES/0183-RESPONDER-Use-fqnames-as-output-when-needed.patch b/SOURCES/0183-RESPONDER-Use-fqnames-as-output-when-needed.patch deleted file mode 100644 index 1af69a1..0000000 --- a/SOURCES/0183-RESPONDER-Use-fqnames-as-output-when-needed.patch +++ /dev/null @@ -1,279 +0,0 @@ -From 48b30d5a62e6af3d1f2b28eac3a2d39efa4349f1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Mon, 19 Jun 2017 09:05:00 +0200 -Subject: [PATCH 183/186] RESPONDER: Use fqnames as output when needed -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -As some regressions have been caused by not handling properly naming -conflicts when using shortnames, last explicitly use fully qualified -names as output in the following situations: -- domain resolution order is set; -- a trusted domain has been using `use_fully_qualified_name = false` - -In both cases we want to ensure that even handling shortnames as input, -the output will always be fully qualified. - -As part of this patch, our tests ended up being modified to reflect the -changes done. In other words, the tests related to shortnames now return -expect as return a fully qualified name for trusted domains. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3403 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 86526891366c4bc3e1ee861143b736d2670a6ba8) ---- - src/confdb/confdb.h | 1 + - src/db/sysdb_subdomains.c | 7 ++ - src/responder/common/cache_req/cache_req_domain.c | 14 +++ - src/responder/common/cache_req/cache_req_domain.h | 8 ++ - src/tests/cmocka/test_nss_srv.c | 104 +++++++++------------- - src/util/usertools.c | 2 +- - 6 files changed, 72 insertions(+), 64 deletions(-) - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index 797353141edcccbf3341d161ca598c99492e54fe..32a422155abef428e8a75fc83a5fe14620c7028e 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -291,6 +291,7 @@ struct sss_domain_info { - bool enumerate; - char **sd_enumerate; - bool fqnames; -+ bool output_fqnames; - bool mpg; - bool ignore_group_members; - uint32_t id_min; -diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c -index e2a4f7bb1fcdf20b6b7e04efc7f396d1c3d08f0f..2789cc4949fb7be9ad272d7613ed18a64fa8a20a 100644 ---- a/src/db/sysdb_subdomains.c -+++ b/src/db/sysdb_subdomains.c -@@ -129,6 +129,13 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, - dom->mpg = mpg; - dom->state = DOM_ACTIVE; - -+ /* use fully qualified names as output in order to avoid causing -+ * conflicts with users who have the same name and either the -+ * shortname user resolution is enabled or the trusted domain has -+ * been explicitly set to use non-fully qualified names as input. -+ */ -+ dom->output_fqnames = true; -+ - /* If the parent domain filters out group members, the subdomain should - * as well if configured */ - inherit_option = string_in_list(CONFDB_DOMAIN_IGNORE_GROUP_MEMBERS, -diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c -index 2c238c9966d322bb542fa2047313ee9e5144edee..b5f7f6c2ffabdbd92ee46b3020cee6ef7fec32d8 100644 ---- a/src/responder/common/cache_req/cache_req_domain.c -+++ b/src/responder/common/cache_req/cache_req_domain.c -@@ -136,6 +136,12 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, - cr_domain->fqnames = - cache_req_domain_use_fqnames(dom, enforce_non_fqnames); - -+ /* when using the domain resolution order, using shortnames as -+ * input is allowed by default. However, we really want to use -+ * the fully qualified name as output in order to avoid -+ * conflicts whith users who have the very same name. */ -+ cr_domain->domain->output_fqnames = true; -+ - DLIST_ADD_END(cr_domains, cr_domain, - struct cache_req_domain *); - break; -@@ -159,6 +165,14 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, - cr_domain->fqnames = - cache_req_domain_use_fqnames(dom, enforce_non_fqnames); - -+ /* when using the domain resolution order, using shortnames as input -+ * is allowed by default. However, we really want to use the fully -+ * qualified name as output in order to avoid conflicts whith users -+ * who have the very same name. */ -+ if (resolution_order != NULL) { -+ cr_domain->domain->output_fqnames = true; -+ } -+ - DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *); - } - -diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h -index 5bcbb9b493caf05bf71aac5cf7633ded91f22e73..3780a5d8d88d76e100738d28d1dd0e697edf5eae 100644 ---- a/src/responder/common/cache_req/cache_req_domain.h -+++ b/src/responder/common/cache_req/cache_req_domain.h -@@ -35,6 +35,14 @@ struct cache_req_domain * - cache_req_domain_get_domain_by_name(struct cache_req_domain *domains, - const char *name); - -+/* -+ * This function may have a side effect of setting the output_fqnames' domain -+ * property when it's called. -+ * -+ * It happens as the output_fqnames' domain property must only be set depending -+ * on whether a domain resolution order is set or not, and the saner place to -+ * set it to all domains is when flattening those (thus, in this function). -+ */ - errno_t - cache_req_domain_new_list_from_domain_resolution_order( - TALLOC_CTX *mem_ctx, -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 03b5bcc302322551a32f5b8cfe4b7698947abbe7..ccedf96beaecfaa4232bbe456d5e5a8394098483 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -1648,29 +1648,23 @@ static int test_nss_getgrnam_members_check_subdom(uint32_t status, - tmp_ctx = talloc_new(nss_test_ctx); - assert_non_null(tmp_ctx); - -- if (nss_test_ctx->subdom->fqnames) { -- exp_members[0] = sss_tc_fqname(tmp_ctx, -- nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, -- submember1.pw_name); -- assert_non_null(exp_members[0]); -+ exp_members[0] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember1.pw_name); -+ assert_non_null(exp_members[0]); - -- exp_members[1] = sss_tc_fqname(tmp_ctx, -- nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, -- submember2.pw_name); -- assert_non_null(exp_members[1]); -+ exp_members[1] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember2.pw_name); -+ assert_non_null(exp_members[1]); - -- expected.gr_name = sss_tc_fqname(tmp_ctx, -- nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, -- testsubdomgroup.gr_name); -- assert_non_null(expected.gr_name); -- } else { -- exp_members[0] = submember1.pw_name; -- exp_members[1] = submember2.pw_name; -- expected.gr_name = testsubdomgroup.gr_name; -- } -+ expected.gr_name = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ testsubdomgroup.gr_name); -+ assert_non_null(expected.gr_name); - - assert_int_equal(status, EOK); - -@@ -1744,15 +1738,11 @@ static int test_nss_getgrnam_check_mix_dom(uint32_t status, - tmp_ctx = talloc_new(nss_test_ctx); - assert_non_null(tmp_ctx); - -- if (nss_test_ctx->subdom->fqnames) { -- exp_members[0] = sss_tc_fqname(tmp_ctx, -- nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, -- submember1.pw_name); -- assert_non_null(exp_members[0]); -- } else { -- exp_members[0] = submember1.pw_name; -- } -+ exp_members[0] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember1.pw_name); -+ assert_non_null(exp_members[0]); - exp_members[1] = testmember1.pw_name; - exp_members[2] = testmember2.pw_name; - -@@ -1840,15 +1830,12 @@ static int test_nss_getgrnam_check_mix_dom_fqdn(uint32_t status, - tmp_ctx = talloc_new(nss_test_ctx); - assert_non_null(tmp_ctx); - -- if (nss_test_ctx->subdom->fqnames) { -- exp_members[0] = sss_tc_fqname(tmp_ctx, -- nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, -- submember1.pw_name); -- assert_non_null(exp_members[0]); -- } else { -- exp_members[0] = submember1.pw_name; -- } -+ exp_members[0] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember1.pw_name); -+ assert_non_null(exp_members[0]); -+ - if (nss_test_ctx->tctx->dom->fqnames) { - exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, - nss_test_ctx->tctx->dom, testmember1.pw_name); -@@ -1961,37 +1948,28 @@ static int test_nss_getgrnam_check_mix_subdom(uint32_t status, - tmp_ctx = talloc_new(nss_test_ctx); - assert_non_null(tmp_ctx); - -- if (nss_test_ctx->subdom->fqnames) { -- exp_members[0] = sss_tc_fqname(tmp_ctx, -- nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, -- submember1.pw_name); -- assert_non_null(exp_members[0]); -+ exp_members[0] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember1.pw_name); -+ assert_non_null(exp_members[0]); - -- exp_members[1] = sss_tc_fqname(tmp_ctx, -- nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, -- submember2.pw_name); -- assert_non_null(exp_members[1]); -- } else { -- exp_members[0] = submember1.pw_name; -- exp_members[1] = submember2.pw_name; -- } -+ exp_members[1] = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ submember2.pw_name); -+ assert_non_null(exp_members[1]); - - /* Important: this member is from a non-qualified domain, so his name will - * not be qualified either - */ - exp_members[2] = testmember1.pw_name; - -- if (nss_test_ctx->subdom->fqnames) { -- expected.gr_name = sss_tc_fqname(tmp_ctx, -- nss_test_ctx->subdom->names, -- nss_test_ctx->subdom, -- testsubdomgroup.gr_name); -- assert_non_null(expected.gr_name); -- } else { -- expected.gr_name = testsubdomgroup.gr_name; -- } -+ expected.gr_name = sss_tc_fqname(tmp_ctx, -+ nss_test_ctx->subdom->names, -+ nss_test_ctx->subdom, -+ testsubdomgroup.gr_name); -+ assert_non_null(expected.gr_name); - - assert_int_equal(status, EOK); - -diff --git a/src/util/usertools.c b/src/util/usertools.c -index 5dfe6d7765b8032c7447de75e10c6c2a1d4c49ec..83131da1cac25e60a5ec3fffa995a545673e53b9 100644 ---- a/src/util/usertools.c -+++ b/src/util/usertools.c -@@ -867,7 +867,7 @@ int sss_output_fqname(TALLOC_CTX *mem_ctx, - goto done; - } - -- if (domain->fqnames) { -+ if (domain->output_fqnames || domain->fqnames) { - output_name = sss_tc_fqname(tmp_ctx, domain->names, - domain, output_name); - if (output_name == NULL) { --- -2.9.4 - diff --git a/SOURCES/0184-DOMAIN-Add-sss_domain_info_-get-set-_output_fqnames.patch b/SOURCES/0184-DOMAIN-Add-sss_domain_info_-get-set-_output_fqnames.patch deleted file mode 100644 index e6bd53b..0000000 --- a/SOURCES/0184-DOMAIN-Add-sss_domain_info_-get-set-_output_fqnames.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 3fc92dcfbd67f82d26d7db46026f1fa1b69e2c70 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Tue, 20 Jun 2017 14:22:48 +0200 -Subject: [PATCH 184/186] DOMAIN: Add - sss_domain_info_{get,set}_output_fqnames() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Let's avoid setting a domain's property directly from cr_domain code. - -In order to do so, let's introduce a setter, which may help us in the -future whenever we decide to make sss_domain_info an opaque structure. - -For completeness, a getter has also been introduced and used in the -usertools code. - -Related: -https://pagure.io/SSSD/sssd/issue/3403 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Jakub Hrozek -(cherry picked from commit fa2fc8a2908619031292eaf375eb1a510b8b2eba) ---- - src/confdb/confdb.h | 5 ++++- - src/responder/common/cache_req/cache_req_domain.c | 4 ++-- - src/util/domain_info_utils.c | 11 +++++++++++ - src/util/usertools.c | 2 +- - src/util/util.h | 5 +++++ - 5 files changed, 23 insertions(+), 4 deletions(-) - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index 32a422155abef428e8a75fc83a5fe14620c7028e..2ba1bc47ee11f699726cefaf7c3335d2a8afee49 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -291,7 +291,6 @@ struct sss_domain_info { - bool enumerate; - char **sd_enumerate; - bool fqnames; -- bool output_fqnames; - bool mpg; - bool ignore_group_members; - uint32_t id_min; -@@ -355,6 +354,10 @@ struct sss_domain_info { - - struct certmap_info **certmaps; - bool user_name_hint; -+ -+ /* Do not use the _output_fqnames property directly in new code, but rather -+ * use sss_domain_info_{get,set}_output_fqnames(). */ -+ bool output_fqnames; - }; - - /** -diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c -index b5f7f6c2ffabdbd92ee46b3020cee6ef7fec32d8..c2b5abb74f3bd3d5055f29a4523f29b05feb2014 100644 ---- a/src/responder/common/cache_req/cache_req_domain.c -+++ b/src/responder/common/cache_req/cache_req_domain.c -@@ -140,7 +140,7 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, - * input is allowed by default. However, we really want to use - * the fully qualified name as output in order to avoid - * conflicts whith users who have the very same name. */ -- cr_domain->domain->output_fqnames = true; -+ sss_domain_info_set_output_fqnames(cr_domain->domain, true); - - DLIST_ADD_END(cr_domains, cr_domain, - struct cache_req_domain *); -@@ -170,7 +170,7 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, - * qualified name as output in order to avoid conflicts whith users - * who have the very same name. */ - if (resolution_order != NULL) { -- cr_domain->domain->output_fqnames = true; -+ sss_domain_info_set_output_fqnames(cr_domain->domain, true); - } - - DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *); -diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c -index 541058a16d585155b3b51511740f7db45281e2fd..45c74f089d0fdeaf6b5b50d7e5058df1716ff777 100644 ---- a/src/util/domain_info_utils.c -+++ b/src/util/domain_info_utils.c -@@ -904,3 +904,14 @@ const char *sss_domain_type_str(struct sss_domain_info *dom) - } - return "Unknown"; - } -+ -+void sss_domain_info_set_output_fqnames(struct sss_domain_info *domain, -+ bool output_fqnames) -+{ -+ domain->output_fqnames = output_fqnames; -+} -+ -+bool sss_domain_info_get_output_fqnames(struct sss_domain_info *domain) -+{ -+ return domain->output_fqnames; -+} -diff --git a/src/util/usertools.c b/src/util/usertools.c -index 83131da1cac25e60a5ec3fffa995a545673e53b9..33f4f7811c843704fff32db3a9ac54b3438f9d37 100644 ---- a/src/util/usertools.c -+++ b/src/util/usertools.c -@@ -867,7 +867,7 @@ int sss_output_fqname(TALLOC_CTX *mem_ctx, - goto done; - } - -- if (domain->output_fqnames || domain->fqnames) { -+ if (sss_domain_info_get_output_fqnames(domain) || domain->fqnames) { - output_name = sss_tc_fqname(tmp_ctx, domain->names, - domain, output_name); - if (output_name == NULL) { -diff --git a/src/util/util.h b/src/util/util.h -index 5ba4c36ca88e325c20a3b1ecc8080a11ca276dcf..72d4116e1206e9cc69715edc45bf5b9b91e37e6b 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -571,6 +571,11 @@ errno_t sssd_domain_init(TALLOC_CTX *mem_ctx, - const char *db_path, - struct sss_domain_info **_domain); - -+void sss_domain_info_set_output_fqnames(struct sss_domain_info *domain, -+ bool output_fqname); -+ -+bool sss_domain_info_get_output_fqnames(struct sss_domain_info *domain); -+ - #define IS_SUBDOMAIN(dom) ((dom)->parent != NULL) - - #define DOM_HAS_VIEWS(dom) ((dom)->has_views) --- -2.9.4 - diff --git a/SOURCES/0185-GPO-Fix-typo-in-DEBUG-message.patch b/SOURCES/0185-GPO-Fix-typo-in-DEBUG-message.patch deleted file mode 100644 index fa94e3d..0000000 --- a/SOURCES/0185-GPO-Fix-typo-in-DEBUG-message.patch +++ /dev/null @@ -1,27 +0,0 @@ -From ab8afcc8befcfa436008da41944cf258513631e6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 7 Jun 2017 14:37:42 +0200 -Subject: [PATCH 185/186] GPO: Fix typo in DEBUG message - -Reviewed-by: Jakub Hrozek -(cherry picked from commit b1d34059533eb50f6e5a4ac7b6fa1bb6fa60a445) ---- - src/providers/ad/ad_gpo.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c -index a8196b4d637eff86a01b342821592bffc214f1ab..2ee284bdc71fcec1c73997f785f7c2c7f387f0b3 100644 ---- a/src/providers/ad/ad_gpo.c -+++ b/src/providers/ad/ad_gpo.c -@@ -2110,7 +2110,7 @@ ad_gpo_process_gpo_done(struct tevent_req *subreq) - &state->num_dacl_filtered_gpos); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, -- "Unable to filter GPO list by DACKL: [%d](%s)\n", -+ "Unable to filter GPO list by DACL: [%d](%s)\n", - ret, sss_strerror(ret)); - goto done; - } --- -2.9.4 - diff --git a/SOURCES/0186-SDAP-Update-parent-sdap_list.patch b/SOURCES/0186-SDAP-Update-parent-sdap_list.patch deleted file mode 100644 index 431f35a..0000000 --- a/SOURCES/0186-SDAP-Update-parent-sdap_list.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 69b69d84ca9fd3453fa83281fc90e34f413a32f9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 14 Jun 2017 19:02:10 +0200 -Subject: [PATCH 186/186] SDAP: Update parent sdap_list - -Update parent sdap_list with newly created subdomain sdap domain. - -Preiously, we inherited the parent sdap_list and used it also in the -subdomain's context (this was introduced recently with commit -c4ddb9ccab670f9c0d0377680237b62f9f91c496), but it caused problems -that were difficult to debug (we somewhere rewrite part of the list -incorrectly). - -This patch reverses to the previous bahavior, where every subdomain -has it's own sdap_list, however this time the parrent domain's -sdap_list is updated so that it has correct information about -search bases of the child domains. - -We should ideally have just one sdap_list to avoid the updating -completely, but this would require more refactoring in the sdap -code. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3421 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 630aea13063c4b242b3433d16ca4346a1a38429b) ---- - src/providers/ad/ad_subdomains.c | 38 +++++++++++++++++++++++++++++++++++--- - 1 file changed, 35 insertions(+), 3 deletions(-) - -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index c9b79dd9d6840802cddc067eef9d5110cf8d0778..e35041c5ad73cb0fcaaaad96333fc17dd3a17638 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -141,6 +141,35 @@ static bool is_domain_enabled(const char *domain, - } - - static errno_t -+update_parent_sdap_list(struct sdap_domain *parent_list, -+ struct sdap_domain *child_sdap) -+{ -+ struct sdap_domain *sditer; -+ -+ DLIST_FOR_EACH(sditer, parent_list) { -+ if (sditer->dom == child_sdap->dom) { -+ break; -+ } -+ } -+ -+ if (sditer == NULL) { -+ /* Nothing to do */ -+ return EOK; -+ } -+ -+ /* Update the search bases */ -+ sditer->search_bases = child_sdap->search_bases; -+ sditer->user_search_bases = child_sdap->user_search_bases; -+ sditer->group_search_bases = child_sdap->group_search_bases; -+ sditer->netgroup_search_bases = child_sdap->netgroup_search_bases; -+ sditer->sudo_search_bases = child_sdap->sudo_search_bases; -+ sditer->service_search_bases = child_sdap->service_search_bases; -+ sditer->autofs_search_bases = child_sdap->autofs_search_bases; -+ -+ return EOK; -+} -+ -+static errno_t - ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, - struct ad_id_ctx *id_ctx, - struct sss_domain_info *subdom, -@@ -221,9 +250,6 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, - ad_id_ctx->sdap_id_ctx->opts = ad_options->id; - ad_options->id_ctx = ad_id_ctx; - -- /* We need to pass the sdap list from parent */ -- ad_id_ctx->sdap_id_ctx->opts->sdom = id_ctx->sdap_id_ctx->opts->sdom; -- - /* use AD plugin */ - srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res, - default_host_dbs, -@@ -267,6 +293,12 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, - "bases.", subdom->name); - } - -+ ret = update_parent_sdap_list(id_ctx->sdap_id_ctx->opts->sdom, -+ sdom); -+ if (ret != EOK) { -+ return ret; -+ } -+ - *_subdom_id_ctx = ad_id_ctx; - return EOK; - } --- -2.9.4 - diff --git a/SOURCES/0187-RESPONDERS-Fix-terminating-idle-connections.patch b/SOURCES/0187-RESPONDERS-Fix-terminating-idle-connections.patch deleted file mode 100644 index 724b886..0000000 --- a/SOURCES/0187-RESPONDERS-Fix-terminating-idle-connections.patch +++ /dev/null @@ -1,84 +0,0 @@ -From d6c7d35fdb4d416360a855a37b8c2164f053b470 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 11 Jul 2017 18:26:01 +0200 -Subject: [PATCH 187/190] RESPONDERS: Fix terminating idle connections -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The client_idle_handler() function tried to schedule another tevent -timer to check for idle client connections in case the current -connection was still valid, but in doing so, it also stored the current -time into the last_request_time field of the client context. - -This kept the connection always alive, because the last_request_time -could then never be older than the timeout. - -This patch changes the setup_client_idle_timer() function to only do -what the synopsis says and set the idle timer. The caller (usually the -function that accepts the connection) is supposed to store the request -time itself. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3448 - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Fabiano Fidêncio ---- - src/responder/common/responder_common.c | 16 +++++++++++----- - 1 file changed, 11 insertions(+), 5 deletions(-) - -diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c -index 9d4889be652c6d6fb974b59001a9ac77b496e9ab..9d706f9799ef1b31122d8380fbf9c53ba0cc9e68 100644 ---- a/src/responder/common/responder_common.c -+++ b/src/responder/common/responder_common.c -@@ -607,7 +607,15 @@ static void accept_fd_handler(struct tevent_context *ev, - cctx->ev = ev; - cctx->rctx = rctx; - -- /* Set up the idle timer */ -+ /* Record the new time and set up the idle timer */ -+ ret = reset_client_idle_timer(cctx); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Could not create idle timer for client. " -+ "This connection may not auto-terminate\n"); -+ /* Non-fatal, continue */ -+ } -+ - ret = setup_client_idle_timer(cctx); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, -@@ -634,7 +642,7 @@ static void client_idle_handler(struct tevent_context *ev, - if (cctx->last_request_time > now) { - DEBUG(SSSDBG_IMPORTANT_INFO, - "Time shift detected, re-scheduling the client timeout\n"); -- goto end; -+ goto done; - } - - if ((now - cctx->last_request_time) > cctx->rctx->client_idle_timeout) { -@@ -648,7 +656,7 @@ static void client_idle_handler(struct tevent_context *ev, - return; - } - --end: -+done: - setup_client_idle_timer(cctx); - } - -@@ -661,11 +669,9 @@ errno_t reset_client_idle_timer(struct cli_ctx *cctx) - - static errno_t setup_client_idle_timer(struct cli_ctx *cctx) - { -- time_t now = time(NULL); - struct timeval tv = - tevent_timeval_current_ofs(cctx->rctx->client_idle_timeout/2, 0); - -- cctx->last_request_time = now; - talloc_zfree(cctx->idle); - - cctx->idle = tevent_add_timer(cctx->ev, cctx, tv, client_idle_handler, cctx); --- -2.9.4 - diff --git a/SOURCES/0188-TESTS-Integration-test-for-idle-timeout.patch b/SOURCES/0188-TESTS-Integration-test-for-idle-timeout.patch deleted file mode 100644 index c587a0f..0000000 --- a/SOURCES/0188-TESTS-Integration-test-for-idle-timeout.patch +++ /dev/null @@ -1,135 +0,0 @@ -From fd008eddbf069014d8f17944d018ad3d85d5679f Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 19 Jul 2017 14:22:17 +0200 -Subject: [PATCH 188/190] TESTS: Integration test for idle timeout -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The secrets responder test was chosen even though the bug was in the generic -responder code b/c it runs a single responder process, so it's trivial to -read the PID of the responder under test. - -Changes subprocess.call() for os.execv() so that the setup function can -return the secret responder PID right away. - -The client timeout in the test has to be at least 10 seconds because -internally, the responders don't allow a shorter timeout. - -Regression test for https://pagure.io/SSSD/sssd/issue/3448 - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Fabiano Fidêncio ---- - src/tests/intg/test_secrets.py | 75 ++++++++++++++++++++++++++++++++++-------- - 1 file changed, 62 insertions(+), 13 deletions(-) - -diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py -index 202f43e61cb0e4986394ad2b32da5abdcb0be3e9..1be31318b194de1550bc84af16260bf1503567dc 100644 ---- a/src/tests/intg/test_secrets.py -+++ b/src/tests/intg/test_secrets.py -@@ -55,9 +55,9 @@ def create_sssd_secrets_fixture(request): - assert secpid >= 0 - - if secpid == 0: -- if subprocess.call([resp_path, "--uid=0", "--gid=0"]) != 0: -- print("sssd_secrets failed to start") -- sys.exit(99) -+ os.execv(resp_path, ("--uid=0", "--gid=0")) -+ print("sssd_secrets failed to start") -+ sys.exit(99) - else: - sock_path = os.path.join(config.RUNSTATEDIR, "secrets.socket") - sck = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) -@@ -83,13 +83,8 @@ def create_sssd_secrets_fixture(request): - return secpid - - --@pytest.fixture --def setup_for_secrets(request): -- """ -- Just set up the local provider for tests and enable the secrets -- responder -- """ -- conf = unindent("""\ -+def generate_sec_config(): -+ return unindent("""\ - [sssd] - domains = local - services = nss -@@ -100,11 +95,19 @@ def setup_for_secrets(request): - [secrets] - max_secrets = 10 - max_payload_size = 2 -- """).format(**locals()) -+ """) -+ -+ -+@pytest.fixture -+def setup_for_secrets(request): -+ """ -+ Just set up the local provider for tests and enable the secrets -+ responder -+ """ -+ conf = generate_sec_config() - - create_conf_fixture(request, conf) -- create_sssd_secrets_fixture(request) -- return None -+ return create_sssd_secrets_fixture(request) - - - def get_secrets_socket(): -@@ -386,3 +389,49 @@ def test_containers(setup_for_secrets, secrets_cli): - with pytest.raises(HTTPError) as err406: - cli.create_container(container) - assert str(err406.value).startswith("406") -+ -+ -+def get_num_fds(pid): -+ procpath = os.path.join("/proc/", str(pid), "fd") -+ return len([fdname for fdname in os.listdir(procpath)]) -+ -+ -+@pytest.fixture -+def setup_for_cli_timeout_test(request): -+ """ -+ Same as the generic setup, except a short client_idle_timeout so that -+ the test_idle_timeout() test closes the fd towards the client. -+ """ -+ conf = generate_sec_config() + \ -+ unindent(""" -+ client_idle_timeout = 10 -+ """).format() -+ -+ create_conf_fixture(request, conf) -+ return create_sssd_secrets_fixture(request) -+ -+ -+def test_idle_timeout(setup_for_cli_timeout_test): -+ """ -+ Test that idle file descriptors are reaped after the idle timeout -+ passes -+ """ -+ secpid = setup_for_cli_timeout_test -+ sock_path = get_secrets_socket() -+ -+ nfds_pre = get_num_fds(secpid) -+ -+ sock = socket.socket(family=socket.AF_UNIX) -+ sock.connect(sock_path) -+ time.sleep(1) -+ nfds_conn = get_num_fds(secpid) -+ assert nfds_pre + 1 == nfds_conn -+ # With the idle timeout set to 10 seconds, we need to sleep at least 15, -+ # because the internal timer ticks every timeout/2 seconds, so it would -+ # tick at 5, 10 and 15 seconds and the client timeout check uses a -+ # greater-than comparison, so the 10-seconds tick wouldn't yet trigger -+ # disconnect -+ time.sleep(15) -+ -+ nfds_post = get_num_fds(secpid) -+ assert nfds_pre == nfds_post --- -2.9.4 - diff --git a/SOURCES/0189-MAN-Document-that-client_idle_timeout-can-t-be-short.patch b/SOURCES/0189-MAN-Document-that-client_idle_timeout-can-t-be-short.patch deleted file mode 100644 index e353c96..0000000 --- a/SOURCES/0189-MAN-Document-that-client_idle_timeout-can-t-be-short.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0442102b2e5c6f1bc331ca2078baff8a7b4a50cb Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Thu, 20 Jul 2017 10:10:58 +0200 -Subject: [PATCH 189/190] MAN: Document that client_idle_timeout can't be - shorter than 10 seconds -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -To ensure the client timeout is not too low and clients do not reconnect -too often, the client_idle_timeout is forced to be 10 seconds minimum. - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Fabiano Fidêncio ---- - src/man/sssd.conf.5.xml | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml -index a35f2807eac8bb89d6cb1dd0a48f738d71a7578f..89729575c724622af817f1c05a94d4ae8f1ece2d 100644 ---- a/src/man/sssd.conf.5.xml -+++ b/src/man/sssd.conf.5.xml -@@ -621,7 +621,9 @@ - a client of an SSSD process can hold onto a file - descriptor without communicating on it. This value - is limited in order to avoid resource exhaustion -- on the system. -+ on the system. The timeout can't be shorter than -+ 10 seconds. If a lower value is configured, it -+ will be adjusted to 10 seconds. - - - Default: 60 --- -2.9.4 - diff --git a/SOURCES/0190-ad_account_can_shortcut-shortcut-if-ID-is-unknown.patch b/SOURCES/0190-ad_account_can_shortcut-shortcut-if-ID-is-unknown.patch deleted file mode 100644 index c652a4d..0000000 --- a/SOURCES/0190-ad_account_can_shortcut-shortcut-if-ID-is-unknown.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 55e8b436443cfae1c3b2155be7325d53760f7271 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 20 Jul 2017 20:01:14 +0200 -Subject: [PATCH 190/190] ad_account_can_shortcut: shortcut if ID is unknown -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If sss_idmap_unix_to_sid() returns an error we can assume that the given -POSIX ID is not from the current domain and can be skipped. This is e.g. -the case in the IPA provider if a POSIX ID used in the IPA domain is -checked in a trusted id-mapped AD domain before the IPA domain is -checked. - -Resolves https://pagure.io/SSSD/sssd/issue/3452 - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek ---- - src/providers/ad/ad_id.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c -index d1f6c444f5ddbcbbac6ff7f41fb6c8bf9ca976cb..e14ada386f16851a65097952c85e57b7acda14aa 100644 ---- a/src/providers/ad/ad_id.c -+++ b/src/providers/ad/ad_id.c -@@ -86,6 +86,8 @@ static bool ad_account_can_shortcut(struct sdap_idmap_ctx *idmap_ctx, - if (err != IDMAP_SUCCESS) { - DEBUG(SSSDBG_MINOR_FAILURE, "Mapping ID [%s] to SID failed: " - "[%s]\n", filter_value, idmap_error_string(err)); -+ /* assume id is from a different domain */ -+ shortcut = true; - goto done; - } - /* fall through */ --- -2.9.4 - diff --git a/SOURCES/0191-sudo-add-a-threshold-option-to-reduce-size-of-rules-.patch b/SOURCES/0191-sudo-add-a-threshold-option-to-reduce-size-of-rules-.patch deleted file mode 100644 index 54279f3..0000000 --- a/SOURCES/0191-sudo-add-a-threshold-option-to-reduce-size-of-rules-.patch +++ /dev/null @@ -1,211 +0,0 @@ -From 5c159808818fcea77822815b5f1131809c0e673c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 11 Jul 2017 12:41:57 +0200 -Subject: [PATCH 191/191] sudo: add a threshold option to reduce size of rules - refresh filter -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If a large number of rules is expired at one time the ldap filter may -become too large to be processed by server. This commits adds a new -option "sudo_threshold" to sudo responder. If the threshold is -exceeded a full refreshed is done instead of rules refresh. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3478 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit a5f300adf19ec9c3087c62bd93a5175db799687a) ---- - src/confdb/confdb.h | 2 ++ - src/config/SSSDConfig/__init__.py.in | 1 + - src/config/cfg_rules.ini | 1 + - src/config/etc/sssd.api.conf | 1 + - src/man/sssd.conf.5.xml | 19 +++++++++++++++++++ - src/responder/sudo/sudosrv.c | 11 +++++++++++ - src/responder/sudo/sudosrv_get_sudorules.c | 25 ++++++++++++++++++++----- - src/responder/sudo/sudosrv_private.h | 1 + - 8 files changed, 56 insertions(+), 5 deletions(-) - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index 2ba1bc47ee11f699726cefaf7c3335d2a8afee49..884b5bd1a493ca9a71654536524125eb8c7c4533 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -139,6 +139,8 @@ - #define CONFDB_DEFAULT_SUDO_TIMED false - #define CONFDB_SUDO_INVERSE_ORDER "sudo_inverse_order" - #define CONFDB_DEFAULT_SUDO_INVERSE_ORDER false -+#define CONFDB_SUDO_THRESHOLD "sudo_threshold" -+#define CONFDB_DEFAULT_SUDO_THRESHOLD 50 - - /* autofs */ - #define CONFDB_AUTOFS_CONF_ENTRY "config/autofs" -diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in -index 75515ab5c68822538728900482296b9159e1547e..137a8fa4d526cb10f3136c62f3c7104d9ecb7599 100644 ---- a/src/config/SSSDConfig/__init__.py.in -+++ b/src/config/SSSDConfig/__init__.py.in -@@ -107,6 +107,7 @@ option_strings = { - # [sudo] - 'sudo_timed' : _('Whether to evaluate the time-based attributes in sudo rules'), - 'sudo_inverse_order' : _('If true, SSSD will switch back to lower-wins ordering logic'), -+ 'sudo_threshold' : _('Maximum number of rules that can be refreshed at once. If this is exceeded, full refresh is performed.'), - - # [autofs] - 'autofs_negative_timeout' : _('Negative cache timeout length (seconds)'), -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index d6506b7c3cee13f7c5400a546deb787e755abc8b..0bdcfdfbefd6cb24e0c01cb9746dbb98c63a31d2 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -144,6 +144,7 @@ option = cache_first - # sudo service - option = sudo_timed - option = sudo_inverse_order -+option = sudo_threshold - - [rule/allowed_autofs_options] - validator = ini_allowed_options -diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf -index f86589ecefa0b9e046aba781ded107f8e94395d6..9d5eaaaa23c4c5395b155563de1cdf7752aa3dde 100644 ---- a/src/config/etc/sssd.api.conf -+++ b/src/config/etc/sssd.api.conf -@@ -79,6 +79,7 @@ pam_app_services = str, None, false - # sudo service - sudo_timed = bool, None, false - sudo_inverse_order = bool, None, false -+sudo_threshold = int, None, false - - [autofs] - # autofs service -diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml -index 89729575c724622af817f1c05a94d4ae8f1ece2d..d508df82d1d99af7835079c928839dc3cc7c28cb 100644 ---- a/src/man/sssd.conf.5.xml -+++ b/src/man/sssd.conf.5.xml -@@ -1376,6 +1376,25 @@ pam_account_locked_message = Account locked, please contact help desk. - - - -+ -+ -+ sudo_threshold (integer) -+ -+ -+ Maximum number of expired rules that can be -+ refreshed at once. If number of expired rules -+ is below threshold, those rules are refreshed -+ with rules refresh mechanism. If -+ the threshold is exceeded a -+ full refresh of sudo rules is -+ triggered instead. -+ -+ -+ Default: 50 -+ -+ -+ -+ - - - -diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c -index b427878d4dbe9090824a01386a7475be88b699c0..dca70ea4afc0e6df6d1b1864338c7b1091a98fee 100644 ---- a/src/responder/sudo/sudosrv.c -+++ b/src/responder/sudo/sudosrv.c -@@ -148,6 +148,17 @@ int sudo_process_init(TALLOC_CTX *mem_ctx, - goto fail; - } - -+ /* Get sudo_inverse_order option */ -+ ret = confdb_get_int(sudo_ctx->rctx->cdb, -+ CONFDB_SUDO_CONF_ENTRY, CONFDB_SUDO_THRESHOLD, -+ CONFDB_DEFAULT_SUDO_THRESHOLD, -+ &sudo_ctx->threshold); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) [%s]\n", -+ ret, strerror(ret)); -+ goto fail; -+ } -+ - ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n"); -diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c -index cfdbfc9c9c66d96f774822d6a4d4aaaf1327abe3..3272e634d895acf4854309371779a00cf1525126 100644 ---- a/src/responder/sudo/sudosrv_get_sudorules.c -+++ b/src/responder/sudo/sudosrv_get_sudorules.c -@@ -479,6 +479,7 @@ sudosrv_refresh_rules_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct resp_ctx *rctx, - struct sss_domain_info *domain, -+ int threshold, - uid_t uid, - const char *username, - char **groups) -@@ -520,9 +521,20 @@ sudosrv_refresh_rules_send(TALLOC_CTX *mem_ctx, - DEBUG(SSSDBG_TRACE_INTERNAL, "Refreshing %d expired rules of [%s@%s]\n", - num_rules, username, domain->name); - -- subreq = sss_dp_get_sudoers_send(state, rctx, domain, false, -- SSS_DP_SUDO_REFRESH_RULES, -- username, num_rules, rules); -+ if (num_rules > threshold) { -+ DEBUG(SSSDBG_TRACE_INTERNAL, -+ "Rules threshold [%d] is reached, performing full refresh " -+ "instead.\n", threshold); -+ -+ subreq = sss_dp_get_sudoers_send(state, rctx, domain, false, -+ SSS_DP_SUDO_FULL_REFRESH, -+ username, 0, NULL); -+ } else { -+ subreq = sss_dp_get_sudoers_send(state, rctx, domain, false, -+ SSS_DP_SUDO_REFRESH_RULES, -+ username, num_rules, rules); -+ } -+ - if (subreq == NULL) { - ret = ENOMEM; - goto immediately; -@@ -609,6 +621,7 @@ struct sudosrv_get_rules_state { - struct sss_domain_info *domain; - char **groups; - bool inverse_order; -+ int threshold; - - struct sysdb_attrs **rules; - uint32_t num_rules; -@@ -640,6 +653,7 @@ struct tevent_req *sudosrv_get_rules_send(TALLOC_CTX *mem_ctx, - state->type = type; - state->uid = uid; - state->inverse_order = sudo_ctx->inverse_order; -+ state->threshold = sudo_ctx->threshold; - - DEBUG(SSSDBG_TRACE_FUNC, "Running initgroups for [%s]\n", username); - -@@ -696,8 +710,9 @@ static void sudosrv_get_rules_initgr_done(struct tevent_req *subreq) - } - - subreq = sudosrv_refresh_rules_send(state, state->ev, state->rctx, -- state->domain, state->uid, -- state->username, state->groups); -+ state->domain, state->threshold, -+ state->uid, state->username, -+ state->groups); - if (subreq == NULL) { - ret = ENOMEM; - goto done; -diff --git a/src/responder/sudo/sudosrv_private.h b/src/responder/sudo/sudosrv_private.h -index 94f3c4458ab20e64db3e0bfce726d5d30a70a202..c76bdd3955bc29b7ba2cda58c503a4c616d7e63a 100644 ---- a/src/responder/sudo/sudosrv_private.h -+++ b/src/responder/sudo/sudosrv_private.h -@@ -48,6 +48,7 @@ struct sudo_ctx { - */ - bool timed; - bool inverse_order; -+ int threshold; - }; - - struct sudo_cmd_ctx { --- -2.13.5 - diff --git a/SOURCES/0192-libwbclient-Change-return-code-for-wbcAuthenticateUs.patch b/SOURCES/0192-libwbclient-Change-return-code-for-wbcAuthenticateUs.patch deleted file mode 100644 index c33350b..0000000 --- a/SOURCES/0192-libwbclient-Change-return-code-for-wbcAuthenticateUs.patch +++ /dev/null @@ -1,57 +0,0 @@ -From b9a2edea74ea04a09301f91fffb6835df72d8760 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Tue, 22 Aug 2017 13:09:18 +0200 -Subject: [PATCH 192/192] libwbclient: Change return code for - wbcAuthenticateUserEx - -Samba-4.6 change behaviour of few functions -New version of code make sure session info for user is stored in cache. -It is a performance optimisation to prevent contacting KDC for each -session. More details in samba bug -https://bugzilla.samba.org/show_bug.cgi?id=11259 - -Old return code WBC_SSSD_NOT_IMPLEMENTED was translated -to NT_STATUS_LOGON_FAILURE which caused many failures. - - [2017/08/21 11:34:15.044321, 5, pid=27742, effective(0, 0), real(0, 0)] - ../libcli/security/security_token.c:53(security_token_debug) - Security token: (NULL) - [2017/08/21 11:34:15.044330, 5, pid=27742, effective(0, 0), real(0, 0)] - ../source3/auth/token_util.c:640(debug_unix_user_token) - UNIX token of user 0 - Primary group is 0 and contains 0 supplementary groups - [2017/08/21 11:34:15.044349, 4, pid=27742, effective(0, 0), real(0, 0)] - ../source3/smbd/sec_ctx.c:439(pop_sec_ctx) - pop_sec_ctx (0, 0) - sec_ctx_stack_ndx = 0 - [2017/08/21 11:34:15.044360, 1, pid=27742, effective(0, 0), real(0, 0)] - ../source3/smbd/sesssetup.c:290(reply_sesssetup_and_X_spnego) - Failed to generate session_info (user and group token) for session - setup: NT_STATUS_LOGON_FAILURE - -Resolves: -https://pagure.io/SSSD/sssd/issue/3461 - -Reviewed-by: Sumit Bose -(cherry picked from commit 725d04cd21016dc6092a9f03cd363bb83d7c054c) -(cherry picked from commit aede6a1f4412f133e4b3fd76944f764d76fc4868) -(cherry picked from commit 260062d946e7cc265e2671f88b1662276431c0bb) ---- - src/sss_client/libwbclient/wbc_pam_sssd.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/sss_client/libwbclient/wbc_pam_sssd.c b/src/sss_client/libwbclient/wbc_pam_sssd.c -index 174cf1310fad0243036fe591978cc89700903896..77698f523e6e7aeb37d4db50b469d1604d7ee595 100644 ---- a/src/sss_client/libwbclient/wbc_pam_sssd.c -+++ b/src/sss_client/libwbclient/wbc_pam_sssd.c -@@ -49,7 +49,7 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params, - *error = NULL; - } - -- WBC_SSSD_NOT_IMPLEMENTED; -+ return WBC_ERR_WINBIND_NOT_AVAILABLE; - } - - /* Trigger a verification of the trust credentials of a specific domain */ --- -2.9.4 - diff --git a/SOURCES/0193-IPA-fix-handling-of-certmap_ctx.patch b/SOURCES/0193-IPA-fix-handling-of-certmap_ctx.patch deleted file mode 100644 index 47b85fb..0000000 --- a/SOURCES/0193-IPA-fix-handling-of-certmap_ctx.patch +++ /dev/null @@ -1,666 +0,0 @@ -From 2fca2f1b77c0e9ae82e1a24bbf89fbc3115a5e24 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 6 Sep 2017 16:42:20 +0200 -Subject: [PATCH 193/194] IPA: fix handling of certmap_ctx -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch fixes a use-after-free in the AD provider part and -initializes the certmap_ctx with data from the cache at startup. - -Related to https://pagure.io/SSSD/sssd/issue/3508 - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek -(cherry picked from commit f2e70ec742cd7aab82b74d7e4b424ba3258da7aa) ---- - Makefile.am | 20 +++ - src/providers/ipa/ipa_init.c | 7 + - src/providers/ipa/ipa_subdomains.c | 53 +------ - src/providers/ipa/ipa_subdomains_server.c | 4 +- - src/providers/ldap/ldap_common.h | 5 + - src/providers/ldap/ldap_id.c | 5 +- - src/providers/ldap/sdap.h | 4 +- - src/providers/ldap/sdap_certmap.c | 152 +++++++++++++++++++ - src/tests/cmocka/test_sdap_certmap.c | 244 ++++++++++++++++++++++++++++++ - 9 files changed, 441 insertions(+), 53 deletions(-) - create mode 100644 src/providers/ldap/sdap_certmap.c - create mode 100644 src/tests/cmocka/test_sdap_certmap.c - -diff --git a/Makefile.am b/Makefile.am -index 503c8cfd795b503f566431c08a56a56147180322..907c3256a154ebe2aae5a1667744e1dfbe8abaae 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -257,6 +257,7 @@ if HAVE_CMOCKA - test_search_bases \ - test_ldap_auth \ - test_sdap_access \ -+ test_sdap_certmap \ - sdap-tests \ - test_sysdb_ts_cache \ - test_sysdb_views \ -@@ -2662,6 +2663,24 @@ test_sdap_access_LDADD = \ - libdlopen_test_providers.la \ - $(NULL) - -+test_sdap_certmap_SOURCES = \ -+ src/tests/cmocka/test_sdap_certmap.c \ -+ src/providers/ldap/sdap_certmap.c \ -+ $(NULL) -+test_sdap_certmap_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(TALLOC_CFLAGS) \ -+ $(POPT_CFLAGS) \ -+ $(NULL) -+test_sdap_certmap_LDADD = \ -+ $(CMOCKA_LIBS) \ -+ $(TALLOC_LIBS) \ -+ $(POPT_LIBS) \ -+ $(SSSD_INTERNAL_LTLIBS) \ -+ libsss_test_common.la \ -+ libsss_certmap.la \ -+ $(NULL) -+ - ad_access_filter_tests_SOURCES = \ - src/tests/cmocka/test_ad_access_filter.c - ad_access_filter_tests_LDADD = \ -@@ -3706,6 +3725,7 @@ libsss_ldap_common_la_SOURCES = \ - src/providers/ldap/sdap_child_helpers.c \ - src/providers/ldap/sdap_fd_events.c \ - src/providers/ldap/sdap_id_op.c \ -+ src/providers/ldap/sdap_certmap.c \ - src/providers/ldap/sdap_idmap.c \ - src/providers/ldap/sdap_idmap.h \ - src/providers/ldap/sdap_range.c \ -diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c -index 7dec4d1fb8541a48470d4e44f10838e5bea67ad5..2b58b1341463f8947d51dee2076dbe92e3093558 100644 ---- a/src/providers/ipa/ipa_init.c -+++ b/src/providers/ipa/ipa_init.c -@@ -649,6 +649,13 @@ static errno_t ipa_init_misc(struct be_ctx *be_ctx, - return ENOMEM; - } - -+ 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/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index ef348adf4a36e870f44387bd700f5c2beea3bfd6..6f0ff50bde234f72d62f43635d9a787316c78430 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -311,25 +311,6 @@ struct priv_sss_debug { - int level; - }; - --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); -- } --} -- - static errno_t ipa_certmap_parse_results(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - struct sdap_options *sdap_opts, -@@ -344,7 +325,6 @@ static errno_t ipa_certmap_parse_results(TALLOC_CTX *mem_ctx, - size_t c; - size_t lc = 0; - int ret; -- struct sss_certmap_ctx *certmap_ctx = NULL; - const char **ocs = NULL; - bool user_name_hint = false; - -@@ -444,50 +424,29 @@ static errno_t ipa_certmap_parse_results(TALLOC_CTX *mem_ctx, - - certmap_list[lc] = NULL; - -- ret = sss_certmap_init(mem_ctx, ext_debug, NULL, &certmap_ctx); -- if (ret != 0) { -- DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n"); -+ ret = sdap_setup_certmap(sdap_opts->sdap_certmap_ctx, certmap_list); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sdap_setup_certmap 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(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], skipping. " -- "Please check for typos and if rule syntax is supported.\n", -- certmap_list[c]->name); -- goto done; -- } -- } -- - ret = sysdb_update_certmap(domain->sysdb, certmap_list, user_name_hint); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_certmap failed"); - goto done; - } - -- sss_certmap_free_ctx(sdap_opts->certmap_ctx); -- sdap_opts->certmap_ctx = talloc_steal(sdap_opts, certmap_ctx); -- - if (_certmap_list != NULL) { - *_certmap_list = certmap_list; -+ } else { -+ talloc_free(certmap_list); - } -+ - ret = EOK; - - done: - talloc_free(ocs); - if (ret != EOK) { -- sss_certmap_free_ctx(certmap_ctx); - talloc_free(certmap_list); - } - -diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c -index 443d83824f329b9d8c3d8e820113e1029f832240..56470ac824feaa59eecbd9f442682220237c2412 100644 ---- a/src/providers/ipa/ipa_subdomains_server.c -+++ b/src/providers/ipa/ipa_subdomains_server.c -@@ -361,8 +361,8 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, - id_ctx->sdap_id_ctx->opts->idmap_ctx; - - /* Set up the certificate mapping context */ -- ad_id_ctx->sdap_id_ctx->opts->certmap_ctx = -- id_ctx->sdap_id_ctx->opts->certmap_ctx; -+ ad_id_ctx->sdap_id_ctx->opts->sdap_certmap_ctx = -+ id_ctx->sdap_id_ctx->opts->sdap_certmap_ctx; - - *_ad_id_ctx = ad_id_ctx; - return EOK; -diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h -index 1acda4147576503b18f61e0bb56f8efd2263fd44..0510b7d5ab5121bd96f699e8e59520a2a18a604f 100644 ---- a/src/providers/ldap/ldap_common.h -+++ b/src/providers/ldap/ldap_common.h -@@ -362,4 +362,9 @@ sdap_id_ctx_new(TALLOC_CTX *mem_ctx, struct be_ctx *bectx, - errno_t sdap_refresh_init(struct be_refresh_ctx *refresh_ctx, - struct sdap_id_ctx *id_ctx); - -+errno_t sdap_init_certmap(TALLOC_CTX *mem_ctx, struct sdap_id_ctx *id_ctx); -+ -+errno_t sdap_setup_certmap(struct sdap_certmap_ctx *sdap_certmap_ctx, -+ struct certmap_info **certmap_list); -+struct sss_certmap_ctx *sdap_get_sss_certmap(struct sdap_certmap_ctx *ctx); - #endif /* _LDAP_COMMON_H_ */ -diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c -index 557712e8dc2b2bde664b4054fa2f8eb39df84d73..93204d35ea3782c9aa5d622a962c295869472631 100644 ---- a/src/providers/ldap/ldap_id.c -+++ b/src/providers/ldap/ldap_id.c -@@ -252,9 +252,8 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - } - - ret = sss_cert_derb64_to_ldap_filter(state, filter_value, attr_name, -- ctx->opts->certmap_ctx, -- state->domain, -- &user_filter); -+ sdap_get_sss_certmap(ctx->opts->sdap_certmap_ctx), -+ state->domain, &user_filter); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "sss_cert_derb64_to_ldap_filter failed.\n"); -diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h -index afdc01948eefe9dda943c8c7ad01a42dd76a1da8..c85fbe9e78e5eefa7e33ea8055730118b0871a4c 100644 ---- a/src/providers/ldap/sdap.h -+++ b/src/providers/ldap/sdap.h -@@ -446,6 +446,8 @@ struct sdap_ext_member_ctx { - ext_member_recv_fn_t ext_member_resolve_recv; - }; - -+struct sdap_certmap_ctx; -+ - struct sdap_options { - struct dp_option *basic; - struct sdap_attr_map *gen_map; -@@ -481,7 +483,7 @@ struct sdap_options { - enum dc_functional_level dc_functional_level; - - /* Certificate mapping support */ -- struct sss_certmap_ctx *certmap_ctx; -+ struct sdap_certmap_ctx *sdap_certmap_ctx; - }; - - struct sdap_server_opts { -diff --git a/src/providers/ldap/sdap_certmap.c b/src/providers/ldap/sdap_certmap.c -new file mode 100644 -index 0000000000000000000000000000000000000000..fcf88a9c69482c8668d486cd2ab0ba37c847e46d ---- /dev/null -+++ b/src/providers/ldap/sdap_certmap.c -@@ -0,0 +1,152 @@ -+ -+/* -+ SSSD -+ -+ Authors: -+ Sumit Bose -+ -+ Copyright (C) 2017 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 "util/util.h" -+#include "lib/certmap/sss_certmap.h" -+#include "providers/ldap/ldap_common.h" -+ -+struct sdap_certmap_ctx { -+ struct sss_certmap_ctx *certmap_ctx; -+}; -+ -+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); -+ } -+} -+ -+struct sss_certmap_ctx *sdap_get_sss_certmap(struct sdap_certmap_ctx *ctx) -+{ -+ return ctx == NULL ? NULL : ctx->certmap_ctx; -+} -+ -+errno_t sdap_setup_certmap(struct sdap_certmap_ctx *sdap_certmap_ctx, -+ struct certmap_info **certmap_list) -+{ -+ int ret; -+ struct sss_certmap_ctx *sss_certmap_ctx = NULL; -+ size_t c; -+ -+ if (sdap_certmap_ctx == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing sdap_certmap_ctx.\n"); -+ return EINVAL; -+ } -+ -+ 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(sdap_certmap_ctx, ext_debug, NULL, &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(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: -+ if (ret == EOK) { -+ sss_certmap_free_ctx(sdap_certmap_ctx->certmap_ctx); -+ sdap_certmap_ctx->certmap_ctx = sss_certmap_ctx; -+ } else { -+ sss_certmap_free_ctx(sss_certmap_ctx); -+ } -+ -+ return ret; -+} -+ -+errno_t sdap_init_certmap(TALLOC_CTX *mem_ctx, struct sdap_id_ctx *id_ctx) -+{ -+ int ret; -+ bool hint; -+ struct certmap_info **certmap_list = NULL; -+ -+ if (id_ctx->opts->sdap_certmap_ctx == NULL) { -+ id_ctx->opts->sdap_certmap_ctx = talloc_zero(mem_ctx, -+ struct sdap_certmap_ctx); -+ if (id_ctx->opts->sdap_certmap_ctx == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); -+ return ENOMEM; -+ } -+ } -+ -+ 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; -+ } -+ -+ ret = sdap_setup_certmap(id_ctx->opts->sdap_certmap_ctx, certmap_list); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sdap_setup_certmap failed.\n"); -+ goto done; -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_free(certmap_list); -+ -+ return ret; -+} -diff --git a/src/tests/cmocka/test_sdap_certmap.c b/src/tests/cmocka/test_sdap_certmap.c -new file mode 100644 -index 0000000000000000000000000000000000000000..9df5666844c8582a3fdb5b086720f1f2819f53f3 ---- /dev/null -+++ b/src/tests/cmocka/test_sdap_certmap.c -@@ -0,0 +1,244 @@ -+/* -+ Authors: -+ Sumit Bose -+ -+ Copyright (C) 2017 Red Hat -+ -+ SSSD tests - sdap certmap -+ -+ 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 -+#include -+#include -+#include -+#include -+ -+#include "providers/ldap/ldap_common.h" -+#include "tests/common.h" -+#include "db/sysdb.h" -+ -+#define TESTS_PATH "certmap_" BASE_FILE_STEM -+#define TEST_CONF_DB "test_sysdb_certmap.ldb" -+#define TEST_ID_PROVIDER "ldap" -+#define TEST_DOM_NAME "certmap_test" -+ -+struct certmap_info map_a = { discard_const("map_a"), 11, -+ NULL, discard_const("(abc=def)"), -+ NULL }; -+struct certmap_info map_b = { discard_const("map_b"), UINT_MAX, -+ NULL, NULL, NULL }; -+struct certmap_info *certmap[] = { &map_a, &map_b, NULL }; -+ -+struct certmap_test_ctx { -+ struct sss_test_ctx *tctx; -+ struct sdap_id_ctx *id_ctx; -+}; -+ -+static int test_sysdb_setup(void **state) -+{ -+ int ret; -+ struct certmap_test_ctx *test_ctx; -+ struct sss_test_conf_param params[] = { -+ { NULL, NULL }, /* Sentinel */ -+ }; -+ -+ assert_true(leak_check_setup()); -+ -+ test_ctx = talloc_zero(global_talloc_context, -+ struct certmap_test_ctx); -+ assert_non_null(test_ctx); -+ check_leaks_push(test_ctx); -+ -+ test_dom_suite_setup(TESTS_PATH); -+ -+ test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, -+ TEST_CONF_DB, TEST_DOM_NAME, -+ TEST_ID_PROVIDER, params); -+ assert_non_null(test_ctx->tctx); -+ -+ ret = sysdb_update_certmap(test_ctx->tctx->sysdb, certmap, false); -+ assert_int_equal(ret, EOK); -+ -+ test_ctx->id_ctx = talloc_zero(test_ctx->tctx, struct sdap_id_ctx); -+ assert_non_null(test_ctx->id_ctx); -+ -+ test_ctx->id_ctx->opts = talloc_zero(test_ctx->tctx, struct sdap_options); -+ assert_non_null(test_ctx->id_ctx->opts); -+ -+ test_ctx->id_ctx->be = talloc_zero(test_ctx->tctx, struct be_ctx); -+ assert_non_null(test_ctx->id_ctx->be); -+ test_ctx->id_ctx->be->domain = test_ctx->tctx->dom; -+ -+ *state = test_ctx; -+ return 0; -+} -+ -+static int test_sysdb_teardown(void **state) -+{ -+ struct certmap_test_ctx *test_ctx = -+ talloc_get_type(*state, struct certmap_test_ctx); -+ -+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); -+ talloc_free(test_ctx->tctx); -+ assert_true(check_leaks_pop(test_ctx)); -+ talloc_free(test_ctx); -+ assert_true(leak_check_teardown()); -+ return 0; -+} -+ -+static void test_sdap_certmap_init(void **state) -+{ -+ int ret; -+ struct certmap_test_ctx *test_ctx = talloc_get_type(*state, -+ struct certmap_test_ctx); -+ -+ ret = sdap_init_certmap(test_ctx, test_ctx->id_ctx); -+ assert_int_equal(ret, EOK); -+ -+ talloc_free(test_ctx->id_ctx->opts->sdap_certmap_ctx); -+} -+ -+static void test_sdap_get_sss_certmap(void **state) -+{ -+ int ret; -+ struct certmap_test_ctx *test_ctx = talloc_get_type(*state, -+ struct certmap_test_ctx); -+ struct sss_certmap_ctx *sss_certmap_ctx; -+ -+ sss_certmap_ctx = sdap_get_sss_certmap(NULL); -+ assert_null(sss_certmap_ctx); -+ -+ ret = sdap_init_certmap(test_ctx, test_ctx->id_ctx); -+ assert_int_equal(ret, EOK); -+ -+ sss_certmap_ctx = sdap_get_sss_certmap( -+ test_ctx->id_ctx->opts->sdap_certmap_ctx); -+ assert_non_null(sss_certmap_ctx); -+ -+ talloc_free(test_ctx->id_ctx->opts->sdap_certmap_ctx); -+} -+ -+static void test_sdap_certmap_init_twice(void **state) -+{ -+ int ret; -+ struct certmap_test_ctx *test_ctx = talloc_get_type(*state, -+ struct certmap_test_ctx); -+ struct sdap_certmap_ctx *sdap_certmap_ref; -+ struct sss_certmap_ctx *sss_certmap_ref; -+ -+ ret = sdap_init_certmap(test_ctx, test_ctx->id_ctx); -+ assert_int_equal(ret, EOK); -+ -+ sdap_certmap_ref = test_ctx->id_ctx->opts->sdap_certmap_ctx; -+ sss_certmap_ref = sdap_get_sss_certmap(sdap_certmap_ref); -+ -+ ret = sdap_init_certmap(test_ctx, test_ctx->id_ctx); -+ assert_int_equal(ret, EOK); -+ -+ assert_ptr_equal(sdap_certmap_ref, -+ test_ctx->id_ctx->opts->sdap_certmap_ctx); -+ assert_ptr_not_equal(sss_certmap_ref, -+ sdap_get_sss_certmap(sdap_certmap_ref)); -+ -+ talloc_free(test_ctx->id_ctx->opts->sdap_certmap_ctx); -+} -+ -+ -+static void test_sdap_setup_certmap(void **state) -+{ -+ int ret; -+ struct certmap_test_ctx *test_ctx = talloc_get_type(*state, -+ struct certmap_test_ctx); -+ struct sdap_certmap_ctx *sdap_certmap_ref; -+ struct sss_certmap_ctx *sss_certmap_ref; -+ -+ ret = sdap_init_certmap(test_ctx, test_ctx->id_ctx); -+ assert_int_equal(ret, EOK); -+ -+ sdap_certmap_ref = test_ctx->id_ctx->opts->sdap_certmap_ctx; -+ sss_certmap_ref = sdap_get_sss_certmap(sdap_certmap_ref); -+ -+ ret = sdap_setup_certmap(NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ assert_ptr_equal(sdap_certmap_ref, -+ test_ctx->id_ctx->opts->sdap_certmap_ctx); -+ assert_ptr_equal(sss_certmap_ref, sdap_get_sss_certmap(sdap_certmap_ref)); -+ -+ ret = sdap_setup_certmap(NULL, certmap); -+ assert_int_equal(ret, EINVAL); -+ assert_ptr_equal(sdap_certmap_ref, -+ test_ctx->id_ctx->opts->sdap_certmap_ctx); -+ assert_ptr_equal(sss_certmap_ref, sdap_get_sss_certmap(sdap_certmap_ref)); -+ -+ ret = sdap_setup_certmap(sdap_certmap_ref, certmap); -+ assert_int_equal(ret, EOK); -+ assert_ptr_equal(sdap_certmap_ref, -+ test_ctx->id_ctx->opts->sdap_certmap_ctx); -+ assert_ptr_not_equal(sss_certmap_ref, -+ sdap_get_sss_certmap(sdap_certmap_ref)); -+ -+ talloc_free(test_ctx->id_ctx->opts->sdap_certmap_ctx); -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ int rv; -+ poptContext pc; -+ int opt; -+ struct poptOption long_options[] = { -+ POPT_AUTOHELP -+ SSSD_DEBUG_OPTS -+ POPT_TABLEEND -+ }; -+ -+ const struct CMUnitTest tests[] = { -+ cmocka_unit_test_setup_teardown(test_sdap_certmap_init, -+ test_sysdb_setup, -+ test_sysdb_teardown), -+ cmocka_unit_test_setup_teardown(test_sdap_get_sss_certmap, -+ test_sysdb_setup, -+ test_sysdb_teardown), -+ cmocka_unit_test_setup_teardown(test_sdap_certmap_init_twice, -+ test_sysdb_setup, -+ test_sysdb_teardown), -+ cmocka_unit_test_setup_teardown(test_sdap_setup_certmap, -+ test_sysdb_setup, -+ test_sysdb_teardown), -+ }; -+ -+ /* Set debug level to invalid value so we can deside if -d 0 was used. */ -+ debug_level = SSSDBG_INVALID; -+ -+ pc = poptGetContext(argv[0], argc, argv, long_options, 0); -+ while((opt = poptGetNextOpt(pc)) != -1) { -+ switch(opt) { -+ default: -+ fprintf(stderr, "\nInvalid option %s: %s\n\n", -+ poptBadOption(pc, 0), poptStrerror(opt)); -+ poptPrintUsage(pc, stderr, 0); -+ return 1; -+ } -+ } -+ poptFreeContext(pc); -+ -+ DEBUG_CLI_INIT(debug_level); -+ -+ tests_set_cwd(); -+ rv = cmocka_run_group_tests(tests, NULL, NULL); -+ -+ return rv; -+} --- -2.13.5 - diff --git a/SOURCES/0194-certmap-make-sure-eku_oid_list-is-always-allocated.patch b/SOURCES/0194-certmap-make-sure-eku_oid_list-is-always-allocated.patch deleted file mode 100644 index c2f4d5d..0000000 --- a/SOURCES/0194-certmap-make-sure-eku_oid_list-is-always-allocated.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 27ef368b4105f19382360fe62f944b36ca74adb7 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 6 Sep 2017 12:20:25 +0200 -Subject: [PATCH 194/194] certmap: make sure eku_oid_list is always allocated -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If there are only OIDs in a part of a matching rule a NULL pointer -dereference might occur. - -Related to https://pagure.io/SSSD/sssd/issue/3508 - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek -(cherry picked from commit f5a8cd60c6f377af1954b58f007d16cf3f6dc846) ---- - src/lib/certmap/sss_certmap_krb5_match.c | 21 ++++++++++++--------- - src/tests/cmocka/test_certmap.c | 17 +++++++++++++++++ - 2 files changed, 29 insertions(+), 9 deletions(-) - -diff --git a/src/lib/certmap/sss_certmap_krb5_match.c b/src/lib/certmap/sss_certmap_krb5_match.c -index e40f17b8ace46e61087e0a2fa570a362a84cead2..0a77ac225d73f3506e102fdbdc9084faa0f19cf0 100644 ---- a/src/lib/certmap/sss_certmap_krb5_match.c -+++ b/src/lib/certmap/sss_certmap_krb5_match.c -@@ -179,19 +179,17 @@ static int parse_krb5_get_eku_value(TALLOC_CTX *mem_ctx, - goto done; - } - -+ comp->eku_oid_list = talloc_zero_array(comp, const char *, -+ eku_list_size + 1); -+ if (comp->eku_oid_list == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ - for (c = 0; eku_list[c] != NULL; c++) { - for (k = 0; ext_key_usage[k].name != NULL; k++) { - CM_DEBUG(ctx, "[%s][%s].", eku_list[c], ext_key_usage[k].name); - if (strcasecmp(eku_list[c], ext_key_usage[k].name) == 0) { -- if (comp->eku_oid_list == NULL) { -- comp->eku_oid_list = talloc_zero_array(comp, const char *, -- eku_list_size + 1); -- if (comp->eku_oid_list == NULL) { -- ret = ENOMEM; -- goto done; -- } -- } -- - comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list, - ext_key_usage[k].oid); - if (comp->eku_oid_list[e] == NULL) { -@@ -225,6 +223,11 @@ CM_DEBUG(ctx, "[%s][%s].", eku_list[c], ext_key_usage[k].name); - } - } - -+ if (e == 0) { -+ talloc_free(comp->eku_oid_list); -+ comp->eku_oid_list = NULL; -+ } -+ - ret = 0; - - done: -diff --git a/src/tests/cmocka/test_certmap.c b/src/tests/cmocka/test_certmap.c -index c998443d086eaa72cc2a05c38ddfc5ba590a1ce7..e732bb214476943d0f723b318ab64d3b4156cace 100644 ---- a/src/tests/cmocka/test_certmap.c -+++ b/src/tests/cmocka/test_certmap.c -@@ -445,6 +445,23 @@ static void test_sss_certmap_add_matching_rule(void **state) - assert_null( - ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list[3]); - -+ ret = sss_certmap_add_rule(ctx, 96, -+ "KRB5:1.2.3", -+ NULL, NULL); -+ assert_int_equal(ret, 0); -+ assert_non_null(ctx->prio_list); -+ assert_non_null(ctx->prio_list->rule_list); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); -+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, -+ relation_and); -+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->eku); -+ assert_true(string_in_list("1.2.3", -+ discard_const( -+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list), -+ true)); -+ assert_null( -+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list[1]); -+ - /* SAN tests */ - ret = sss_certmap_add_rule(ctx, 89, "KRB5:abc", NULL, NULL); - assert_int_equal(ret, 0); --- -2.13.5 - diff --git a/SOURCES/0195-cache_req-Look-for-name-attribute-also-in-nss_cmd_ge.patch b/SOURCES/0195-cache_req-Look-for-name-attribute-also-in-nss_cmd_ge.patch deleted file mode 100644 index 2841962..0000000 --- a/SOURCES/0195-cache_req-Look-for-name-attribute-also-in-nss_cmd_ge.patch +++ /dev/null @@ -1,62 +0,0 @@ -From cf75c30a42059480eca4c352598ceb3760c27e46 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 21 Aug 2017 11:42:43 +0200 -Subject: [PATCH 195/195] cache_req: Look for name attribute also in - nss_cmd_getsidbyid -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We always check negcache after getting data from backend since commit -4c09cd008967c5c0ec358dc658ffc6fc1cef2697 because we usually do have a name -in begging of requests "* by ID". - -We were not interested in name in request sid by id before. However, function -cache_req_search_ncache_filter always expect name otherwise it returns -ERR_INTERNAL. - -[sssd[nss]] [cache_req_set_plugin] (0x2000): CR #8: Setting "Object by ID" plugin -[sssd[nss]] [cache_req_send] (0x0400): CR #8: New request 'Object by ID' -[sssd[nss]] [cache_req_select_domains] (0x0400): CR #8: Performing a multi-domain search -[sssd[nss]] [cache_req_search_domains] (0x0400): CR #8: Search will check the cache and check the data provider -[sssd[nss]] [cache_req_validate_domain_type] (0x2000): Request type POSIX-only for domain sssdad2012r2.com type POSIX is valid -[sssd[nss]] [cache_req_set_domain] (0x0400): CR #8: Using domain [sssdad2012r2.com] -[sssd[nss]] [cache_req_search_send] (0x0400): CR #8: Looking up ID:233600513@sssdad2012r2.com -[sssd[nss]] [cache_req_search_ncache] (0x0400): CR #8: Checking negative cache for [ID:233600513@sssdad2012r2.com] -[sssd[nss]] [sss_ncache_check_str] (0x2000): Checking negative cache for [NCE/UID/sssdad2012r2.com/233600513] -[sssd[nss]] [cache_req_search_ncache] (0x0400): CR #8: [ID:233600513@sssdad2012r2.com] is not present in negative cache -[sssd[nss]] [cache_req_search_cache] (0x0400): CR #8: Looking up [ID:233600513@sssdad2012r2.com] in cache -[sssd[nss]] [cache_req_search_send] (0x0400): CR #8: Returning [ID:233600513@sssdad2012r2.com] from cache -[sssd[nss]] [cache_req_search_ncache_filter] (0x0400): CR #8: Filtering out results by negative cache -[sssd[nss]] [cache_req_search_ncache_filter] (0x0020): CR #8: sss_get_name_from_msg() returned NULL, which should never happen in this scenario! -[sssd[nss]] [cache_req_process_result] (0x0400): CR #8: Finished: Error 1432158209: Internal Error -[sssd[nss]] [nss_protocol_done] (0x4000): Sending reply: error [1432158209]: Internal Error -[sssd[nss]] [client_recv] (0x0200): Client disconnected! - -Resolves: -https://pagure.io/SSSD/sssd/issue/3485 - -Reviewed-by: Pavel Březina -(cherry picked from commit 2e72ababbbadda4c4036f99528460c1d595e0941) ---- - src/responder/common/cache_req/cache_req_data.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c -index 5ab1493b81dbcd1529f1124a2bb1f99d3ae82281..3c365e2fe5826fd58c75f07b08193e5566db2563 100644 ---- a/src/responder/common/cache_req/cache_req_data.c -+++ b/src/responder/common/cache_req/cache_req_data.c -@@ -26,7 +26,9 @@ static const char ** - cache_req_data_create_attrs(TALLOC_CTX *mem_ctx, - const char **requested) - { -- static const char *defattrs[] = { SYSDB_DEFAULT_ATTRS }; -+ static const char *defattrs[] = { SYSDB_DEFAULT_ATTRS, SYSDB_NAME, -+ OVERRIDE_PREFIX SYSDB_NAME, -+ SYSDB_DEFAULT_OVERRIDE_NAME }; - static size_t defnum = sizeof(defattrs) / sizeof(defattrs[0]); - const char **attrs; - size_t reqnum; --- -2.13.5 - diff --git a/SOURCES/0196-sssd_client-add-mutex-protected-call-to-the-PAC-resp.patch b/SOURCES/0196-sssd_client-add-mutex-protected-call-to-the-PAC-resp.patch deleted file mode 100644 index 2fe32d6..0000000 --- a/SOURCES/0196-sssd_client-add-mutex-protected-call-to-the-PAC-resp.patch +++ /dev/null @@ -1,461 +0,0 @@ -From daa59b79602cfeff81223a7461e18f513178c9d4 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 18 Sep 2017 15:00:53 +0200 -Subject: [PATCH 196/196] sssd_client: add mutex protected call to the PAC - responder -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -SSSD's plugin for MIT Kerberos to send the PAC to the PAC responder -currently uses sss_pac_make_request() which does not protect the -communication with the PAC responder with a mutex as e.g. the NSS and -PAM clients. - -If an application using threads loads this plugin via libkrb5 in -different threads and is heavily processing Kerberos tickets with PACs -chances are that two threads try to communicate with SSSD at once. In -this case one of the threads will miss a reply and will wait for it -until the default client timeout of 300s is passed. - -This patch adds a call which uses a mutex to protect the communication -which will avoid the 300s delay mentioned above. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3518 - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 1f331476e7d33bb03cc35a2a9064ee1cc5bed6cf) ---- - Makefile.am | 16 ++++ - src/sss_client/common.c | 30 +++++++ - src/sss_client/sss_cli.h | 7 ++ - src/sss_client/sss_pac_responder_client.c | 137 ++++++++++++++++++++++++++++++ - src/sss_client/sssd_pac.c | 4 +- - src/tests/intg/Makefile.am | 1 + - src/tests/intg/test_pac_responder.py | 120 ++++++++++++++++++++++++++ - 7 files changed, 313 insertions(+), 2 deletions(-) - create mode 100644 src/sss_client/sss_pac_responder_client.c - create mode 100644 src/tests/intg/test_pac_responder.py - -diff --git a/Makefile.am b/Makefile.am -index 907c3256a154ebe2aae5a1667744e1dfbe8abaae..cdd517d50679b876814303fb7d6c63d49bcd8d38 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -3501,6 +3501,9 @@ endif - if BUILD_WITH_LIBCURL - noinst_PROGRAMS += tcurl-test-tool - endif -+if BUILD_PAC_RESPONDER -+ noinst_PROGRAMS += sssd_pac_test_client -+endif - - if BUILD_AUTOFS - autofs_test_client_SOURCES = \ -@@ -4210,6 +4213,19 @@ sssd_pac_plugin_la_LDFLAGS = \ - -avoid-version \ - -module - -+sssd_pac_test_client_SOURCES = \ -+ src/sss_client/sss_pac_responder_client.c \ -+ src/sss_client/common.c \ -+ src/util/strtonum.c \ -+ $(NULL) -+sssd_pac_test_client_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(NULL) -+sssd_pac_test_client_LDADD = \ -+ $(CLIENT_LIBS) \ -+ -lpthread \ -+ $(NULL) -+ - # python[23] bindings - pysss_la_SOURCES = \ - $(SSSD_TOOLS_OBJ) \ -diff --git a/src/sss_client/common.c b/src/sss_client/common.c -index b7a5ed760ca379acdfd8f1d2bf95cee1aa271fd8..b527c046e2e3369934b4f9ea7efc1b52eb8c57ea 100644 ---- a/src/sss_client/common.c -+++ b/src/sss_client/common.c -@@ -821,6 +821,22 @@ int sss_pac_make_request(enum sss_cli_command cmd, - } - } - -+int sss_pac_make_request_with_lock(enum sss_cli_command cmd, -+ struct sss_cli_req_data *rd, -+ uint8_t **repbuf, size_t *replen, -+ int *errnop) -+{ -+ int ret; -+ -+ sss_pac_lock(); -+ -+ ret = sss_pac_make_request(cmd, rd, repbuf, replen, errnop); -+ -+ sss_pac_unlock(); -+ -+ return ret; -+} -+ - errno_t check_server_cred(int sockfd) - { - #ifdef HAVE_UCRED -@@ -1079,6 +1095,8 @@ static struct sss_mutex sss_pam_mtx = { .mtx = PTHREAD_MUTEX_INITIALIZER }; - - static struct sss_mutex sss_nss_mc_mtx = { .mtx = PTHREAD_MUTEX_INITIALIZER }; - -+static struct sss_mutex sss_pac_mtx = { .mtx = PTHREAD_MUTEX_INITIALIZER }; -+ - static void sss_mt_lock(struct sss_mutex *m) - { - pthread_mutex_lock(&m->mtx); -@@ -1121,6 +1139,16 @@ void sss_nss_mc_unlock(void) - sss_mt_unlock(&sss_nss_mc_mtx); - } - -+/* PAC mutex wrappers */ -+void sss_pac_lock(void) -+{ -+ sss_mt_lock(&sss_pac_mtx); -+} -+void sss_pac_unlock(void) -+{ -+ sss_mt_unlock(&sss_pac_mtx); -+} -+ - #else - - /* sorry no mutexes available */ -@@ -1130,6 +1158,8 @@ void sss_pam_lock(void) { return; } - void sss_pam_unlock(void) { return; } - void sss_nss_mc_lock(void) { return; } - void sss_nss_mc_unlock(void) { return; } -+void sss_pac_lock(void) { return; } -+void sss_pac_unlock(void) { return; } - #endif - - -diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h -index d4198407f2f86c6594aee6a2a43775e429692df0..337fe9803d2df3167cd2da77107dbd077f35a51b 100644 ---- a/src/sss_client/sss_cli.h -+++ b/src/sss_client/sss_cli.h -@@ -585,6 +585,11 @@ int sss_pac_make_request(enum sss_cli_command cmd, - uint8_t **repbuf, size_t *replen, - int *errnop); - -+int sss_pac_make_request_with_lock(enum sss_cli_command cmd, -+ struct sss_cli_req_data *rd, -+ uint8_t **repbuf, size_t *replen, -+ int *errnop); -+ - int sss_sudo_make_request(enum sss_cli_command cmd, - struct sss_cli_req_data *rd, - uint8_t **repbuf, size_t *replen, -@@ -634,6 +639,8 @@ void sss_pam_lock(void); - void sss_pam_unlock(void); - void sss_nss_mc_lock(void); - void sss_nss_mc_unlock(void); -+void sss_pac_lock(void); -+void sss_pac_unlock(void); - - errno_t sss_readrep_copy_string(const char *in, - size_t *offset, -diff --git a/src/sss_client/sss_pac_responder_client.c b/src/sss_client/sss_pac_responder_client.c -new file mode 100644 -index 0000000000000000000000000000000000000000..9eb0cbea6175ee273b23d9a975529d85c02fc603 ---- /dev/null -+++ b/src/sss_client/sss_pac_responder_client.c -@@ -0,0 +1,137 @@ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "sss_client/sss_cli.h" -+ -+const uint8_t pac[] = { -+0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, -+0x02, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, -+0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x68, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x0c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x78, 0x02, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xb8, -+0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, -+0x00, 0x00, 0xc8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, -+0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x02, 0x00, 0x30, 0xe3, 0xd6, 0x9e, 0x99, 0x2b, 0xd3, 0x01, 0xff, -+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -+0xff, 0x7f, 0xe2, 0xf7, 0x8a, 0xaf, 0x00, 0x0f, 0xd0, 0x01, 0xe2, 0xb7, 0xf4, -+0xd9, 0xc9, 0x0f, 0xd0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, -+0x06, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, -+0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x45, 0x02, 0x00, 0x00, -+0x50, 0x04, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1c, -+0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x14, -+0x00, 0x20, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x24, 0x00, 0x02, 0x00, -+0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, -+0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x74, 0x00, -+0x75, 0x00, 0x31, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x03, 0x00, 0x00, 0x00, 0x74, 0x00, 0x20, 0x00, 0x75, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, -+0xfd, 0xa2, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x07, -+0x00, 0x00, 0x00, 0x5c, 0x04, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x56, 0x04, -+0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x89, 0xa6, 0x00, 0x00, 0x07, 0x00, 0x00, -+0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, -+0x41, 0x00, 0x44, 0x00, 0x2d, 0x00, 0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, -+0x00, 0x45, 0x00, 0x52, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x41, 0x00, 0x44, 0x00, 0x04, 0x00, 0x00, -+0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, -+0xf8, 0x12, 0x13, 0xdc, 0x47, 0xf3, 0x1c, 0x76, 0x47, 0x2f, 0x2e, 0xd7, 0x02, -+0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x34, 0x00, -+0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x29, 0xc9, 0x4f, 0xd9, -+0xc2, 0x3c, 0xc3, 0x78, 0x36, 0x55, 0x87, 0xf8, 0x54, 0x04, 0x00, 0x00, 0x05, -+0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, -+0x00, 0x00, 0x25, 0xe1, 0xff, 0x1c, 0xf7, 0x87, 0x6b, 0x2c, 0x25, 0xd2, 0x0c, -+0xe3, 0xf2, 0x03, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x89, 0x65, 0x2d, 0xd3, 0x01, -+0x06, 0x00, 0x74, 0x00, 0x75, 0x00, 0x31, 0x00, 0x20, 0x00, 0x10, 0x00, 0x10, -+0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, -+0x75, 0x00, 0x31, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x40, -+0x00, 0x61, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x64, 0x00, 0x65, 0x00, 0x76, 0x00, -+0x65, 0x00, 0x6c, 0x00, 0x41, 0x00, 0x44, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x45, -+0x00, 0x56, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x76, 0x8e, -+0x25, 0x32, 0x7c, 0x85, 0x00, 0x32, 0xac, 0x8f, 0x02, 0x2c, 0x10, 0x00, 0x00, -+0x00, 0x6b, 0xe8, 0x51, 0x03, 0x30, 0xed, 0xca, 0x7d, 0xe2, 0x12, 0xa5, 0xde}; -+ -+enum nss_status _nss_sss_getpwuid_r(uid_t uid, struct passwd *result, -+ char *buffer, size_t buflen, int *errnop); -+static void *pac_client(void *arg) -+{ -+ struct sss_cli_req_data sss_data = { sizeof(pac), pac }; -+ int errnop = -1; -+ int ret; -+ size_t c; -+ -+ fprintf(stderr, "[%ld][%d][%ld][%s] started\n", time(NULL), getpid(), -+ syscall(SYS_gettid), -+ (char *) arg); -+ for (c = 0; c < 1000; c++) { -+ /* sss_pac_make_request() does not protect the client's file -+ * descriptor to the PAC responder. With this one thread will miss a -+ * reply for a SSS_GET_VERSION request and will wait until -+ * SSS_CLI_SOCKET_TIMEOUT is passed. -+ -+ ret = sss_pac_make_request(SSS_PAC_ADD_PAC_USER, &sss_data, -+ NULL, NULL, &errnop); -+ */ -+ ret = sss_pac_make_request_with_lock(SSS_PAC_ADD_PAC_USER, &sss_data, -+ NULL, NULL, &errnop); -+ if (ret != NSS_STATUS_SUCCESS -+ && !(ret == NSS_STATUS_UNAVAIL && errnop != ECONNREFUSED)) { -+ /* NSS_STATUS_UNAVAIL is returned if the PAC responder rejects -+ * the request which is ok becasue the client is waiting for a -+ * response here as well. Only errnop == ECONNREFUSED should -+ * be treated as error becasue this means that the PAC -+ * responder is not running. */ -+ fprintf(stderr, "pac: [%s][%d][%d]\n", (char *)arg, ret, errnop); -+ return ((void *)((uintptr_t)("X"))); -+ } -+ } -+ -+ fprintf(stderr, "[%ld][%s] done\n", time(NULL),(char *) arg); -+ return NULL; -+} -+ -+int main(void) -+{ -+ pthread_t thread1; -+ pthread_t thread2; -+ int ret; -+ void *t_ret; -+ -+ pthread_create(&thread1, NULL, pac_client, -+ ((void *)((uintptr_t)("Thread 1")))); -+ pthread_create(&thread2, NULL, pac_client, -+ ((void *)((uintptr_t)("Thread 2")))); -+ -+ ret = pthread_join(thread1, &t_ret); -+ if (ret != 0 || t_ret != NULL) { -+ fprintf(stderr, "Thread 1 failed.\n"); -+ return EIO; -+ } -+ -+ ret = pthread_join(thread2, &t_ret); -+ if (ret != 0 || t_ret != NULL) { -+ fprintf(stderr, "Thread 1 failed.\n"); -+ return EIO; -+ } -+ -+ return 0; -+} -diff --git a/src/sss_client/sssd_pac.c b/src/sss_client/sssd_pac.c -index 1d98e38826b36aed199b32880a7e27de905a4592..8444834a7f148787e847f5e8e21186c8701b2de7 100644 ---- a/src/sss_client/sssd_pac.c -+++ b/src/sss_client/sssd_pac.c -@@ -169,8 +169,8 @@ static krb5_error_code sssdpac_verify(krb5_context kcontext, - sss_data.len = sssdctx->data.length; - sss_data.data = sssdctx->data.data; - -- ret = sss_pac_make_request(SSS_PAC_ADD_PAC_USER, &sss_data, -- NULL, NULL, &errnop); -+ ret = sss_pac_make_request_with_lock(SSS_PAC_ADD_PAC_USER, &sss_data, -+ NULL, NULL, &errnop); - if (ret != 0) { - /* Ignore the error */ - } -diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am -index 8566106e9017a8d3c9e7a3898a3a886e2966e346..0af7c62ca243822d919619f3d0ebc852a317efc4 100644 ---- a/src/tests/intg/Makefile.am -+++ b/src/tests/intg/Makefile.am -@@ -29,6 +29,7 @@ dist_noinst_DATA = \ - kdc.py \ - krb5utils.py \ - test_kcm.py \ -+ test_pac_responder.py \ - $(NULL) - - config.py: config.py.m4 -diff --git a/src/tests/intg/test_pac_responder.py b/src/tests/intg/test_pac_responder.py -new file mode 100644 -index 0000000000000000000000000000000000000000..4354a5d78da6a6627a27d0ca85c8a1d47419cedf ---- /dev/null -+++ b/src/tests/intg/test_pac_responder.py -@@ -0,0 +1,120 @@ -+# -+# SSSD PAC responder tests -+# -+# Copyright (c) 2017 Red Hat, Inc. -+# Author: Sumit Bose -+# -+# This 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; version 2 only -+# -+# 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 . -+# -+import os -+import stat -+import time -+import config -+import signal -+import subprocess -+import pytest -+from util import unindent -+ -+ -+def stop_sssd(): -+ with open(config.PIDFILE_PATH, "r") as pid_file: -+ pid = int(pid_file.read()) -+ os.kill(pid, signal.SIGTERM) -+ while True: -+ try: -+ os.kill(pid, signal.SIGCONT) -+ except: -+ break -+ time.sleep(1) -+ -+ -+def create_conf_fixture(request, contents): -+ """Generate sssd.conf and add teardown for removing it""" -+ conf = open(config.CONF_PATH, "w") -+ conf.write(contents) -+ conf.close() -+ os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR) -+ request.addfinalizer(lambda: os.unlink(config.CONF_PATH)) -+ -+ -+def create_sssd_fixture(request): -+ """Start sssd and add teardown for stopping it and removing state""" -+ if subprocess.call(["sssd", "-D", "-f"]) != 0: -+ raise Exception("sssd start failed") -+ -+ def teardown(): -+ try: -+ stop_sssd() -+ except: -+ pass -+ for path in os.listdir(config.DB_PATH): -+ os.unlink(config.DB_PATH + "/" + path) -+ for path in os.listdir(config.MCACHE_PATH): -+ os.unlink(config.MCACHE_PATH + "/" + path) -+ request.addfinalizer(teardown) -+ -+ -+@pytest.fixture -+def local_domain_only(request): -+ conf = unindent("""\ -+ [sssd] -+ domains = LOCAL -+ services = nss, pac -+ -+ [nss] -+ memcache_timeout = 0 -+ -+ [domain/LOCAL] -+ id_provider = local -+ min_id = 10000 -+ max_id = 20000 -+ """).format(**locals()) -+ create_conf_fixture(request, conf) -+ create_sssd_fixture(request) -+ return None -+ -+ -+@pytest.fixture -+def sssd_pac_test_client(request): -+ path = os.path.join(config.ABS_BUILDDIR, -+ "..", "..", "..", "sssd_pac_test_client") -+ if os.access(path, os.X_OK): -+ return path -+ -+ return None -+ -+ -+def timeout_handler(signum, frame): -+ raise Exception("Timeout") -+ -+ -+def test_multithreaded_pac_client(local_domain_only, sssd_pac_test_client): -+ """ -+ Test for ticket -+ https://pagure.io/SSSD/sssd/issue/3518 -+ """ -+ -+ if not sssd_pac_test_client: -+ pytest.skip("The sssd_pac_test_client is not available, skipping test") -+ -+ signal.signal(signal.SIGALRM, timeout_handler) -+ signal.alarm(10) -+ -+ try: -+ subprocess.check_call(sssd_pac_test_client) -+ except: -+ # cancel alarm -+ signal.alarm(0) -+ raise Exception("sssd_pac_test_client failed") -+ -+ signal.alarm(0) --- -2.13.5 - diff --git a/SOURCES/0197-sysdb-sanitize-search-filter-input.patch b/SOURCES/0197-sysdb-sanitize-search-filter-input.patch deleted file mode 100644 index 0b2134d..0000000 --- a/SOURCES/0197-sysdb-sanitize-search-filter-input.patch +++ /dev/null @@ -1,140 +0,0 @@ -From 944295de4cf4eeba75d4f6bd476a4f59743e1813 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 5 Oct 2017 11:07:38 +0200 -Subject: [PATCH 197/197] sysdb: sanitize search filter input -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch sanitizes the input for sysdb searches by UPN/email, SID and -UUID. - -This security issue was assigned CVE-2017-12173 - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek -(cherry picked from commit 1f2662c8f97c9c0fa250055d4b6750abfc6d0835) ---- - src/db/sysdb_ops.c | 43 +++++++++++++++++++++++++++++++++++-------- - src/tests/sysdb-tests.c | 7 +++++++ - 2 files changed, 42 insertions(+), 8 deletions(-) - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 7ca6575ce75dab7805236c9f48dbf28a2f3946d2..408af9f389edbe0aff0fb8b96f49f0c4463a620a 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -601,6 +601,7 @@ int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx, - int ret; - const char *def_attrs[] = { SYSDB_NAME, SYSDB_UPN, SYSDB_CANONICAL_UPN, - SYSDB_USER_EMAIL, NULL }; -+ char *sanitized; - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { -@@ -608,6 +609,12 @@ int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx, - goto done; - } - -+ ret = sss_filter_sanitize(tmp_ctx, upn, &sanitized); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n"); -+ goto done; -+ } -+ - if (domain_scope == true) { - base_dn = sysdb_user_base_dn(tmp_ctx, domain); - } else { -@@ -620,7 +627,7 @@ int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx, - - ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, - base_dn, LDB_SCOPE_SUBTREE, attrs ? attrs : def_attrs, -- SYSDB_PWUPN_FILTER, upn, upn, upn); -+ SYSDB_PWUPN_FILTER, sanitized, sanitized, sanitized); - if (ret != EOK) { - ret = sysdb_error_to_errno(ret); - goto done; -@@ -4757,17 +4764,31 @@ static errno_t sysdb_search_object_by_str_attr(TALLOC_CTX *mem_ctx, - bool expect_only_one_result, - struct ldb_result **_res) - { -- char *filter; -+ char *filter = NULL; - errno_t ret; -+ char *sanitized = NULL; - -- filter = talloc_asprintf(NULL, filter_tmpl, str); -+ if (str == NULL) { -+ return EINVAL; -+ } -+ -+ ret = sss_filter_sanitize(NULL, str, &sanitized); -+ if (ret != EOK || sanitized == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n"); -+ goto done; -+ } -+ -+ filter = talloc_asprintf(NULL, filter_tmpl, sanitized); - if (filter == NULL) { -- return ENOMEM; -+ ret = ENOMEM; -+ goto done; - } - - ret = sysdb_search_object_attr(mem_ctx, domain, filter, attrs, - expect_only_one_result, _res); - -+done: -+ talloc_free(sanitized); - talloc_free(filter); - return ret; - } -@@ -4856,7 +4877,8 @@ errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx, - struct ldb_result **res) - { - int ret; -- char *user_filter; -+ char *user_filter = NULL; -+ char *filter = NULL; - - ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_MAPPED_CERT, - NULL, NULL, &user_filter); -@@ -4865,10 +4887,15 @@ errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx, - return ret; - } - -- ret = sysdb_search_object_by_str_attr(mem_ctx, domain, -- SYSDB_USER_CERT_FILTER, -- user_filter, attrs, false, res); -+ filter = talloc_asprintf(NULL, SYSDB_USER_CERT_FILTER, user_filter); - talloc_free(user_filter); -+ if (filter == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = sysdb_search_object_attr(mem_ctx, domain, filter, attrs, false, res); -+ -+ talloc_free(filter); - - return ret; - } -diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c -index 6ec82ce4ca5c4f918bc9f3144c21f33b270ea47e..588eb9ef02033ec061b4187964fe562da84e86c8 100644 ---- a/src/tests/sysdb-tests.c -+++ b/src/tests/sysdb-tests.c -@@ -6444,6 +6444,13 @@ START_TEST(test_upn_basic) - fail_unless(strcmp(str, UPN_PRINC) == 0, - "Expected [%s], got [%s].", UPN_PRINC, str); - -+ /* check if input is sanitized */ -+ ret = sysdb_search_user_by_upn(test_ctx, test_ctx->domain, false, -+ "abc@def.ghi)(name="UPN_USER_NAME")(abc=xyz", -+ NULL, &msg); -+ fail_unless(ret == ENOENT, -+ "sysdb_search_user_by_upn failed with un-sanitized input."); -+ - talloc_free(test_ctx); - } - END_TEST --- -2.13.5 - diff --git a/SOURCES/0198-ipa-make-sure-view-name-is-initialized-at-startup.patch b/SOURCES/0198-ipa-make-sure-view-name-is-initialized-at-startup.patch deleted file mode 100644 index 25422d6..0000000 --- a/SOURCES/0198-ipa-make-sure-view-name-is-initialized-at-startup.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 2d39f46386fb36b5a68f41644ce22c15bf6ccb67 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 31 Aug 2017 22:30:25 +0200 -Subject: [PATCH 198/199] ipa: make sure view name is initialized at startup - -sysdb_master_domain_update() can only set the view name properly if it was not -set before but it might be called multiple times before the view name is -available if the cache is empty. Since ipa_apply_view() keeps track if -the view name was already set at startup or not the name can safely be -cleaned here before sysdb_master_domain_update() is called. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3501 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit f00591a4615720640cf01b1c408315b57dd397dc) ---- - src/providers/ipa/ipa_subdomains.c | 19 ++++++++++++++++++- - 1 file changed, 18 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index 6f0ff50bde234f72d62f43635d9a787316c78430..0cb4d405e45689e9548ad3652e7260f2265bd1fe 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -739,6 +739,18 @@ done: - return ret; - } - -+static void clean_view_name(struct sss_domain_info *domain) -+{ -+ struct sss_domain_info *dom = domain; -+ -+ while (dom) { -+ dom->has_views = false; -+ talloc_free(discard_const(dom->view_name)); -+ dom->view_name = NULL; -+ dom = get_next_domain(dom, SSS_GND_DESCEND); -+ } -+} -+ - static errno_t ipa_apply_view(struct sss_domain_info *domain, - struct ipa_id_ctx *ipa_id_ctx, - const char *view_name, -@@ -831,7 +843,12 @@ static errno_t ipa_apply_view(struct sss_domain_info *domain, - } - - if (!read_at_init) { -- /* refresh view data of all domains at startup */ -+ /* refresh view data of all domains at startup, since -+ * sysdb_master_domain_update and sysdb_update_subdomains might have -+ * been called earlier without the proper view name the name is -+ * cleaned here before the calls. This is acceptable because this is -+ * the initial setup (!read_at_init). */ -+ clean_view_name(domain); - ret = sysdb_master_domain_update(domain); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_master_domain_update failed " --- -2.13.5 - diff --git a/SOURCES/0199-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch b/SOURCES/0199-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch deleted file mode 100644 index ba0c504..0000000 --- a/SOURCES/0199-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch +++ /dev/null @@ -1,142 +0,0 @@ -From a1634a3c4b977364fd7612efa3ee21872a8d578e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Fri, 20 Oct 2017 09:26:43 +0200 -Subject: [PATCH 199/199] CACHE_REQ: Copy the cr_domain list for each request -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Let's copy the cr_domain list for each request as this list may be -free'd due to a refresh domains request. - -Resolves: https://pagure.io/SSSD/sssd/issue/3551 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Pavel Březina -(cherry picked from commit 0f44eefe2ce75a0814c8688495477f6c57f3d39a) ---- - src/responder/common/cache_req/cache_req.c | 14 +++++++-- - src/responder/common/cache_req/cache_req_domain.c | 38 +++++++++++++++++++++++ - src/responder/common/cache_req/cache_req_domain.h | 5 +++ - 3 files changed, 55 insertions(+), 2 deletions(-) - -diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c -index 7d77eb7dd72a7ccf3d687eee8f746ab84176b487..83eab8ed2de0b5c7d25306d853aadc9b53cb4842 100644 ---- a/src/responder/common/cache_req/cache_req.c -+++ b/src/responder/common/cache_req/cache_req.c -@@ -688,6 +688,7 @@ struct cache_req_state { - const char *domain_name; - - /* work data */ -+ struct cache_req_domain *cr_domains; - struct cache_req_result **results; - size_t num_results; - bool first_iteration; -@@ -940,6 +941,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req, - bool bypass_cache; - bool bypass_dp; - bool search; -+ errno_t ret; - - state = tevent_req_data(req, struct cache_req_state); - -@@ -951,12 +953,20 @@ static errno_t cache_req_select_domains(struct tevent_req *req, - return EOK; - } - -+ ret = cache_req_domain_copy_cr_domains(state, -+ state->cr->rctx->cr_domains, -+ &state->cr_domains); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_copy_cr_domains() failed\n"); -+ return EINVAL; -+ } -+ - if (domain_name != NULL) { - CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, - "Performing a single domain search\n"); - - cr_domain = cache_req_domain_get_domain_by_name( -- state->cr->rctx->cr_domains, domain_name); -+ state->cr_domains, domain_name); - if (cr_domain == NULL) { - return ERR_DOMAIN_NOT_FOUND; - } -@@ -965,7 +975,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req, - CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, - "Performing a multi-domain search\n"); - -- cr_domain = state->cr->rctx->cr_domains; -+ cr_domain = state->cr_domains; - check_next = true; - } - -diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c -index c2b5abb74f3bd3d5055f29a4523f29b05feb2014..8c9f155303b174f16b884eb66ba1c88a0256719d 100644 ---- a/src/responder/common/cache_req/cache_req_domain.c -+++ b/src/responder/common/cache_req/cache_req_domain.c -@@ -47,6 +47,44 @@ cache_req_domain_get_domain_by_name(struct cache_req_domain *domains, - return ret; - } - -+errno_t -+cache_req_domain_copy_cr_domains(TALLOC_CTX *mem_ctx, -+ struct cache_req_domain *src, -+ struct cache_req_domain **_dest) -+{ -+ struct cache_req_domain *cr_domains = NULL; -+ struct cache_req_domain *cr_domain; -+ struct cache_req_domain *iter; -+ errno_t ret; -+ -+ if (src == NULL) { -+ return EINVAL; -+ } -+ -+ DLIST_FOR_EACH(iter, src) { -+ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain); -+ if (cr_domain == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ cr_domain->domain = iter->domain; -+ cr_domain->fqnames = iter->fqnames; -+ -+ DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *); -+ } -+ -+ *_dest = cr_domains; -+ ret = EOK; -+ -+done: -+ if (ret != EOK) { -+ cache_req_domain_list_zfree(&cr_domains); -+ } -+ -+ return ret; -+} -+ - void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains) - { - struct cache_req_domain *p, *q, *r; -diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h -index 3780a5d8d88d76e100738d28d1dd0e697edf5eae..ebdc71dd635d5d8a5d06e30e96c5d4101b6d98bf 100644 ---- a/src/responder/common/cache_req/cache_req_domain.h -+++ b/src/responder/common/cache_req/cache_req_domain.h -@@ -50,6 +50,11 @@ cache_req_domain_new_list_from_domain_resolution_order( - const char *domain_resolution_order, - struct cache_req_domain **_cr_domains); - -+errno_t -+cache_req_domain_copy_cr_domains(TALLOC_CTX *mem_ctx, -+ struct cache_req_domain *src, -+ struct cache_req_domain **_dest); -+ - void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains); - - --- -2.13.5 - diff --git a/SOURCES/0200-cache_req-Correction-of-cache_req-debug-string-ID-fo.patch b/SOURCES/0200-cache_req-Correction-of-cache_req-debug-string-ID-fo.patch deleted file mode 100644 index fd77137..0000000 --- a/SOURCES/0200-cache_req-Correction-of-cache_req-debug-string-ID-fo.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 9c22ba8f68b48aff49bcdc8af67964a8852e998c Mon Sep 17 00:00:00 2001 -From: amitkuma -Date: Tue, 14 Nov 2017 13:59:12 +0530 -Subject: [PATCH 200/201] cache_req: Correction of cache_req debug string ID - format -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The cache-req debug string representation uses a wrong format -specifier for by-ID requests. -data->id (uint32_t) should be replaced with %"PRIu32" -in cache_req_group_by_id.c, cache_req_object_by_id.c & -cache_req_user_by_id.c. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3570 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit d25646c64a7117a6551468256efa82d01647751e) ---- - src/responder/common/cache_req/plugins/cache_req_group_by_id.c | 2 +- - src/responder/common/cache_req/plugins/cache_req_object_by_id.c | 2 +- - src/responder/common/cache_req/plugins/cache_req_user_by_id.c | 2 +- - 3 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -index 5ca64283a781318bc4e4d6920fff989c3f3919b4..121f95abe86d2466aaea69f0fe68dfb33b1fee9e 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -@@ -31,7 +31,7 @@ cache_req_group_by_id_create_debug_name(TALLOC_CTX *mem_ctx, - struct cache_req_data *data, - struct sss_domain_info *domain) - { -- return talloc_asprintf(mem_ctx, "GID:%d@%s", data->id, domain->name); -+ return talloc_asprintf(mem_ctx, "GID:%"PRIu32"@%s", data->id, domain->name); - } - - static errno_t -diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -index 339bd4f5fef827acc1aa3c123d041e426d9e4782..4c88e1035b41969703c1c38d740e15516ac0d622 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -@@ -31,7 +31,7 @@ cache_req_object_by_id_create_debug_name(TALLOC_CTX *mem_ctx, - struct cache_req_data *data, - struct sss_domain_info *domain) - { -- return talloc_asprintf(mem_ctx, "ID:%d@%s", data->id, domain->name); -+ return talloc_asprintf(mem_ctx, "ID:%"PRIu32"@%s", data->id, domain->name); - } - - static errno_t -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -index 913f9be5bcc2dfd074b52cb3b15fb6948826e831..3c25c7631b3da4a829ab577629334a7ee97980da 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -@@ -31,7 +31,7 @@ cache_req_user_by_id_create_debug_name(TALLOC_CTX *mem_ctx, - struct cache_req_data *data, - struct sss_domain_info *domain) - { -- return talloc_asprintf(mem_ctx, "UID:%d@%s", data->id, domain->name); -+ return talloc_asprintf(mem_ctx, "UID:%"PRIu32"@%s", data->id, domain->name); - } - - static errno_t --- -2.14.3 - diff --git a/SOURCES/0201-cache-Check-for-max_id-min_id-in-cache_req.patch b/SOURCES/0201-cache-Check-for-max_id-min_id-in-cache_req.patch deleted file mode 100644 index 1186293..0000000 --- a/SOURCES/0201-cache-Check-for-max_id-min_id-in-cache_req.patch +++ /dev/null @@ -1,318 +0,0 @@ -From 7618d442a25a16940f0842d2ad4ae34e60079844 Mon Sep 17 00:00:00 2001 -From: amitkuma -Date: Thu, 30 Nov 2017 22:18:39 +0530 -Subject: [PATCH 201/201] cache: Check for max_id/min_id in cache_req -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The cache_req code doesn't check the min_id/max_id -boundaries for requests by ID. -Extending the .lookup_fn function in each plugin -that searches by ID for a check that returns non-zero -if the entry is out of the range and 0 if not. - -Resolves: https://pagure.io/SSSD/sssd/issue/3569 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 2af80640f18966d65cf82106059ce3c060df93bf) ---- - src/responder/common/cache_req/cache_req.c | 1 + - src/responder/common/cache_req/cache_req_private.h | 2 + - src/responder/common/cache_req/cache_req_search.c | 5 ++ - .../common/cache_req/plugins/cache_req_common.c | 11 +++ - .../cache_req/plugins/cache_req_group_by_id.c | 6 ++ - .../cache_req/plugins/cache_req_object_by_id.c | 6 ++ - .../cache_req/plugins/cache_req_user_by_id.c | 5 ++ - src/tests/cmocka/test_responder_cache_req.c | 81 +++++++++++++++++++++- - src/util/util_errors.c | 1 + - src/util/util_errors.h | 1 + - 10 files changed, 117 insertions(+), 2 deletions(-) - -diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c -index 83eab8ed2de0b5c7d25306d853aadc9b53cb4842..3ebf64af24bb9a2a67165dd17d27fd25fc7915c2 100644 ---- a/src/responder/common/cache_req/cache_req.c -+++ b/src/responder/common/cache_req/cache_req.c -@@ -574,6 +574,7 @@ static void cache_req_search_domains_done(struct tevent_req *subreq) - } - - break; -+ case ERR_ID_OUTSIDE_RANGE: - case ENOENT: - if (state->check_next == false) { - /* Not found. */ -diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h -index c0ee5f969f2a171b8a6eb396b3d14b593d157b76..5b79d9429bc29c47c28e0b5a6367a6e7035ca1c3 100644 ---- a/src/responder/common/cache_req/cache_req_private.h -+++ b/src/responder/common/cache_req/cache_req_private.h -@@ -165,4 +165,6 @@ bool - cache_req_common_dp_recv(struct tevent_req *subreq, - struct cache_req *cr); - -+errno_t cache_req_idminmax_check(struct cache_req_data *data, -+ struct sss_domain_info *domain); - #endif /* _CACHE_REQ_PRIVATE_H_ */ -diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c -index 56d0345cd8f98de574961d3c9628ae7a4c24f9be..ba25dcf578ef80aa8597bccb41da839d7bd146b3 100644 ---- a/src/responder/common/cache_req/cache_req_search.c -+++ b/src/responder/common/cache_req/cache_req_search.c -@@ -197,6 +197,11 @@ static errno_t cache_req_search_cache(TALLOC_CTX *mem_ctx, - - *_result = result; - break; -+ case ERR_ID_OUTSIDE_RANGE: -+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, -+ "ID [%s] was filtered out\n", -+ cr->debugobj); -+ break; - case ENOENT: - CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, - "Object [%s] was not found in cache\n", -diff --git a/src/responder/common/cache_req/plugins/cache_req_common.c b/src/responder/common/cache_req/plugins/cache_req_common.c -index b80f310feeebbdbc824db441ff5313632585d3fb..d7c6ab2eac412042f90d491eb8428116156f512b 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_common.c -+++ b/src/responder/common/cache_req/plugins/cache_req_common.c -@@ -26,6 +26,17 @@ - #include "providers/data_provider.h" - #include "responder/common/cache_req/cache_req_plugin.h" - -+errno_t cache_req_idminmax_check(struct cache_req_data *data, -+ struct sss_domain_info *domain) -+{ -+ if (((domain->id_min != 0) && (data->id < domain->id_min)) || -+ ((domain->id_max != 0) && (data->id > domain->id_max))) { -+ DEBUG(SSSDBG_FUNC_DATA, "id exceeds min/max boundaries\n"); -+ return ERR_ID_OUTSIDE_RANGE; -+ } -+ return EOK; -+} -+ - static struct ldb_message * - cache_req_well_known_sid_msg(TALLOC_CTX *mem_ctx, - const char *sid, -diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -index 121f95abe86d2466aaea69f0fe68dfb33b1fee9e..04e085456f38e154a04ce0a803f2ba22830c1827 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c -@@ -64,6 +64,12 @@ cache_req_group_by_id_lookup(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - struct ldb_result **_result) - { -+ errno_t ret; -+ -+ ret = cache_req_idminmax_check(data, domain); -+ if (ret != EOK) { -+ return ret; -+ } - return sysdb_getgrgid_with_views(mem_ctx, domain, data->id, _result); - } - -diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -index 4c88e1035b41969703c1c38d740e15516ac0d622..50c149e8795a61307e445d4c063dc0df1166519c 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c -@@ -90,6 +90,12 @@ cache_req_object_by_id_lookup(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - struct ldb_result **_result) - { -+ errno_t ret; -+ -+ ret = cache_req_idminmax_check(data, domain); -+ if (ret != EOK) { -+ return ret; -+ } - return sysdb_search_object_by_id(mem_ctx, domain, data->id, - data->attrs, _result); - } -diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -index 3c25c7631b3da4a829ab577629334a7ee97980da..05add9564f57655bb53520b848971286bba6cab5 100644 ---- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c -@@ -64,6 +64,11 @@ cache_req_user_by_id_lookup(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - struct ldb_result **_result) - { -+ errno_t ret; -+ ret = cache_req_idminmax_check(data, domain); -+ if (ret != EOK) { -+ return ret; -+ } - return sysdb_getpwuid_with_views(mem_ctx, domain, data->id, _result); - } - -diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c -index 80086232fd437876c2b190fb972c2ee3194d9efd..82ba4125265d0bacd44a9f0082d588eef673a6f0 100644 ---- a/src/tests/cmocka/test_responder_cache_req.c -+++ b/src/tests/cmocka/test_responder_cache_req.c -@@ -58,6 +58,11 @@ struct test_group { - test_single_domain_setup, \ - test_single_domain_teardown) - -+#define new_single_domain_id_limit_test(test) \ -+ cmocka_unit_test_setup_teardown(test_ ## test, \ -+ test_single_domain_id_limits_setup, \ -+ test_single_domain_teardown) -+ - #define new_multi_domain_test(test) \ - cmocka_unit_test_setup_teardown(test_ ## test, \ - test_multi_domain_setup, \ -@@ -451,7 +456,8 @@ __wrap_sss_dp_get_account_send(TALLOC_CTX *mem_ctx, - return test_req_succeed_send(mem_ctx, rctx->ev); - } - --static int test_single_domain_setup(void **state) -+static int test_single_domain_setup_common(void **state, -+ struct sss_test_conf_param *params) - { - struct cache_req_test_ctx *test_ctx = NULL; - errno_t ret; -@@ -465,7 +471,7 @@ static int test_single_domain_setup(void **state) - *state = test_ctx; - - test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, TEST_CONF_DB, -- TEST_DOM_NAME, TEST_ID_PROVIDER, NULL); -+ TEST_DOM_NAME, TEST_ID_PROVIDER, params); - assert_non_null(test_ctx->tctx); - - test_ctx->rctx = mock_rctx(test_ctx, test_ctx->tctx->ev, -@@ -480,6 +486,11 @@ static int test_single_domain_setup(void **state) - return 0; - } - -+static int test_single_domain_setup(void **state) -+{ -+ return test_single_domain_setup_common(state, NULL); -+} -+ - static int test_single_domain_teardown(void **state) - { - struct cache_req_test_ctx *test_ctx; -@@ -495,6 +506,16 @@ static int test_single_domain_teardown(void **state) - return 0; - } - -+static int test_single_domain_id_limits_setup(void **state) -+{ -+ struct sss_test_conf_param params[] = { -+ { "min_id", "100" }, -+ { "max_id", "10000" }, -+ { NULL, NULL }, /* Sentinel */ -+ }; -+ return test_single_domain_setup_common(state, params); -+} -+ - static int test_multi_domain_setup(void **state) - { - struct cache_req_test_ctx *test_ctx = NULL; -@@ -526,6 +547,32 @@ static int test_multi_domain_setup(void **state) - return 0; - } - -+void test_user_by_id_below_id_range(void **state) -+{ -+ struct cache_req_test_ctx *test_ctx = NULL; -+ -+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); -+ -+ /* Test. */ -+ run_cache_req(test_ctx, cache_req_user_by_id_send, -+ cache_req_user_by_id_test_done, test_ctx->tctx->dom, -+ 0, 10, ENOENT); -+ assert_false(test_ctx->dp_called); -+} -+ -+void test_user_by_id_above_id_range(void **state) -+{ -+ struct cache_req_test_ctx *test_ctx = NULL; -+ -+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); -+ -+ /* Test. */ -+ run_cache_req(test_ctx, cache_req_user_by_id_send, -+ cache_req_user_by_id_test_done, test_ctx->tctx->dom, -+ 0, 100000, ENOENT); -+ assert_false(test_ctx->dp_called); -+} -+ - static int test_multi_domain_teardown(void **state) - { - struct cache_req_test_ctx *test_ctx; -@@ -1084,6 +1131,32 @@ void test_group_by_name_multiple_domains_found(void **state) - check_group(test_ctx, &groups[0], domain); - } - -+void test_group_by_id_below_id_range(void **state) -+{ -+ struct cache_req_test_ctx *test_ctx = NULL; -+ -+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); -+ -+ /* Test. */ -+ run_cache_req(test_ctx, cache_req_group_by_id_send, -+ cache_req_group_by_id_test_done, test_ctx->tctx->dom, -+ 0, 10, ENOENT); -+ assert_false(test_ctx->dp_called); -+} -+ -+void test_group_by_id_above_id_range(void **state) -+{ -+ struct cache_req_test_ctx *test_ctx = NULL; -+ -+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); -+ -+ /* Test. */ -+ run_cache_req(test_ctx, cache_req_group_by_id_send, -+ cache_req_group_by_id_test_done, test_ctx->tctx->dom, -+ 0, 100000, ENOENT); -+ assert_false(test_ctx->dp_called); -+} -+ - void test_group_by_name_multiple_domains_notfound(void **state) - { - struct cache_req_test_ctx *test_ctx = NULL; -@@ -2170,6 +2243,8 @@ int main(int argc, const char *argv[]) - new_single_domain_test(user_by_id_missing_notfound), - new_multi_domain_test(user_by_id_multiple_domains_found), - new_multi_domain_test(user_by_id_multiple_domains_notfound), -+ new_single_domain_id_limit_test(user_by_id_below_id_range), -+ new_single_domain_id_limit_test(user_by_id_above_id_range), - - new_single_domain_test(group_by_name_cache_valid), - new_single_domain_test(group_by_name_cache_expired), -@@ -2180,6 +2255,8 @@ int main(int argc, const char *argv[]) - new_multi_domain_test(group_by_name_multiple_domains_found), - new_multi_domain_test(group_by_name_multiple_domains_notfound), - new_multi_domain_test(group_by_name_multiple_domains_parse), -+ new_single_domain_id_limit_test(group_by_id_below_id_range), -+ new_single_domain_id_limit_test(group_by_id_above_id_range), - - new_single_domain_test(group_by_id_cache_valid), - new_single_domain_test(group_by_id_cache_expired), -diff --git a/src/util/util_errors.c b/src/util/util_errors.c -index 97eaf160f20bcc8cfe52254070a2d182e19addd4..9f6e413f0414f38dee4f0ee6b5f3fbeaac5d6612 100644 ---- a/src/util/util_errors.c -+++ b/src/util/util_errors.c -@@ -116,6 +116,7 @@ struct err_string error_to_str[] = { - { "Unable to initialize SSL" }, /* ERR_SSL_FAILURE */ - { "Unable to verify peer" }, /* ERR_UNABLE_TO_VERIFY_PEER */ - { "Unable to resolve host" }, /* ERR_UNABLE_TO_RESOLVE_HOST */ -+ { "ID is outside the allowed range" }, /* ERR_ID_OUTSIDE_RANGE */ - { "ERR_LAST" } /* ERR_LAST */ - }; - -diff --git a/src/util/util_errors.h b/src/util/util_errors.h -index 4a250bf0339ba689680c155fa8e6d43f42c2467e..051111ea7c249a5d8e4f302022898648ba2ffdd2 100644 ---- a/src/util/util_errors.h -+++ b/src/util/util_errors.h -@@ -138,6 +138,7 @@ enum sssd_errors { - ERR_SSL_FAILURE, - ERR_UNABLE_TO_VERIFY_PEER, - ERR_UNABLE_TO_RESOLVE_HOST, -+ ERR_ID_OUTSIDE_RANGE, - ERR_LAST /* ALWAYS LAST */ - }; - --- -2.14.3 - diff --git a/SOURCES/0202-sudo-always-use-srv_opts-from-id-context.patch b/SOURCES/0202-sudo-always-use-srv_opts-from-id-context.patch deleted file mode 100644 index a22ead0..0000000 --- a/SOURCES/0202-sudo-always-use-srv_opts-from-id-context.patch +++ /dev/null @@ -1,64 +0,0 @@ -From fbfb378def4ce7b807685b6d5391a9f3a2ef26d5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Thu, 19 Oct 2017 10:39:21 +0200 -Subject: [PATCH 202/202] sudo: always use srv_opts from id context - -Prior this patch, we remember id_ctx->srv_opts in sudo request to switch -the latest usn values. This works fine most of the time but it may cause -a crash. - -If we have two concurrent sudo refresh and one of these fails, it causes -failover to try the next server and possibly replacing the old srv_opts -with new one and it causes an access after free in the other refresh. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3562 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 2ee201dcf6bbe52abbbed3c2fc4c35ca2e0c8a43) ---- - src/providers/ldap/sdap_async_sudo.c | 7 +------ - 1 file changed, 1 insertion(+), 6 deletions(-) - -diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c -index 3c69837fda313b2645c3a8497252670312f600ea..88a387422d5c9ae86cea583bb38dadf90cba37f3 100644 ---- a/src/providers/ldap/sdap_async_sudo.c -+++ b/src/providers/ldap/sdap_async_sudo.c -@@ -279,7 +279,6 @@ done: - struct sdap_sudo_refresh_state { - struct sdap_sudo_ctx *sudo_ctx; - struct tevent_context *ev; -- struct sdap_server_opts *srv_opts; - struct sdap_options *opts; - struct sdap_id_op *sdap_op; - struct sysdb_ctx *sysdb; -@@ -405,9 +404,6 @@ static void sdap_sudo_refresh_connect_done(struct tevent_req *subreq) - - DEBUG(SSSDBG_TRACE_FUNC, "SUDO LDAP connection successful\n"); - -- /* Obtain srv_opts here in case of first connection. */ -- state->srv_opts = state->sudo_ctx->id_ctx->srv_opts; -- - /* Renew host information if needed. */ - if (state->sudo_ctx->run_hostinfo) { - subreq = sdap_sudo_get_hostinfo_send(state, state->opts, -@@ -586,7 +582,6 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq) - goto done; - } - -- - /* start transaction */ - ret = sysdb_transaction_start(state->sysdb); - if (ret != EOK) { -@@ -621,7 +616,7 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq) - /* remember new usn */ - ret = sysdb_get_highest_usn(state, rules, rules_count, &usn); - if (ret == EOK) { -- sdap_sudo_set_usn(state->srv_opts, usn); -+ sdap_sudo_set_usn(state->sudo_ctx->id_ctx->srv_opts, usn); - } else { - DEBUG(SSSDBG_MINOR_FAILURE, "Unable to get highest USN [%d]: %s\n", - ret, sss_strerror(ret)); --- -2.14.3 - diff --git a/SOURCES/0203-SELINUX-Use-getseuserbyname-to-get-IPA-seuser.patch b/SOURCES/0203-SELINUX-Use-getseuserbyname-to-get-IPA-seuser.patch deleted file mode 100644 index 927f159..0000000 --- a/SOURCES/0203-SELINUX-Use-getseuserbyname-to-get-IPA-seuser.patch +++ /dev/null @@ -1,182 +0,0 @@ -From 0006bd76856787614f961001929fea95d0669fe5 Mon Sep 17 00:00:00 2001 -From: Justin Stephenson -Date: Thu, 9 Mar 2017 17:21:37 -0500 -Subject: [PATCH 203/205] SELINUX: Use getseuserbyname to get IPA seuser -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The libselinux function getseuserbyname is more reliable method to retrieve -SELinux usernames then functions from libsemanage `semanage_user_query` -and is recommended by libsemanage developers. -Replace get_seuser function with getseuserbyname. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3308 - -Reviewed-by: Michal Židek -Reviewed-by: Jakub Hrozek -Reviewed-by: Petr Lautrbach -(cherry picked from commit cfe87ca0c4fded9cbf907697d08fa0e6c8f8ebce) ---- - Makefile.am | 1 + - src/providers/ipa/selinux_child.c | 12 +++---- - src/util/sss_semanage.c | 73 --------------------------------------- - src/util/util.h | 2 -- - 4 files changed, 7 insertions(+), 81 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index cdd517d50679b876814303fb7d6c63d49bcd8d38..1eb398830e4817d4da0878a6577b45df101e920d 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -4094,6 +4094,7 @@ selinux_child_LDADD = \ - $(POPT_LIBS) \ - $(DHASH_LIBS) \ - $(SEMANAGE_LIBS) \ -+ $(SELINUX_LIBS) \ - $(NULL) - endif - -diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c -index f8dd3954a7244df2dcbb910aabf8888f41306c09..073475094ee491bd5453898c6ba65214fa14fe59 100644 ---- a/src/providers/ipa/selinux_child.c -+++ b/src/providers/ipa/selinux_child.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - #include "util/util.h" - #include "util/child_common.h" -@@ -172,11 +173,10 @@ static bool seuser_needs_update(struct input_buffer *ibuf) - char *db_mls_range = NULL; - errno_t ret; - -- ret = get_seuser(ibuf, ibuf->username, &db_seuser, &db_mls_range); -+ ret = getseuserbyname(ibuf->username, &db_seuser, &db_mls_range); - DEBUG(SSSDBG_TRACE_INTERNAL, -- "get_seuser: ret: %d msg: [%s] seuser: %s mls: %s\n", -- ret, sss_strerror(ret), -- db_seuser ? db_seuser : "unknown", -+ "getseuserbyname: ret: %d seuser: %s mls: %s\n", -+ ret, db_seuser ? db_seuser : "unknown", - db_mls_range ? db_mls_range : "unknown"); - if (ret == EOK && db_seuser && db_mls_range && - strcmp(db_seuser, ibuf->seuser) == 0 && -@@ -188,8 +188,8 @@ static bool seuser_needs_update(struct input_buffer *ibuf) - needs_update = false; - } - -- talloc_free(db_seuser); -- talloc_free(db_mls_range); -+ free(db_seuser); -+ free(db_mls_range); - return needs_update; - } - -diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c -index 0da97aad4d8eba733b131c2749932e03ca4242c4..37278cc986a1ea49dc2218a635d52b9d54ca089d 100644 ---- a/src/util/sss_semanage.c -+++ b/src/util/sss_semanage.c -@@ -382,73 +382,6 @@ done: - sss_semanage_close(handle); - return ret; - } -- --int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name, -- char **_seuser, char **_mls_range) --{ -- errno_t ret; -- const char *seuser; -- const char *mls_range; -- semanage_handle_t *sm_handle = NULL; -- semanage_seuser_t *sm_user = NULL; -- semanage_seuser_key_t *sm_key = NULL; -- -- ret = sss_semanage_init(&sm_handle); -- if (ret == ERR_SELINUX_NOT_MANAGED) { -- goto done; -- } else if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux handle\n"); -- goto done; -- } -- -- ret = semanage_seuser_key_create(sm_handle, login_name, &sm_key); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create key for %s\n", login_name); -- ret = EIO; -- goto done; -- } -- -- ret = semanage_seuser_query(sm_handle, sm_key, &sm_user); -- if (ret < 0) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot query for %s\n", login_name); -- ret = EIO; -- goto done; -- } -- -- seuser = semanage_seuser_get_sename(sm_user); -- if (seuser != NULL) { -- *_seuser = talloc_strdup(mem_ctx, seuser); -- if (*_seuser == NULL) { -- ret = ENOMEM; -- goto done; -- } -- DEBUG(SSSDBG_OP_FAILURE, -- "SELinux user for %s: %s\n", login_name, *_seuser); -- } else { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get sename for %s\n", login_name); -- } -- -- mls_range = semanage_seuser_get_mlsrange(sm_user); -- if (mls_range != NULL) { -- *_mls_range = talloc_strdup(mem_ctx, mls_range); -- if (*_mls_range == NULL) { -- ret = ENOMEM; -- goto done; -- } -- DEBUG(SSSDBG_OP_FAILURE, -- "SELinux range for %s: %s\n", login_name, *_mls_range); -- } else { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get mlsrange for %s\n", login_name); -- } -- -- ret = EOK; --done: -- semanage_seuser_key_free(sm_key); -- semanage_seuser_free(sm_user); -- sss_semanage_close(sm_handle); -- return ret; --} -- - #else /* HAVE_SEMANAGE */ - int set_seuser(const char *login_name, const char *seuser_name, - const char *mls) -@@ -460,10 +393,4 @@ int del_seuser(const char *login_name) - { - return EOK; - } -- --int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name, -- char **_seuser, char **_mls_range) --{ -- return EOK; --} - #endif /* HAVE_SEMANAGE */ -diff --git a/src/util/util.h b/src/util/util.h -index 72d4116e1206e9cc69715edc45bf5b9b91e37e6b..1719d8eec1b6b05877b9be3382589e442bff85be 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -658,8 +658,6 @@ errno_t restore_creds(struct sss_creds *saved_creds); - int set_seuser(const char *login_name, const char *seuser_name, - const char *mlsrange); - int del_seuser(const char *login_name); --int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name, -- char **_seuser, char **_mls_range); - - /* convert time from generalized form to unix time */ - errno_t sss_utc_to_time_t(const char *str, const char *format, time_t *unix_time); --- -2.14.3 - diff --git a/SOURCES/0204-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch b/SOURCES/0204-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch deleted file mode 100644 index 3c6c46d..0000000 --- a/SOURCES/0204-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch +++ /dev/null @@ -1,203 +0,0 @@ -From 8db75e9ebbdaec1dde836380ca38d8cfec61cf3d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Thu, 1 Feb 2018 11:34:21 +0100 -Subject: [PATCH 204/205] SELINUX: Check if SELinux is managed in selinux_child -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If SELinux policy is not managed at all, don't call any SELinux user -handling functions and instead return that no update is needed. - -Pair-Programmed-With: Jakub Hrozek -Reviewed-by: Lukáš Slebodník -Reviewed-by: Fabiano Fidêncio - -Resolves: -https://pagure.io/SSSD/sssd/issue/3618 -(cherry picked from commit 450b472a68abf442479755c7916c757907b35ea5) ---- - src/providers/ipa/selinux_child.c | 3 +- - src/util/sss_semanage.c | 82 +++++++++++++++++++++++++++++++-------- - src/util/util.h | 3 ++ - 3 files changed, 70 insertions(+), 18 deletions(-) - -diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c -index 073475094ee491bd5453898c6ba65214fa14fe59..bc9460e122ce991087a744fd5335e6c468c6a64b 100644 ---- a/src/providers/ipa/selinux_child.c -+++ b/src/providers/ipa/selinux_child.c -@@ -27,7 +27,6 @@ - #include - #include - #include --#include - - #include "util/util.h" - #include "util/child_common.h" -@@ -173,7 +172,7 @@ static bool seuser_needs_update(struct input_buffer *ibuf) - char *db_mls_range = NULL; - errno_t ret; - -- ret = getseuserbyname(ibuf->username, &db_seuser, &db_mls_range); -+ ret = sss_get_seuser(ibuf->username, &db_seuser, &db_mls_range); - DEBUG(SSSDBG_TRACE_INTERNAL, - "getseuserbyname: ret: %d seuser: %s mls: %s\n", - ret, db_seuser ? db_seuser : "unknown", -diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c -index 37278cc986a1ea49dc2218a635d52b9d54ca089d..25b6bcdad2ad7e7ac710497f13d6a6e22360b0dd 100644 ---- a/src/util/sss_semanage.c -+++ b/src/util/sss_semanage.c -@@ -22,8 +22,9 @@ - #include "config.h" - - #include --#ifdef HAVE_SEMANAGE -+#if defined(HAVE_SEMANAGE) && defined(HAVE_SELINUX) - #include -+#include - #endif - - #include "util/util.h" -@@ -32,7 +33,7 @@ - #define DEFAULT_SERANGE "s0" - #endif - --#ifdef HAVE_SEMANAGE -+#if defined(HAVE_SEMANAGE) && defined(HAVE_SELINUX) - /* turn libselinux messages into SSSD DEBUG() calls */ - static void sss_semanage_error_callback(void *varg, - semanage_handle_t *handle, -@@ -73,33 +74,47 @@ static void sss_semanage_close(semanage_handle_t *handle) - semanage_handle_destroy(handle); - } - --static int sss_semanage_init(semanage_handle_t **_handle) -+static int sss_is_selinux_managed(semanage_handle_t *handle) - { - int ret; -- semanage_handle_t *handle = NULL; - -- handle = semanage_handle_create(); -- if (!handle) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n"); -- ret = EIO; -- goto done; -+ if (handle == NULL) { -+ return EINVAL; - } - -- semanage_msg_set_callback(handle, -- sss_semanage_error_callback, -- NULL); -- - ret = semanage_is_managed(handle); - if (ret == 0) { - DEBUG(SSSDBG_TRACE_FUNC, "SELinux policy not managed via libsemanage\n"); -- ret = ERR_SELINUX_NOT_MANAGED; -- goto done; -+ return ERR_SELINUX_NOT_MANAGED; - } else if (ret == -1) { - DEBUG(SSSDBG_CRIT_FAILURE, "Call to semanage_is_managed failed\n"); -+ return EIO; -+ } -+ -+ return EOK; -+} -+ -+static int sss_semanage_init(semanage_handle_t **_handle) -+{ -+ int ret; -+ semanage_handle_t *handle = NULL; -+ -+ handle = semanage_handle_create(); -+ if (!handle) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n"); - ret = EIO; - goto done; - } - -+ semanage_msg_set_callback(handle, -+ sss_semanage_error_callback, -+ NULL); -+ -+ ret = sss_is_selinux_managed(handle); -+ if (ret != EOK) { -+ goto done; -+ } -+ - ret = semanage_access_check(handle); - if (ret < SEMANAGE_CAN_READ) { - DEBUG(SSSDBG_CRIT_FAILURE, "Cannot read SELinux policy store\n"); -@@ -229,6 +244,34 @@ done: - return ret; - } - -+int sss_get_seuser(const char *linuxuser, -+ char **selinuxuser, -+ char **level) -+{ -+ int ret; -+ semanage_handle_t *handle; -+ -+ handle = semanage_handle_create(); -+ if (handle == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n"); -+ return EIO; -+ } -+ -+ semanage_msg_set_callback(handle, -+ sss_semanage_error_callback, -+ NULL); -+ -+ /* We only needed the handle for this call. Close the handle right -+ * after it */ -+ ret = sss_is_selinux_managed(handle); -+ sss_semanage_close(handle); -+ if (ret != EOK) { -+ return ret; -+ } -+ -+ return getseuserbyname(linuxuser, selinuxuser, level); -+} -+ - int set_seuser(const char *login_name, const char *seuser_name, - const char *mls) - { -@@ -382,7 +425,7 @@ done: - sss_semanage_close(handle); - return ret; - } --#else /* HAVE_SEMANAGE */ -+#else /* HAVE_SEMANAGE && HAVE_SELINUX */ - int set_seuser(const char *login_name, const char *seuser_name, - const char *mls) - { -@@ -393,4 +436,11 @@ int del_seuser(const char *login_name) - { - return EOK; - } -+ -+int sss_get_seuser(const char *linuxuser, -+ char **selinuxuser, -+ char **level) -+{ -+ return EOK; -+} - #endif /* HAVE_SEMANAGE */ -diff --git a/src/util/util.h b/src/util/util.h -index 1719d8eec1b6b05877b9be3382589e442bff85be..74ce2dcecfe17d1cea96cfb5c4b7edb8fd46f09f 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -658,6 +658,9 @@ errno_t restore_creds(struct sss_creds *saved_creds); - int set_seuser(const char *login_name, const char *seuser_name, - const char *mlsrange); - int del_seuser(const char *login_name); -+int sss_get_seuser(const char *linuxuser, -+ char **selinuxuser, -+ char **level); - - /* convert time from generalized form to unix time */ - errno_t sss_utc_to_time_t(const char *str, const char *format, time_t *unix_time); --- -2.14.3 - diff --git a/SOURCES/0205-util-Add-sss_-prefix-to-some-functions.patch b/SOURCES/0205-util-Add-sss_-prefix-to-some-functions.patch deleted file mode 100644 index 020f747..0000000 --- a/SOURCES/0205-util-Add-sss_-prefix-to-some-functions.patch +++ /dev/null @@ -1,142 +0,0 @@ -From da163073db166a8f3acc07391ccdaedc8aa70230 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 6 Feb 2018 19:17:55 +0100 -Subject: [PATCH 205/205] util: Add sss_ prefix to some functions -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add sss_ prefix to del_seuser and set_seuser for consistency -with sss_get_seuser. Also sss_ prefix makes it clear that -these functions come from SSSD. - -Reviewed-by: Lukáš Slebodník - -Resolves: -https://pagure.io/SSSD/sssd/issue/3618 -(cherry picked from commit 6b9c38df5712b951e31800efea2df0802e333e08) ---- - src/providers/ipa/selinux_child.c | 4 ++-- - src/tools/sss_useradd.c | 2 +- - src/tools/sss_userdel.c | 2 +- - src/tools/sss_usermod.c | 2 +- - src/util/sss_semanage.c | 12 ++++++------ - src/util/util.h | 6 +++--- - 6 files changed, 14 insertions(+), 14 deletions(-) - -diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c -index bc9460e122ce991087a744fd5335e6c468c6a64b..701be4b35b0f9a9afd9c58eae724d3b8615d0b8c 100644 ---- a/src/providers/ipa/selinux_child.c -+++ b/src/providers/ipa/selinux_child.c -@@ -157,9 +157,9 @@ static int sc_set_seuser(const char *login_name, const char *seuser_name, - * default. We need to remove the SELinux user from the DB - * in that case - */ -- ret = del_seuser(login_name); -+ ret = sss_del_seuser(login_name); - } else { -- ret = set_seuser(login_name, seuser_name, mls); -+ ret = sss_set_seuser(login_name, seuser_name, mls); - } - umask(old_mask); - return ret; -diff --git a/src/tools/sss_useradd.c b/src/tools/sss_useradd.c -index 8521b83011b42c9e2acca4136f154acb3919440c..ca2cbd6c119e5a1735e5b3b524cddeccb68a2578 100644 ---- a/src/tools/sss_useradd.c -+++ b/src/tools/sss_useradd.c -@@ -205,7 +205,7 @@ int main(int argc, const char **argv) - - /* Set SELinux login context - must be done after transaction is done - * b/c libselinux calls getpwnam */ -- ret = set_seuser(tctx->octx->name, pc_selinux_user, NULL); -+ ret = sss_set_seuser(tctx->octx->name, pc_selinux_user, NULL); - if (ret != EOK) { - ERROR("Cannot set SELinux login context\n"); - ret = EXIT_FAILURE; -diff --git a/src/tools/sss_userdel.c b/src/tools/sss_userdel.c -index d085dc3cabd31b2ee82b13c6cbc39c7658b071d1..fb0f2c2ab6163738da2dcf4177c06cd5dc524345 100644 ---- a/src/tools/sss_userdel.c -+++ b/src/tools/sss_userdel.c -@@ -254,7 +254,7 @@ int main(int argc, const char **argv) - - /* Set SELinux login context - must be done after transaction is done - * b/c libselinux calls getpwnam */ -- ret = del_seuser(tctx->octx->name); -+ ret = sss_del_seuser(tctx->octx->name); - if (ret != EOK) { - ERROR("Cannot reset SELinux login context\n"); - ret = EXIT_FAILURE; -diff --git a/src/tools/sss_usermod.c b/src/tools/sss_usermod.c -index 55e94394766f5f46bb3c14c231186f2d79d6b6ab..6a818f13ad2a7e087e23fa2190b83aeb1eabdbac 100644 ---- a/src/tools/sss_usermod.c -+++ b/src/tools/sss_usermod.c -@@ -300,7 +300,7 @@ int main(int argc, const char **argv) - - /* Set SELinux login context - must be done after transaction is done - * b/c libselinux calls getpwnam */ -- ret = set_seuser(tctx->octx->name, pc_selinux_user, NULL); -+ ret = sss_set_seuser(tctx->octx->name, pc_selinux_user, NULL); - if (ret != EOK) { - ERROR("Cannot set SELinux login context\n"); - ret = EXIT_FAILURE; -diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c -index 25b6bcdad2ad7e7ac710497f13d6a6e22360b0dd..1150b6236c2c227fe2fc69f2505b6e254a1e64ec 100644 ---- a/src/util/sss_semanage.c -+++ b/src/util/sss_semanage.c -@@ -272,8 +272,8 @@ int sss_get_seuser(const char *linuxuser, - return getseuserbyname(linuxuser, selinuxuser, level); - } - --int set_seuser(const char *login_name, const char *seuser_name, -- const char *mls) -+int sss_set_seuser(const char *login_name, const char *seuser_name, -+ const char *mls) - { - semanage_handle_t *handle = NULL; - semanage_seuser_key_t *key = NULL; -@@ -346,7 +346,7 @@ done: - return ret; - } - --int del_seuser(const char *login_name) -+int sss_del_seuser(const char *login_name) - { - semanage_handle_t *handle = NULL; - semanage_seuser_key_t *key = NULL; -@@ -426,13 +426,13 @@ done: - return ret; - } - #else /* HAVE_SEMANAGE && HAVE_SELINUX */ --int set_seuser(const char *login_name, const char *seuser_name, -- const char *mls) -+int sss_set_seuser(const char *login_name, const char *seuser_name, -+ const char *mls) - { - return EOK; - } - --int del_seuser(const char *login_name) -+int sss_del_seuser(const char *login_name) - { - return EOK; - } -diff --git a/src/util/util.h b/src/util/util.h -index 74ce2dcecfe17d1cea96cfb5c4b7edb8fd46f09f..e816ba8462afb907e291aaa1692208ccb822205c 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -655,9 +655,9 @@ errno_t restore_creds(struct sss_creds *saved_creds); - * certain permissions. Therefore the caller should make sure the umask is - * not too restricted (especially when called from the daemon code). - */ --int set_seuser(const char *login_name, const char *seuser_name, -- const char *mlsrange); --int del_seuser(const char *login_name); -+int sss_set_seuser(const char *login_name, const char *seuser_name, -+ const char *mlsrange); -+int sss_del_seuser(const char *login_name); - int sss_get_seuser(const char *linuxuser, - char **selinuxuser, - char **level); --- -2.14.3 - diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec index e957397..f4ef270 100644 --- a/SPECS/sssd.spec +++ b/SPECS/sssd.spec @@ -8,7 +8,7 @@ # Determine the location of the LDB modules directory %global ldb_modulesdir %(pkg-config --variable=modulesdir ldb) -%global ldb_version 1.1.17 +%global ldb_version 1.2.2 %if (0%{?fedora} || 0%{?rhel} >= 7) @@ -19,7 +19,7 @@ %global with_krb5_localauth_plugin 1 -%global libwbc_alternatives_version 0.13 +%global libwbc_alternatives_version 0.14 %global libwbc_lib_version %{libwbc_alternatives_version}.0 %global libwbc_alternatives_suffix %nil %if 0%{?__isa_bits} == 64 @@ -39,221 +39,121 @@ %endif Name: sssd -Version: 1.15.2 -Release: 50%{?dist}.11 +Version: 1.16.0 +Release: 19%{?dist} Group: Applications/System Summary: System Security Services Daemon License: GPLv3+ URL: https://pagure.io/SSSD/sssd/ Source0: https://releases.pagure.org/SSSD/sssd/sssd-%{version}.tar.gz +Source1: cert9.db +Source2: key4.db BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) ### Patches ### -Patch0001: 0001-MAN-Mention-sssd-secrets-in-SEE-ALSO-section.patch -Patch0002: 0002-split_on_separator-move-to-a-separate-file.patch -Patch0003: 0003-util-move-string_in_list-to-util_ext.patch -Patch0004: 0004-certmap-add-new-library-libsss_certmap.patch -Patch0005: 0005-certmap-add-placeholder-for-OpenSSL-implementation.patch -Patch0006: 0006-sysdb-add-sysdb_attrs_copy.patch -Patch0007: 0007-sdap_get_users_send-new-argument-mapped_attrs.patch -Patch0008: 0008-LDAP-always-store-the-certificate-from-the-request.patch -Patch0009: 0009-sss_cert_derb64_to_ldap_filter-add-sss_certmap-suppo.patch -Patch0010: 0010-sysdb-add-certmap-related-calls.patch -Patch0011: 0011-IPA-add-certmap-support.patch -Patch0012: 0012-nss-idmap-add-sss_nss_getlistbycert.patch -Patch0013: 0013-nss-allow-larger-buffer-for-certificate-based-reques.patch -Patch0014: 0014-IPA-Add-s2n-request-to-string-function.patch -Patch0015: 0015-IPA-Enhance-debug-logging-for-ipa-s2n-operations.patch -Patch0016: 0016-UTIL-iobuf-Make-input-parameter-for-the-readonly-ope.patch -Patch0017: 0017-UTIL-Fix-a-typo-in-the-tcurl-test-tool.patch -Patch0018: 0018-UTIL-Add-SAFEALIGN_COPY_UINT8_CHECK.patch -Patch0019: 0019-UTIL-Add-utility-macro-cli_creds_get_gid.patch -Patch0020: 0020-UTIL-Add-type-specific-getsetters-to-sss_iobuf.patch -Patch0021: 0021-UTIL-krb5-principal-un-marshalling.patch -Patch0022: 0022-KCM-Initial-responder-build-and-packaging.patch -Patch0023: 0023-KCM-request-parsing-and-sending-a-reply.patch -Patch0024: 0024-KCM-Implement-an-internal-ccache-storage-and-retriev.patch -Patch0025: 0025-KCM-Add-a-in-memory-credential-storage.patch -Patch0026: 0026-KCM-Implement-KCM-server-operations.patch -Patch0027: 0027-MAN-Add-a-manual-page-for-sssd-kcm.patch -Patch0028: 0028-TESTS-Add-integration-tests-for-the-KCM-responder.patch -Patch0029: 0029-SECRETS-Create-DB-path-before-the-operation-itself.patch -Patch0030: 0030-SECRETS-Return-a-nicer-error-message-on-request-with.patch -Patch0031: 0031-SECRETS-Store-ccaches-in-secrets-for-the-KCM-respond.patch -Patch0032: 0032-TCURL-Support-HTTP-POST-for-creating-containers.patch -Patch0033: 0033-KCM-Store-ccaches-in-secrets.patch -Patch0034: 0034-KCM-Make-the-secrets-ccache-back-end-configurable-ma.patch -Patch0035: 0035-KCM-Queue-requests-by-the-same-UID.patch -Patch0036: 0036-KCM-Idle-terminate-the-responder-if-the-secrets-back.patch -Patch0037: 0037-CONFIGURE-Fix-fallback-if-pkg-config-for-uuid-is-mis.patch -Patch0038: 0038-intg-fix-configure-failure-with-strict-cflags.patch -Patch0039: 0039-intg-Remove-bashism-from-intgcheck-prepare.patch -Patch0040: 0040-UTIL-Introduce-subdomain_create_conf_path.patch -Patch0041: 0041-SUBDOMAINS-Allow-use_fully_qualified_names-for-subdo.patch -Patch0042: 0042-CACHE_REQ-Descend-into-subdomains-on-lookups.patch -Patch0043: 0043-NSS-TESTS-Fix-subdomains-attribution.patch -Patch0044: 0044-NSS-TESTS-Improve-setup-teardown-for-subdomains-test.patch -Patch0045: 0045-NSS-TESTS-Include-searches-for-non-fqnames-members-o.patch -Patch0046: 0046-SYSDB-Add-methods-to-deal-with-the-domain-s-resoluti.patch -Patch0047: 0047-SYSDB-TESTS-Add-tests-for-the-domain-s-resolution-or.patch -Patch0048: 0048-IPA-Get-ipaDomainsResolutionOrder-from-ipaConfig.patch -Patch0049: 0049-IPA_SUBDOMAINS-Rename-_refresh_view-to-_refresh_view.patch -Patch0050: 0050-IPA-Get-ipaDomainsResolutionOrder-from-IPA-ID-View.patch -Patch0051: 0051-DLINKLIST-Add-DLIST_FOR_EACH_SAFE-macro.patch -Patch0052: 0052-CACHE_REQ-Make-use-of-domainResolutionOrder.patch -Patch0053: 0053-UTIL-Expose-replace_char-as-sss_replace_char.patch -Patch0054: 0054-Add-domain_resolution_order-config-option.patch -Patch0055: 0055-ssh-handle-binary-keys-correctly.patch -Patch0056: 0056-ssh-add-support-for-certificates-from-non-default-vi.patch -Patch0057: 0057-krb5-return-to-responder-that-pkinit-is-not-availabl.patch -Patch0058: 0058-IPA-add-mapped-attributes-to-user-from-trusted-domai.patch -Patch0059: 0059-IPA-lookup-AD-users-by-certificates-on-IPA-clients.patch -Patch0060: 0060-IPA-enable-AD-user-lookup-by-certificate.patch -Patch0061: 0061-CONFDB-Introduce-SSSD-domain-type-to-distinguish-POS.patch -Patch0062: 0062-CONFDB-Allow-configuring-application-sections-as-non.patch -Patch0063: 0063-CACHE_REQ-Domain-type-selection-in-cache_req.patch -Patch0064: 0064-IFP-Search-both-POSIX-and-non-POSIX-domains.patch -Patch0065: 0065-IFP-ListByName-Don-t-crash-when-no-results-are-found.patch -Patch0066: 0066-PAM-Remove-unneeded-memory-context.patch -Patch0067: 0067-PAM-Add-application-services.patch -Patch0068: 0068-SYSDB-Allow-storing-non-POSIX-users.patch -Patch0069: 0069-SYSDB-Only-generate-new-UID-in-local-domain.patch -Patch0070: 0070-LDAP-save-non-POSIX-users-in-application-domains.patch -Patch0071: 0071-LDAP-Relax-search-filters-in-application-domains.patch -Patch0072: 0072-KRB5-Authenticate-users-in-a-non-POSIX-domain-using-.patch -Patch0073: 0073-KCM-Fix-off-by-one-error-in-secrets-key-parsing.patch -Patch0074: 0074-tcurl-add-support-for-ssl-and-raw-output.patch -Patch0075: 0075-tcurl-test-refactor-so-new-options-can-be-added-more.patch -Patch0076: 0076-tcurl-test-add-support-for-raw-output.patch -Patch0077: 0077-tcurl-test-add-support-for-tls-settings.patch -Patch0078: 0078-tcurl-add-support-for-http-basic-auth.patch -Patch0079: 0079-tcurl-test-allow-to-set-custom-headers.patch -Patch0080: 0080-tcurl-test-add-support-for-client-certificate.patch -Patch0081: 0081-ci-do-not-build-secrets-on-rhel6.patch -Patch0082: 0082-build-make-curl-required-by-secrets.patch -Patch0083: 0083-secrets-use-tcurl-in-proxy-provider.patch -Patch0084: 0084-secrets-remove-http-parser-code-in-proxy-provider.patch -Patch0085: 0085-secrets-allow-to-configure-certificate-check.patch -Patch0086: 0086-secrets-support-HTTP-basic-authentication-with-proxy.patch -Patch0087: 0087-secrets-fix-debug-message.patch -Patch0088: 0088-secrets-always-add-Content-Length-header.patch -Patch0089: 0089-sss_iobuf-fix-read-shadows-a-global-declaration.patch -Patch0090: 0090-configure-fix-typo.patch -Patch0091: 0091-pam_test_client-add-service-and-environment-to-PAM-t.patch -Patch0092: 0092-pam_test_client-add-SSSD-getpwnam-lookup.patch -Patch0093: 0093-sss_sifp-update-method-names.patch -Patch0094: 0094-pam_test_client-add-InfoPipe-user-lookup.patch -Patch0095: 0095-sssctl-integrate-pam_test_client-into-sssctl.patch -Patch0096: 0096-i18n-adding-sssctl-files.patch -Patch0097: 0097-responders-do-not-leak-selinux-context-on-clients-de.patch -Patch0098: 0098-ipa_s2n_get_acct_info_send-provide-correct-req_input.patch -Patch0099: 0099-config-check-Message-when-sssd.conf-is-missing.patch -Patch0100: 0100-sbus-check-connection-for-NULL-before-unregister-it.patch -Patch0101: 0101-selinux-Do-not-fail-if-SELinux-is-not-managed.patch -Patch0102: 0102-UTIL-Use-max-15-characters-for-AD-host-UPN.patch -Patch0103: 0103-Move-sized_output_name-and-sized_domain_name-into-re.patch -Patch0104: 0104-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch -Patch0105: 0105-RESPONDER-Fallback-to-global-domain-resolution-order.patch -Patch0106: 0106-NSS-TESTS-Improve-non-fqnames-tests.patch -Patch0107: 0107-CACHE_REQ-Allow-configurationless-shortname-lookups.patch -Patch0108: 0108-CACHE_REQ_DOMAIN-Add-some-comments-to-cache_req_doma.patch -Patch0109: 0109-RESPONDER_COMMON-Improve-domaiN_resolution_order-deb.patch -Patch0110: 0110-CACHE_REQ_DOMAIN-debug-the-set-domain-resolution-ord.patch -Patch0111: 0111-SECRETS-remove-unused-variable.patch -Patch0112: 0112-IPA-Improve-DEBUG-message-if-a-group-has-no-ipaNTSec.patch -Patch0113: 0113-IPA-Improve-s2n-debug-message-for-missing-ipaNTSecur.patch -Patch0114: 0114-CONFDB-Fix-standalone-application-domains.patch -Patch0115: 0115-utils-add-sss_domain_is_forest_root.patch -Patch0116: 0116-ad-handle-forest-root-not-listed-in-ad_enabled_domai.patch -Patch0117: 0117-SDAP-Fix-handling-of-search-bases.patch -Patch0118: 0118-overrides-add-certificates-to-mapped-attribute.patch -Patch0119: 0119-AD-Make-ad_account_can_shortcut-reusable-by-SSSD-on-.patch -Patch0120: 0120-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch -Patch0121: 0121-PAM-check-matching-certificates-from-all-domains.patch -Patch0122: 0122-DP-Reduce-Data-Provider-log-level-noise.patch -Patch0123: 0123-NSS-Move-output-name-formatting-to-utils.patch -Patch0124: 0124-CACHE_REQ-Add-a-new-cache_req_ncache_filter_fn-plugi.patch -Patch0125: 0125-CACHE_REQ_RESULT-Introduce-cache_req_create_ldb_resu.patch -Patch0126: 0126-CACHE_REQ-Make-use-of-cache_req_ncache_filter_fn.patch -Patch0127: 0127-SERVER_MODE-Update-sdap-lists-for-each-ad_ctx.patch -Patch0128: 0128-sss_nss_getlistbycert-return-results-from-multiple-d.patch -Patch0129: 0129-CACHE_REQ-Avoid-using-of-uninitialized-value.patch -Patch0130: 0130-CACHE_REQ-Ensure-the-domains-are-updated-for-filter-.patch -Patch0131: 0131-AD-SUBDOMAINS-Fix-search-bases-for-child-domains.patch -Patch0132: 0132-KRB5-Advise-the-user-to-inspect-the-krb5_child.log-i.patch -Patch0133: 0133-cache_req-use-the-right-negative-cache-for-initgroup.patch -Patch0134: 0134-test-make-sure-p11_child-is-build-for-pam-srv-tests.patch -Patch0135: 0135-pam-properly-support-UPN-logon-names.patch -Patch0136: 0136-KCM-Fix-the-per-client-serialization-queue.patch -Patch0137: 0137-TESTS-Add-a-test-for-parallel-execution-of-klist.patch -Patch0138: 0138-ipa-filter-IPA-users-from-extdom-lookups-by-certific.patch -Patch0139: 0139-krb5-accept-changed-principal-if-krb5_canonicalize-T.patch -Patch0140: 0140-IPA-Avoid-using-uninitialized-ret-value-when-skippin.patch -Patch0141: 0141-IPA-Return-from-function-after-marking-a-request-as-.patch -Patch0142: 0142-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch -Patch0143: 0143-VALIDATORS-Add-subdomain-section.patch -Patch0144: 0144-VALIDATORS-Remove-application-section-domain.patch -Patch0145: 0145-VALIDATORS-Escape-special-regex-chars.patch -Patch0146: 0146-TESTS-Add-unit-tests-for-cfg-validation.patch -Patch0147: 0147-MAN-Fix-typo-in-trusted-domain-section.patch -Patch0148: 0148-VALIDATORS-Change-regex-for-app-domains.patch -Patch0149: 0149-VALIDATORS-Detect-inherit_from-in-normal-domain.patch -Patch0150: 0150-VALIDATOR-prevent-duplicite-report-from-subdomain-se.patch -Patch0151: 0151-test_config_check-Fix-few-issues.patch -Patch0152: 0152-KRB5-Fix-access_provider-krb5.patch -Patch0153: 0153-BUILD-Improve-error-messages-for-optional-dependenci.patch -Patch0154: 0154-RESPONDER_COMMON-update-certmaps-in-responders.patch -Patch0155: 0155-tests-fix-test_pam_preauth_cert_no_logon_name.patch -Patch0156: 0156-pam_sss-add-support-for-SSS_PAM_CERT_INFO_WITH_HINT.patch -Patch0157: 0157-add_pam_cert_response-add-support-for-SSS_PAM_CERT_I.patch -Patch0158: 0158-PAM-send-user-name-hint-response-when-needed.patch -Patch0159: 0159-sysdb-sysdb_get_certmap-allow-empty-certmap.patch -Patch0160: 0160-sssctl-show-user-name-used-for-authentication-in-use.patch -Patch0161: 0161-RESP-Provide-a-reusable-request-to-fully-resolve-inc.patch -Patch0162: 0162-IFP-Only-format-the-output-name-to-the-short-version.patch -Patch0163: 0163-IFP-Resolve-group-names-from-GIDs-if-required.patch -Patch0164: 0164-ldap-handle-certmap-errors-gracefully.patch -Patch0165: 0165-SECRETS-Fix-warning-Wpointer-bool-conversion.patch -Patch0166: 0166-IPA-Fix-the-PAM-error-code-that-auth-code-expects-to.patch -Patch0167: 0167-pam_sss-Fix-checking-of-empty-string-cert_user.patch -Patch0168: 0168-CACHE_REQ-Simplify-_search_ncache_filter.patch -Patch0169: 0169-CACHE_REQ_SEARCH-Check-for-filtered-users-groups-als.patch -Patch0170: 0170-cache_req-Do-not-use-default_domain_suffix-with-netg.patch -Patch0171: 0171-krb5-disable-enterprise-principals-during-password-c.patch -Patch0172: 0172-pam_sss-Fix-leaking-of-memory-in-case-of-failures.patch -Patch0173: 0173-IFP-Add-domain-and-domainname-attributes-to-the-user.patch -Patch0174: 0174-IFP-Fix-error-handling-in-ifp_user_get_attr_handle_r.patch -Patch0175: 0175-SYSDB-Return-ERR_NO_TS-when-there-s-no-timestamp-cac.patch -Patch0176: 0176-SYSDB-Internally-expose-sysdb_search_ts_matches.patch -Patch0177: 0177-SYSDB-Make-the-usage-of-the-filter-more-generic-for-.patch -Patch0178: 0178-SYSDB_OPS-Mark-an-entry-as-expired-also-in-the-times.patch -Patch0179: 0179-SYSDB_OPS-Invalidate-a-cache-entry-also-in-the-ts_ca.patch -Patch0180: 0180-SYSDB-Introduce-_search_-users-groups-_by_timestamp.patch -Patch0181: 0181-LDAP_ID_CLEANUP-Use-sysdb_search_-_by_timestamp.patch -Patch0182: 0182-krb5-use-plain-principal-if-password-is-expired.patch -Patch0183: 0183-RESPONDER-Use-fqnames-as-output-when-needed.patch -Patch0184: 0184-DOMAIN-Add-sss_domain_info_-get-set-_output_fqnames.patch -Patch0185: 0185-GPO-Fix-typo-in-DEBUG-message.patch -Patch0186: 0186-SDAP-Update-parent-sdap_list.patch -Patch0187: 0187-RESPONDERS-Fix-terminating-idle-connections.patch -Patch0188: 0188-TESTS-Integration-test-for-idle-timeout.patch -Patch0189: 0189-MAN-Document-that-client_idle_timeout-can-t-be-short.patch -Patch0190: 0190-ad_account_can_shortcut-shortcut-if-ID-is-unknown.patch -Patch0191: 0191-sudo-add-a-threshold-option-to-reduce-size-of-rules-.patch -Patch0192: 0192-libwbclient-Change-return-code-for-wbcAuthenticateUs.patch -Patch0193: 0193-IPA-fix-handling-of-certmap_ctx.patch -Patch0194: 0194-certmap-make-sure-eku_oid_list-is-always-allocated.patch -Patch0195: 0195-cache_req-Look-for-name-attribute-also-in-nss_cmd_ge.patch -Patch0196: 0196-sssd_client-add-mutex-protected-call-to-the-PAC-resp.patch -Patch0197: 0197-sysdb-sanitize-search-filter-input.patch -Patch0198: 0198-ipa-make-sure-view-name-is-initialized-at-startup.patch -Patch0199: 0199-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch -Patch0200: 0200-cache_req-Correction-of-cache_req-debug-string-ID-fo.patch -Patch0201: 0201-cache-Check-for-max_id-min_id-in-cache_req.patch -Patch0202: 0202-sudo-always-use-srv_opts-from-id-context.patch -Patch0203: 0203-SELINUX-Use-getseuserbyname-to-get-IPA-seuser.patch -Patch0204: 0204-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch -Patch0205: 0205-util-Add-sss_-prefix-to-some-functions.patch +Patch0001: 0001-NSS-Move-memcache-setup-to-separate-function.patch +Patch0002: 0002-NSS-Specify-memcache_timeout-0-semantics.patch +Patch0003: 0003-MAN-Document-memcache_timeout-0-meaning.patch +Patch0004: 0004-CONFIG-Add-a-new-option-auto_private_groups.patch +Patch0005: 0005-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch +Patch0006: 0006-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch +Patch0007: 0007-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch +Patch0008: 0008-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch +Patch0009: 0009-TESTS-Add-integration-tests-for-the-auto_private_gro.patch +Patch0010: 0010-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch +Patch0011: 0011-MAN-GPO-Security-Filtering-limitation.patch +Patch0012: 0012-sudo-always-use-srv_opts-from-id-context.patch +Patch0013: 0013-AD-Remember-last-site-discovered.patch +Patch0014: 0014-sysdb-add-functions-to-get-set-client-site.patch +Patch0015: 0015-AD-Remember-last-site-discovered-in-sysdb.patch +Patch0016: 0016-UTIL-Add-wrapper-function-to-configure-logger.patch +Patch0017: 0017-Add-parameter-logger-to-daemons.patch +Patch0018: 0018-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch +Patch0019: 0019-SYSTEMD-Add-environment-file-to-responder-service-fi.patch +Patch0020: 0020-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch +Patch0021: 0021-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch +Patch0022: 0022-sss_client-create-nss_common.h.patch +Patch0023: 0023-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch +Patch0024: 0024-NSS-add-_EX-version-of-some-requests.patch +Patch0025: 0025-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch +Patch0026: 0026-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch +Patch0027: 0027-nss-make-memcache_delete_entry-public.patch +Patch0028: 0028-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch +Patch0029: 0029-NSS-TESTS-add-unit-tests-for-_EX-requests.patch +Patch0030: 0030-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch +Patch0031: 0031-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch +Patch0032: 0032-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch +Patch0033: 0033-SYSTEMD-Clean-pid-file-in-corner-cases.patch +Patch0034: 0034-CHILD-Pass-information-about-logger-to-children.patch +Patch0035: 0035-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch +Patch0036: 0036-p11_child-return-multiple-certs.patch +Patch0037: 0037-PAM-handled-multiple-certs-in-the-responder.patch +Patch0038: 0038-pam_sss-refactoring-use-struct-cert_auth_info.patch +Patch0039: 0039-p11_child-use-options-to-select-certificate-for-auth.patch +Patch0040: 0040-pam-add-prompt-string-for-certificate-authentication.patch +Patch0041: 0041-PAM-allow-missing-logon_name-during-certificate-auth.patch +Patch0042: 0042-p11_child-add-descriptions-for-error-codes-to-debug-.patch +Patch0043: 0043-pam-filter-certificates-in-the-responder-not-in-the-.patch +Patch0044: 0044-PAM-add-certificate-s-label-to-the-selection-prompt.patch +Patch0045: 0045-SYSDB-Remove-code-causing-a-covscan-warning.patch +Patch0046: 0046-SYSDB-Better-debugging-for-email-conflicts.patch +Patch0047: 0047-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch +Patch0048: 0048-TOOLS-Add-a-new-sssctl-command-access-report.patch +Patch0049: 0049-dp-use-void-to-express-empty-output-argument-list.patch +Patch0050: 0050-dp-add-method-to-refresh-access-control-rules.patch +Patch0051: 0051-ipa-implement-method-to-refresh-HBAC-rules.patch +Patch0052: 0052-ifp-add-method-to-refresh-access-control-rules-in-do.patch +Patch0053: 0053-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch +Patch0054: 0054-sysdb-be_refresh_get_values_ex-remove-unused-option.patch +Patch0055: 0055-sysdb-do-not-use-objectClass-for-users-and-groups.patch +Patch0056: 0056-sysdb-do-not-use-LDB_SCOPE_ONELEVEL.patch +Patch0057: 0057-sysdb-remove-IDXONE-and-objectClass-from-users-and-g.patch +Patch0058: 0058-mmap_cache-make-checks-independent-of-input-size.patch +Patch0059: 0059-NSS-Fix-covscan-warning.patch +Patch0060: 0060-responder-Fix-talloc-hierarchy-in-sized_output_name.patch +Patch0061: 0061-test_responder-Check-memory-leak-in-sized_output_nam.patch +Patch0062: 0062-UTIL-add-find_domain_by_object_name_ex.patch +Patch0063: 0063-ipa-handle-users-from-different-domains-in-ipa_resol.patch +Patch0064: 0064-overrides-fixes-for-sysdb_invalidate_overrides.patch +Patch0065: 0065-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch +Patch0066: 0066-IPA-use-cache-searches-in-get_groups_dns.patch +Patch0067: 0067-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch +Patch0068: 0068-SDAP-Split-out-utility-function-sdap_get_object_doma.patch +Patch0069: 0069-LDAP-Extract-the-check-whether-to-run-a-POSIX-check-.patch +Patch0070: 0070-LDAP-Only-run-the-POSIX-check-with-a-GC-connection.patch +Patch0071: 0071-SDAP-Search-with-a-NULL-search-base-when-looking-up-.patch +Patch0072: 0072-SDAP-Rename-sdap_posix_check-to-sdap_gc_posix_check.patch +Patch0073: 0073-DP-Create-a-new-handler-function-getAccountDomain.patch +Patch0074: 0074-AD-Implement-a-real-getAccountDomain-handler-for-the.patch +Patch0075: 0075-RESP-Expose-DP-method-getAccountDomain-to-responders.patch +Patch0076: 0076-NEGCACHE-Add-API-for-setting-and-checking-locate-acc.patch +Patch0077: 0077-TESTS-Add-tests-for-the-object-by-id-cache_req-inter.patch +Patch0078: 0078-CACHE_REQ-Export-cache_req_search_ncache_add-as-cach.patch +Patch0079: 0079-CACHE_REQ-Add-plugin-methods-required-for-the-domain.patch +Patch0080: 0080-CACHE_REQ-Add-a-private-request-cache_req_locate_dom.patch +Patch0081: 0081-CACHE_REQ-Implement-the-plugin-methods-that-utilize-.patch +Patch0082: 0082-CACHE_REQ-Use-the-domain-locator-request-to-only-sea.patch +Patch0083: 0083-MAN-Document-how-the-Global-Catalog-is-used-currentl.patch +Patch0084: 0084-p11_child-make-sure-OCSP-checks-are-done.patch +Patch0085: 0085-IPA-Include-SYSDB_OBJECTCATEGORY-not-OBJECTCLASS-in-.patch +Patch0086: 0086-nss-idmap-allow-NULL-result-in-_timeout-calls.patch +Patch0087: 0087-cache-Check-for-max_id-min_id-in-cache_req.patch +Patch0088: 0088-Revert-p11_child-make-sure-OCSP-checks-are-done.patch +Patch0089: 0089-p11_child-properly-check-results-of-CERT_VerifyCerti.patch +Patch0090: 0090-ifp-use-realloc-in-ifp_list_ctx_remaining_capacity.patch +Patch0091: 0091-IPA-Delay-the-first-periodic-refresh-of-trusted-doma.patch +Patch0092: 0092-sysdb-add-userMappedCertificate-to-the-index.patch +Patch0093: 0093-AD-Inherit-the-MPG-setting-from-the-main-domain.patch +Patch0094: 0094-SDAP-skip-builtin-AD-groups-in-sdap_save_grpmem.patch +Patch0095: 0095-SYSDB-Read-the-ldb_message-from-loop-s-index-counter.patch +Patch0096: 0096-nss-idmap-check-timed-muted-return-code.patch +Patch0097: 0097-DESKPROFILE-Add-checks-for-user-and-host-category.patch +Patch0098: 0098-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch +Patch0099: 0099-util-Add-sss_-prefix-to-some-functions.patch +Patch0100: 0100-MAN-Explain-how-does-auto_private_groups-affect-subd.patch +Patch0101: 0101-AD-Use-the-right-sdap_domain-for-the-forest-root.patch +Patch0102: 0102-AD-sdap_get_ad_tokengroups_done-allocate-temporary-d.patch +Patch0103: 0103-AD-do-not-allocate-temporary-data-on-long-living-con.patch #This patch should not be removed in RHEL-7 Patch999: 0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec @@ -277,6 +177,7 @@ Requires: python-sssdconfig = %{version}-%{release} %global pubconfpath %{sssdstatedir}/pubconf %global gpocachepath %{sssdstatedir}/gpo_cache %global secdbpath %{sssdstatedir}/secrets +%global deskprofilepath %{sssdstatedir}/deskprofile ### Build Dependencies ### @@ -332,6 +233,7 @@ BuildRequires: jansson-devel BuildRequires: http-parser-devel BuildRequires: curl-devel BuildRequires: libuuid-devel +BuildRequires: pkgconfig(gdm-pam-extensions) %description Provides a set of daemons to manage access to remote directories and @@ -350,9 +252,6 @@ License: GPLv3+ # Conflicts Conflicts: selinux-policy < 3.10.0-46 Conflicts: sssd < 1.10.0-8%{?dist}.beta2 -# Due to ABI changes in rhel-7,5 (1.1.30/1.2.0) -# rhel-7.4 <= will never have libldb 1.2.0 due to samba-4.6.x -Conflicts: libldb >= 1.1.30 # Requires Requires: sssd-client%{?_isa} = %{version}-%{release} Requires: libsss_idmap%{?_isa} = %{version}-%{release} @@ -749,6 +648,9 @@ for p in %patches ; do UpdateTimestamps -p1 $p done +cp %{SOURCE1} src/tests/cmocka/p11_nssdb_2certs/ +cp %{SOURCE2} src/tests/cmocka/p11_nssdb_2certs/ + %build autoreconf -ivf @@ -968,6 +870,7 @@ done %attr(700,sssd,sssd) %dir %{dbpath} %attr(755,sssd,sssd) %dir %{mcpath} %attr(700,root,root) %dir %{secdbpath} +%attr(755,root,root) %dir %{deskprofilepath} %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/passwd %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/initgroups @@ -979,8 +882,6 @@ done %attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd %attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd/conf.d %ghost %attr(0600,sssd,sssd) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf -%attr(755,root,root) %dir %{_sysconfdir}/systemd/system/sssd.service.d -%config(noreplace) %{_sysconfdir}/systemd/system/sssd.service.d/journal.conf %dir %{_sysconfdir}/logrotate.d %config(noreplace) %{_sysconfdir}/logrotate.d/sssd %dir %{_sysconfdir}/rwtab.d @@ -998,6 +899,7 @@ done %{_mandir}/man5/sssd-files.5* %{_mandir}/man5/sssd-simple.5* %{_mandir}/man5/sssd-sudo.5* +%{_mandir}/man5/sssd-session-recording.5* %{_mandir}/man5/sssd-secrets.5* %{_mandir}/man5/sss_rpcidmapd.5* %{_mandir}/man8/sssd.8* @@ -1006,10 +908,12 @@ done %dir %{_datadir}/sssd/systemtap %{_datadir}/sssd/systemtap/id_perf.stp %{_datadir}/sssd/systemtap/nested_group_perf.stp +%{_datadir}/sssd/systemtap/dp_request.stp %dir %{_datadir}/systemtap %dir %{_datadir}/systemtap/tapset %{_datadir}/systemtap/tapset/sssd.stp %{_datadir}/systemtap/tapset/sssd_functions.stp +%{_mandir}/man5/sssd-systemtap.5* %endif %if (0%{?install_pcscd_polkit_rule} == 1) @@ -1242,8 +1146,8 @@ getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "Us %if (0%{?with_kcm} == 1) %files kcm -f sssd_kcm.lang %{_libexecdir}/%{servicename}/sssd_kcm -%dir %{_sysconfdir}/krb5.conf.d -%config(noreplace) %{_sysconfdir}/krb5.conf.d/kcm_default_ccache +%dir %{_datadir}/sssd-kcm +%{_datadir}/sssd-kcm/kcm_default_ccache %{_unitdir}/sssd-kcm.socket %{_unitdir}/sssd-kcm.service %{_mandir}/man8/sssd-kcm.8* @@ -1393,58 +1297,194 @@ fi } %changelog -* Tue Feb 13 2018 Fabiano Fidêncio - 1.15.2-50-11 -- Resolves: rhbz#1516700 - SELINUX: Use getseuserbyname to get IPA - seuser [rhel-7.4.z] - -* Sun Jan 07 2018 Fabiano Fidêncio - 1.15.2-50-10 -- Resolves: rhbz#1530975 - sssd_be stuck in an infinite loop after - completing full refresh of sudo rules - [rhel-7.4.z] - -* Fri Jan 05 2018 Fabiano Fidêncio - 1.15.2-50.9 -- Resolves: rhbz#1525110 - NSS by-id requests are not checked against +* Wed Feb 21 2018 Fabiano Fidêncio - 1.16.0-19 +- Related: rhbzrhbz#1544943 - sssd goes offline when renewing expired ticket + +* Wed Feb 21 2018 Fabiano Fidêncio - 1.16.0-18 +- Resolves: rhbz#1543348 - sssd_be consumes more memory on RHEL 7.4 systems. +- Resolves: rhbz#1544943 - sssd goes offline when renewing expired ticket + +* Mon Feb 19 2018 Fabiano Fidêncio - 1.16.0-17 +- Resolves: rhbz#1523282 - sssd used wrong search base with wrong AD + server + +* Tue Feb 6 2018 Fabiano Fidêncio - 1.16.0-16 +- Resolves: rhbz#1538643 - SSSD crashes when retrieving a Desktop Profile + with no specific host/hostgroup set +- Related: rhbz#1441908 - SELINUX: Use getseuserbyname to get IPA seuser +- Related: rhbz#1327705 - [RFE] Automatic creation of user private groups + on RHEL clients joined to AD via sssd [RHEL 7] + +* Wed Jan 24 2018 Fabiano Fidêncio - 1.16.0-15 +- Resolves: rhbz#1517971 - AD Domain goes offline immediately during + subdomain initialization - IPA AD Trust +- Related: rhbz#1482555 - sysdb index improvements - missing ghost + attribute indexing, unneeded objectclass index + etc.. +- Related: rhbz#1327705 - [RFE] Automatic creation of user private groups + on RHEL clients joined to AD via sssd [RHEL 7] +- Resolves: rhbz#1527149 - AD provider - AD BUILTIN groups are cached with + gidNumber = 0 +- Related: rhbz#1461899 - Loading enterprise principals doesn't work with + a primed cache +- Related: rhbz#1473571 - ipa-extdom-extop plugin can exhaust DS worker + threads + +* Fri Dec 15 2017 Fabiano Fidêncio - 1.16.0-14 +- Resolves: rhbz#1525644 - dbus-send unable to find user by CAC cert + +* Thu Dec 14 2017 Fabiano Fidêncio - 1.16.0-13 +- Resolves: rhbz#1523010 - IPA user able to authenticate with revoked cert + on smart card + +* Mon Dec 11 2017 Fabiano Fidêncio - 1.16.0-12 +- Resolves: rhbz#1512027 - NSS by-id requests are not checked against max_id/min_id ranges before triggering the - backend [rhel-7.4.z] - -* Fri Nov 03 2017 Fabiano Fidêncio - 1.15.2-50.8 -- Resolves: rhbz#1508972 - Accessing IdM kerberos ticket fails while id - mapping is applied [rhel-7.4.z] -- Resolves: rhbz#1509177 - Race condition between refreshing the cr_domain + backend + +* Fri Dec 08 2017 Fabiano Fidêncio - 1.16.0-11 +- Related: rhbz#1507614 - Improve Smartcard integration if multiple + certificates or multiple mapped identities are + available +- Resolves: rhbz#1523010 - IPA user able to authenticate with revoked + cert on smart card +- Resolves: rhbz#1520984 - getent output is not showing home directory + for IPA AD trusted user +- Related: rhbz#1473571 - ipa-extdom-extop plugin can exhaust DS worker + threads + +* Wed Dec 06 2017 Fabiano Fidêncio - 1.16.0-10 +- Resolves: rhbz#1421194 - SSSD doesn't use AD global catalog for + gidnumber lookup, resulting in unacceptable + delay for large forests + +* Fri Dec 01 2017 Fabiano Fidêncio - 1.16.0-9 +- Resolves: rhbz#1482231 - sssd_nss consumes more memory until + restarted or machine swaps +- Resolves: rhbz#1512508 - SSSD fails to fetch group information after + switching IPA client to a non-default view + +* Thu Nov 30 2017 Fabiano Fidêncio - 1.16.0-8 +- Resolves: rhbz#1490120 - SSSD complaining about corrupted mmap cache + and logging error in /var/log/messages and + /var/log/sssd/sssd_nss.log + +* Mon Nov 27 2017 Fabiano Fidêncio - 1.16.0-7 +- Resolves: rhbz#1272214 - [RFE] Create a local per system report about + who can access that IDM client (attestation) +- Resolves: rhbz#1482555 - sysdb index improvements - missing ghost + attribute indexing, unneeded objectclass index + etc.. +- Resolves: rhbz#888739 - Enumerating large number of users makes sssd_be + hog the cpu for a long time. +- Resolves: rhbz#1373547 - SSSD performance issue with malloc and brk + calls +- Resolves: rhbz#1472255 - Improve SSSD performance in the 7.5 release + +* Tue Nov 14 2017 Fabiano Fidêncio - 1.16.0-6 +- Related: rhbz#1460724 - SYSLOG_IDENTIFIER is different +- Related: rhbz#1432010 - SSSD ships a drop-in configuration snippet in + /etc/systemd/system +- Related: rhbz#1507614 - Improve Smartcard integration if multiple + certificates or multiple mapped identities are + available + +* Mon Nov 13 2017 Fabiano Fidêncio - 1.16.0-5 +- Resolves: rhbz#1507614 - Improve Smartcard integration if multiple + certificates or multiple mapped identities are + available +- Related: rhbz#1499659 - CVE-2017-12173 sssd: unsanitized input when + searching in local cache database [rhel-7.5] +- Resolves: rhbz#1408294 - SSSD authentication fails when two IPA + accounts share an email address without a + clear way to debug the problem +- Resolves: rhbz#1502686 - crash - /usr/libexec/sssd/sssd_nss in + nss_setnetgrent_timeout + +* Sun Nov 12 2017 Fabiano Fidêncio - 1.16.0-4 +- Related: rhbz#1460724 - SYSLOG_IDENTIFIER is different +- Related: rhbz#1459609 - When sssd is configured with id_provider proxy + and auth_provider ldap, login fails if the LDAP + server is not allowing anonymous binds. + +* Mon Nov 06 2017 Fabiano Fidêncio - 1.16.0-3 +- Resolves: rhbz#1473571 - ipa-extdom-extop plugin can exhaust DS worker + threads + +* Fri Nov 03 2017 Fabiano Fidêncio - 1.16.0-2 +- Resolves: rhbz#1484376 - [RFE] Add a configuration option to SSSD to + disable the memory cache +- Resolves: rhbz#1327705 - Automatic creation of user private groups on + RHEL clients joined to AD via sssd [RHEL 7] +- Resolves: rhbz#1505277 - Race condition between refreshing the cr_domain list and a request that is using the list can - cause a segfault is sssd_nss [rhel-7.4.z] - -* Fri Oct 27 2017 Fabiano Fidêncio - 1.15.2-50.7 -- Resolves: rhbz#1506142 - SSSD can crash due to ABI changes in - libldb >= 1.2.0 (1.1.30) [rhel-7.4.z] -- Resolves: rhbz#1506682 - sssd_client: add mutex protected call to the - PAC responder [rhel-7.4.z] -- Resolves: rhbz#1499658 - CVE-2017-12173 sssd: unsanitized input when - searching in local cache database [rhel-7.4.z] - -* Wed Sep 27 2017 Fabiano Fidêncio - 1.15.2-50.6 -- Add a patch that was missed in 1.15.2-50.4 -- Related: rhbz#1489290 - samba shares with sssd authentication broken - on 7.4 [rhel-7.4.z] - -* Thu Sep 21 2017 Fabiano Fidêncio - 1.15.2-50.5 -- Resolves: rhbz#1493916 - Issues with certificate mapping rules [rhel-7.4.z] - -* Mon Sep 11 2017 Jakub Hrozek - 1.15.2-50.4 -- Resolves: rhbz#1489290 - samba shares with sssd authentication broken - on 7.4 [rhel-7.4.z] - -* Fri Aug 18 2017 Fabiano Fidêncio - 1.15.2-50.3 -- Resolves: rhbz#1482927 - sssd_be is utilizing more CPU during sudoi - rules refresh [rhel-7.4.z] - -* Sun Aug 6 2017 Jakub Hrozek - 1.15.2-50.2 -- Resolves: rhbz#1478252 - Querying the AD domain for external domain's - ID can mark the AD domain offline [rhel-7.4.z] - -* Sun Aug 6 2017 Jakub Hrozek - 1.15.2-50.1 -- Resolves: rhbz#1478250 - Idle nss file descriptors should be closed - [rhel-7.4.z] + cause a segfault is sssd_nss +- Resolves: rhbz#1462343 - document information on why SSSD does not use + host-based security filtering when processing + AD GPOs +- Resolves: rhbz#1498734 - sssd_be stuck in an infinite loop after + completing full refresh of sudo rules +- Resolves: rhbz#1400614 - [RFE] sssd should remember DNS sites from + first search +- Resolves: rhbz#1460724 - SYSLOG_IDENTIFIER is different +- Resolves: rhbz#1459609 - When sssd is configured with id_provider proxy + and auth_provider ldap, login fails if the LDAP + server is not allowing anonymous binds. + +* Fri Oct 20 2017 Fabiano Fidêncio - 1.16.0-1 +- Resolves: rhbz#1469791 - Rebase SSSD to version 1.16+ +- Resolves: rhbz#1132264 - Allow sssd to retrieve sudo rules of local + users whose sudo rules stored in ldap server +- Resolves: rhbz#1301740 - sssd can be marked offline if a trusted domain + is not reachable +- Resolves: rhbz#1399262 - Use TCP for kerberos with AD by default +- Resolves: rhbz#1416150 - RFE: Log to syslog when sssd cannot contact + servers, goes offline +- Resolves: rhbz#1441908 - SELINUX: Use getseuserbyname to get IPA seuser +- Resolves: rhbz#1454559 - python-sssdconfig doesn't parse hexadecimal debug + _level, resulting in set_option(): + /usr/lib/python2.7/site-packages/SSSDConfig/__init__.py + killed by TypeError +- Resolves: rhbz#1456968 - MAN: document that attribute 'provider' is not + allowed in section 'secrets' +- Resolves: rhbz#1460689 - KCM/secrets: Storing many secrets in a rapid + succession segfaults the secrets responder +- Resolves: rhbz#1464049 - Idle nss file descriptors should be closed +- Resolves: rhbz#1468610 - sssd_be is utilizing more CPU during sudo rules + refresh +- Resolves: rhbz#1474711 - Querying the AD domain for external domain's ID can + mark the AD domain offline +- Resolves: rhbz#1479398 - samba shares with sssd authentication broken on 7.4 +- Resolves: rhbz#1479983 - id root triggers an LDAP lookup +- Resolves: rhbz#1489895 - Issues with certificate mapping rules +- Resolves: rhbz#1490501 - sssd incorrectly checks 'try_inotify' thinking it is + the wrong section +- Resolves: rhbz#1490913 - MAN: Document that full_name_format must be set if + the output of trusted domains user resolution should + be shortnames only +- Resolves: rhbz#1499659 - CVE-2017-12173 sssd: unsanitized input when + searching in local cache database [rhel-7.5] +- Resolves: rhbz#1461899 - Loading enterprise principals doesn't work with a + primed cache +- Resolves: rhbz#1482674 - SUDO doesn't work for IPA users on IPA clients after + applying ID Views for them in IPA server +- Resolves: rhbz#1486053 - Accessing IdM kerberos ticket fails while id mapping + is applied +- Resolves: rhbz#1486786 - sssd going in offline mode due to sudo search filter. +- Resolves: rhbz#1500087 - SSSD creates bad override search filter due to AD + Trust object with parenthesis +- Resolves: rhbz#1502713 - SSSD can crash due to ABI changes in libldb >= 1.2.0 + (1.1.30) +- Resolves: rhbz#1461462 - sssd_client: add mutex protected call to the PAC + responder +- Resolves: rhbz#1489666 - Combination sssd-ad and postfix recieve incorrect + mail with asterisks or spaces +- Resolves: rhbz#1525052 - sssd_krb5_localauth_plugin fails to fallback to otheri + localname rules + +* Tue Oct 17 2017 Jakub Hrozek - 1.15.2-51 +- Require the 7.5 libldb version which broke ABI +- Related: rhbz#1469791 - Rebase SSSD to version 1.16+ * Wed Jun 21 2017 Jakub Hrozek - 1.15.2-50 - Resolves: rhbz#1457926 - Wrong search base used when SSSD is directly